Fixed line endings and SVN props with fixup.sh script

This commit is contained in:
skarg
2016-09-08 15:56:11 +00:00
parent 27a3c1ff0f
commit 10aa414351
258 changed files with 93175 additions and 93175 deletions
+480 -480
View File
@@ -1,480 +1,480 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 credential 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.
*
*********************************************************************/
/* Access Credential Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_credential.h"
#include "handlers.h"
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_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Credential_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_Credential_Init(
void)
{
unsigned i;
if (!Access_Credential_Initialized) {
Access_Credential_Initialized = true;
for (i = 0; i < MAX_ACCESS_CREDENTIALS; i++) {
ac_descr[i].global_identifier = 0; /* set to some meaningful value */
ac_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
ac_descr[i].credential_status = false;
ac_descr[i].reasons_count = 0;
ac_descr[i].auth_factors_count = 0;
memset(&ac_descr[i].activation_time, 0, sizeof(BACNET_DATE_TIME));
memset(&ac_descr[i].expiration_time, 0, sizeof(BACNET_DATE_TIME));
ac_descr[i].credential_disable = ACCESS_CREDENTIAL_DISABLE_NONE;
ac_descr[i].assigned_access_rights_count = 0;
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_Credential_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_CREDENTIALS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_Credential_Count(
void)
{
return MAX_ACCESS_CREDENTIALS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_Credential_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_Credential_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_CREDENTIALS;
if (object_instance < MAX_ACCESS_CREDENTIALS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_Credential_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_CREDENTIALS) {
sprintf(text_string, "ACCESS CREDENTIAL %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Credential_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index =
Access_Credential_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_ACCESS_CREDENTIAL, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Credential_Object_Name(rpdata->object_instance,
&char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
OBJECT_ACCESS_CREDENTIAL);
break;
case PROP_GLOBAL_IDENTIFIER:
apdu_len =
encode_application_unsigned(&apdu[0],
ac_descr[object_index].global_identifier);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
ac_descr[object_index].reliability);
break;
case PROP_CREDENTIAL_STATUS:
apdu_len =
encode_application_enumerated(&apdu[0],
ac_descr[object_index].credential_status);
break;
case PROP_REASON_FOR_DISABLE:
for (i = 0; i < ac_descr[object_index].reasons_count; i++) {
len =
encode_application_enumerated(&apdu[0],
ac_descr[object_index].reason_for_disable[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
break;
case PROP_AUTHENTICATION_FACTORS:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ac_descr[object_index].auth_factors_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < ac_descr[object_index].auth_factors_count; i++) {
len =
bacapp_encode_credential_authentication_factor(&apdu
[0], &ac_descr[object_index].auth_factors[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
ac_descr[object_index].auth_factors_count) {
apdu_len =
bacapp_encode_credential_authentication_factor(&apdu
[0],
&ac_descr[object_index].
auth_factors[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_ACTIVATION_TIME:
apdu_len =
bacapp_encode_datetime(&apdu[0],
&ac_descr[object_index].activation_time);
break;
case PROP_EXPIRATION_TIME:
apdu_len =
bacapp_encode_datetime(&apdu[0],
&ac_descr[object_index].expiration_time);
break;
case PROP_CREDENTIAL_DISABLE:
apdu_len =
encode_application_enumerated(&apdu[0],
ac_descr[object_index].credential_disable);
break;
case PROP_ASSIGNED_ACCESS_RIGHTS:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ac_descr[object_index].assigned_access_rights_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0;
i < ac_descr[object_index].assigned_access_rights_count;
i++) {
len =
bacapp_encode_assigned_access_rights(&apdu[0],
&ac_descr[object_index].assigned_access_rights[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
ac_descr[object_index].assigned_access_rights_count) {
apdu_len =
bacapp_encode_assigned_access_rights(&apdu[0],
&ac_descr[object_index].
assigned_access_rights[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(rpdata->object_property != PROP_AUTHENTICATION_FACTORS)
&& (rpdata->object_property != PROP_ASSIGNED_ACCESS_RIGHTS)
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_Credential_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->object_property != PROP_AUTHENTICATION_FACTORS)
&& (wp_data->object_property != PROP_ASSIGNED_ACCESS_RIGHTS)
&& (wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index =
Access_Credential_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_GLOBAL_IDENTIFIER:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
ac_descr[object_index].global_identifier =
value.type.Unsigned_Int;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
case PROP_CREDENTIAL_STATUS:
case PROP_REASON_FOR_DISABLE:
case PROP_AUTHENTICATION_FACTORS:
case PROP_ACTIVATION_TIME:
case PROP_EXPIRATION_TIME:
case PROP_CREDENTIAL_DISABLE:
case PROP_ASSIGNED_ACCESS_RIGHTS:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessCredential(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_Credential_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_CREDENTIAL;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Credential_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_CREDENTIAL
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Credential", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessCredential);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_CREDENTIAL */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 credential 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.
*
*********************************************************************/
/* Access Credential Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_credential.h"
#include "handlers.h"
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_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Credential_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_Credential_Init(
void)
{
unsigned i;
if (!Access_Credential_Initialized) {
Access_Credential_Initialized = true;
for (i = 0; i < MAX_ACCESS_CREDENTIALS; i++) {
ac_descr[i].global_identifier = 0; /* set to some meaningful value */
ac_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
ac_descr[i].credential_status = false;
ac_descr[i].reasons_count = 0;
ac_descr[i].auth_factors_count = 0;
memset(&ac_descr[i].activation_time, 0, sizeof(BACNET_DATE_TIME));
memset(&ac_descr[i].expiration_time, 0, sizeof(BACNET_DATE_TIME));
ac_descr[i].credential_disable = ACCESS_CREDENTIAL_DISABLE_NONE;
ac_descr[i].assigned_access_rights_count = 0;
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_Credential_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_CREDENTIALS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_Credential_Count(
void)
{
return MAX_ACCESS_CREDENTIALS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_Credential_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_Credential_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_CREDENTIALS;
if (object_instance < MAX_ACCESS_CREDENTIALS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_Credential_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_CREDENTIALS) {
sprintf(text_string, "ACCESS CREDENTIAL %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Credential_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index =
Access_Credential_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_ACCESS_CREDENTIAL, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Credential_Object_Name(rpdata->object_instance,
&char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
OBJECT_ACCESS_CREDENTIAL);
break;
case PROP_GLOBAL_IDENTIFIER:
apdu_len =
encode_application_unsigned(&apdu[0],
ac_descr[object_index].global_identifier);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
ac_descr[object_index].reliability);
break;
case PROP_CREDENTIAL_STATUS:
apdu_len =
encode_application_enumerated(&apdu[0],
ac_descr[object_index].credential_status);
break;
case PROP_REASON_FOR_DISABLE:
for (i = 0; i < ac_descr[object_index].reasons_count; i++) {
len =
encode_application_enumerated(&apdu[0],
ac_descr[object_index].reason_for_disable[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
break;
case PROP_AUTHENTICATION_FACTORS:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ac_descr[object_index].auth_factors_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < ac_descr[object_index].auth_factors_count; i++) {
len =
bacapp_encode_credential_authentication_factor(&apdu
[0], &ac_descr[object_index].auth_factors[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
ac_descr[object_index].auth_factors_count) {
apdu_len =
bacapp_encode_credential_authentication_factor(&apdu
[0],
&ac_descr[object_index].
auth_factors[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_ACTIVATION_TIME:
apdu_len =
bacapp_encode_datetime(&apdu[0],
&ac_descr[object_index].activation_time);
break;
case PROP_EXPIRATION_TIME:
apdu_len =
bacapp_encode_datetime(&apdu[0],
&ac_descr[object_index].expiration_time);
break;
case PROP_CREDENTIAL_DISABLE:
apdu_len =
encode_application_enumerated(&apdu[0],
ac_descr[object_index].credential_disable);
break;
case PROP_ASSIGNED_ACCESS_RIGHTS:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ac_descr[object_index].assigned_access_rights_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0;
i < ac_descr[object_index].assigned_access_rights_count;
i++) {
len =
bacapp_encode_assigned_access_rights(&apdu[0],
&ac_descr[object_index].assigned_access_rights[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
ac_descr[object_index].assigned_access_rights_count) {
apdu_len =
bacapp_encode_assigned_access_rights(&apdu[0],
&ac_descr[object_index].
assigned_access_rights[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(rpdata->object_property != PROP_AUTHENTICATION_FACTORS)
&& (rpdata->object_property != PROP_ASSIGNED_ACCESS_RIGHTS)
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_Credential_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->object_property != PROP_AUTHENTICATION_FACTORS)
&& (wp_data->object_property != PROP_ASSIGNED_ACCESS_RIGHTS)
&& (wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index =
Access_Credential_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_GLOBAL_IDENTIFIER:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
ac_descr[object_index].global_identifier =
value.type.Unsigned_Int;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
case PROP_CREDENTIAL_STATUS:
case PROP_REASON_FOR_DISABLE:
case PROP_AUTHENTICATION_FACTORS:
case PROP_ACTIVATION_TIME:
case PROP_EXPIRATION_TIME:
case PROP_CREDENTIAL_DISABLE:
case PROP_ASSIGNED_ACCESS_RIGHTS:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessCredential(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_Credential_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_CREDENTIAL;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Credential_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_CREDENTIAL
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Credential", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessCredential);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_CREDENTIAL */
#endif /* TEST */
+124 -124
View File
@@ -1,124 +1,124 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_CREDENTIAL_H
#define ACCESS_CREDENTIAL_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "datetime.h"
#include "timestamp.h"
#include "bacdevobjpropref.h"
#include "assigned_access_rights.h"
#include "credential_authentication_factor.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_CREDENTIALS
#define MAX_ACCESS_CREDENTIALS 4
#endif
#ifndef MAX_REASONS_FOR_DISABLE
#define MAX_REASONS_FOR_DISABLE 4
#endif
#ifndef MAX_AUTHENTICATION_FACTORS
#define MAX_AUTHENTICATION_FACTORS 4
#endif
#ifndef MAX_ASSIGNED_ACCESS_RIGHTS
#define MAX_ASSIGNED_ACCESS_RIGHTS 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t global_identifier;
BACNET_RELIABILITY reliability;
bool credential_status;
uint32_t reasons_count;
BACNET_ACCESS_CREDENTIAL_DISABLE_REASON
reason_for_disable[MAX_REASONS_FOR_DISABLE];
uint32_t auth_factors_count;
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR
auth_factors[MAX_AUTHENTICATION_FACTORS];
BACNET_DATE_TIME activation_time, expiration_time;
BACNET_ACCESS_CREDENTIAL_DISABLE credential_disable;
uint32_t assigned_access_rights_count;
BACNET_ASSIGNED_ACCESS_RIGHTS
assigned_access_rights[MAX_ASSIGNED_ACCESS_RIGHTS];
} ACCESS_CREDENTIAL_DESCR;
void Access_Credential_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Credential_Valid_Instance(
uint32_t object_instance);
unsigned Access_Credential_Count(
void);
uint32_t Access_Credential_Index_To_Instance(
unsigned index);
unsigned Access_Credential_Instance_To_Index(
uint32_t instance);
bool Access_Credential_Object_Instance_Add(
uint32_t instance);
bool Access_Credential_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Credential_Name_Set(
uint32_t object_instance,
char *new_name);
int Access_Credential_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Credential_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Credential_Create(
uint32_t object_instance);
bool Access_Credential_Delete(
uint32_t object_instance);
void Access_Credential_Cleanup(
void);
void Access_Credential_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessCredential(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_CREDENTIAL_H
#define ACCESS_CREDENTIAL_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "datetime.h"
#include "timestamp.h"
#include "bacdevobjpropref.h"
#include "assigned_access_rights.h"
#include "credential_authentication_factor.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_CREDENTIALS
#define MAX_ACCESS_CREDENTIALS 4
#endif
#ifndef MAX_REASONS_FOR_DISABLE
#define MAX_REASONS_FOR_DISABLE 4
#endif
#ifndef MAX_AUTHENTICATION_FACTORS
#define MAX_AUTHENTICATION_FACTORS 4
#endif
#ifndef MAX_ASSIGNED_ACCESS_RIGHTS
#define MAX_ASSIGNED_ACCESS_RIGHTS 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t global_identifier;
BACNET_RELIABILITY reliability;
bool credential_status;
uint32_t reasons_count;
BACNET_ACCESS_CREDENTIAL_DISABLE_REASON
reason_for_disable[MAX_REASONS_FOR_DISABLE];
uint32_t auth_factors_count;
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR
auth_factors[MAX_AUTHENTICATION_FACTORS];
BACNET_DATE_TIME activation_time, expiration_time;
BACNET_ACCESS_CREDENTIAL_DISABLE credential_disable;
uint32_t assigned_access_rights_count;
BACNET_ASSIGNED_ACCESS_RIGHTS
assigned_access_rights[MAX_ASSIGNED_ACCESS_RIGHTS];
} ACCESS_CREDENTIAL_DESCR;
void Access_Credential_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Credential_Valid_Instance(
uint32_t object_instance);
unsigned Access_Credential_Count(
void);
uint32_t Access_Credential_Index_To_Instance(
unsigned index);
unsigned Access_Credential_Instance_To_Index(
uint32_t instance);
bool Access_Credential_Object_Instance_Add(
uint32_t instance);
bool Access_Credential_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Credential_Name_Set(
uint32_t object_instance,
char *new_name);
int Access_Credential_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Credential_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Credential_Create(
uint32_t object_instance);
bool Access_Credential_Delete(
uint32_t object_instance);
void Access_Credential_Cleanup(
void);
void Access_Credential_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessCredential(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+45 -45
View File
@@ -1,45 +1,45 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_CREDENTIAL
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_credential.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/assigned_access_rights.c \
$(SRC_DIR)/authentication_factor.c \
$(SRC_DIR)/credential_authentication_factor.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_credential
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_CREDENTIAL
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_credential.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/assigned_access_rights.c \
$(SRC_DIR)/authentication_factor.c \
$(SRC_DIR)/credential_authentication_factor.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_credential
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
File diff suppressed because it is too large Load Diff
+143 -143
View File
@@ -1,143 +1,143 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_DOOR_H
#define ACCESS_DOOR_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_DOORS
#define MAX_ACCESS_DOORS 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
bool value_active[BACNET_MAX_PRIORITY];
BACNET_DOOR_VALUE priority_array[BACNET_MAX_PRIORITY];
BACNET_DOOR_VALUE relinquish_default;
BACNET_EVENT_STATE event_state;
BACNET_RELIABILITY reliability;
bool out_of_service;
BACNET_DOOR_STATUS door_status;
BACNET_LOCK_STATUS lock_status;
BACNET_DOOR_SECURED_STATUS secured_status;
uint32_t door_pulse_time, door_extended_pulse_time,
door_unlock_delay_time, door_open_too_long_time;
BACNET_DOOR_ALARM_STATE door_alarm_state;
} ACCESS_DOOR_DESCR;
void Access_Door_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Door_Valid_Instance(
uint32_t object_instance);
unsigned Access_Door_Count(
void);
uint32_t Access_Door_Index_To_Instance(
unsigned index);
unsigned Access_Door_Instance_To_Index(
uint32_t instance);
bool Access_Door_Object_Instance_Add(
uint32_t instance);
BACNET_DOOR_VALUE Access_Door_Present_Value(
uint32_t object_instance);
unsigned Access_Door_Present_Value_Priority(
uint32_t object_instance);
bool Access_Door_Present_Value_Set(
uint32_t object_instance,
BACNET_DOOR_VALUE value,
unsigned priority);
bool Access_Door_Present_Value_Relinquish(
uint32_t object_instance,
unsigned priority);
BACNET_DOOR_VALUE Access_Door_Relinquish_Default(
uint32_t object_instance);
bool Access_Door_Relinquish_Default_Set(
uint32_t object_instance,
float value);
bool Access_Door_Change_Of_Value(
uint32_t instance);
void Access_Door_Change_Of_Value_Clear(
uint32_t instance);
bool Access_Door_Encode_Value_List(
uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
bool Access_Door_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Door_Name_Set(
uint32_t object_instance,
char *new_name);
char *Access_Door_Description(
uint32_t instance);
bool Access_Door_Description_Set(
uint32_t instance,
char *new_name);
bool Access_Door_Out_Of_Service(
uint32_t instance);
void Access_Door_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
int Access_Door_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Door_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Door_Create(
uint32_t object_instance);
bool Access_Door_Delete(
uint32_t object_instance);
void Access_Door_Cleanup(
void);
void Access_Door_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessDoor(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_DOOR_H
#define ACCESS_DOOR_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_DOORS
#define MAX_ACCESS_DOORS 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
bool value_active[BACNET_MAX_PRIORITY];
BACNET_DOOR_VALUE priority_array[BACNET_MAX_PRIORITY];
BACNET_DOOR_VALUE relinquish_default;
BACNET_EVENT_STATE event_state;
BACNET_RELIABILITY reliability;
bool out_of_service;
BACNET_DOOR_STATUS door_status;
BACNET_LOCK_STATUS lock_status;
BACNET_DOOR_SECURED_STATUS secured_status;
uint32_t door_pulse_time, door_extended_pulse_time,
door_unlock_delay_time, door_open_too_long_time;
BACNET_DOOR_ALARM_STATE door_alarm_state;
} ACCESS_DOOR_DESCR;
void Access_Door_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Door_Valid_Instance(
uint32_t object_instance);
unsigned Access_Door_Count(
void);
uint32_t Access_Door_Index_To_Instance(
unsigned index);
unsigned Access_Door_Instance_To_Index(
uint32_t instance);
bool Access_Door_Object_Instance_Add(
uint32_t instance);
BACNET_DOOR_VALUE Access_Door_Present_Value(
uint32_t object_instance);
unsigned Access_Door_Present_Value_Priority(
uint32_t object_instance);
bool Access_Door_Present_Value_Set(
uint32_t object_instance,
BACNET_DOOR_VALUE value,
unsigned priority);
bool Access_Door_Present_Value_Relinquish(
uint32_t object_instance,
unsigned priority);
BACNET_DOOR_VALUE Access_Door_Relinquish_Default(
uint32_t object_instance);
bool Access_Door_Relinquish_Default_Set(
uint32_t object_instance,
float value);
bool Access_Door_Change_Of_Value(
uint32_t instance);
void Access_Door_Change_Of_Value_Clear(
uint32_t instance);
bool Access_Door_Encode_Value_List(
uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
bool Access_Door_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Door_Name_Set(
uint32_t object_instance,
char *new_name);
char *Access_Door_Description(
uint32_t instance);
bool Access_Door_Description_Set(
uint32_t instance,
char *new_name);
bool Access_Door_Out_Of_Service(
uint32_t instance);
void Access_Door_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
int Access_Door_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Door_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Door_Create(
uint32_t object_instance);
bool Access_Door_Delete(
uint32_t object_instance);
void Access_Door_Cleanup(
void);
void Access_Door_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessDoor(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+42 -42
View File
@@ -1,42 +1,42 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_DOOR
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_door.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_door
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_DOOR
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_door.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_door
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
+476 -476
View File
@@ -1,476 +1,476 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Access Point Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_point.h"
#include "handlers.h"
static bool Access_Point_Initialized = false;
static ACCESS_POINT_DESCR ap_descr[MAX_ACCESS_POINTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_AUTHENTICATION_STATUS,
PROP_ACTIVE_AUTHENTICATION_POLICY,
PROP_NUMBER_OF_AUTHENTICATION_POLICIES,
PROP_AUTHORIZATION_MODE,
PROP_ACCESS_EVENT,
PROP_ACCESS_EVENT_TAG,
PROP_ACCESS_EVENT_TIME,
PROP_ACCESS_EVENT_CREDENTIAL,
PROP_ACCESS_DOORS,
PROP_PRIORITY_FOR_WRITING,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Point_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_Point_Init(
void)
{
unsigned i;
if (!Access_Point_Initialized) {
Access_Point_Initialized = true;
for (i = 0; i < MAX_ACCESS_POINTS; i++) {
ap_descr[i].event_state = EVENT_STATE_NORMAL;
ap_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
ap_descr[i].out_of_service = false;
ap_descr[i].authentication_status =
AUTHENTICATION_STATUS_NOT_READY;
ap_descr[i].active_authentication_policy = 0;
ap_descr[i].number_of_authentication_policies = 0;
ap_descr[i].authorization_mode = AUTHORIZATION_MODE_AUTHORIZE;
ap_descr[i].access_event = ACCESS_EVENT_NONE;
/* timestamp uninitialized */
/* access_event_credential should be set to some meaningful value */
ap_descr[i].num_doors = 0;
/* fill in the access doors with proper ids */
ap_descr[i].priority_for_writing = 16; /* lowest possible for now */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_Point_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_POINTS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_Point_Count(
void)
{
return MAX_ACCESS_POINTS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_Point_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_Point_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_POINTS;
if (object_instance < MAX_ACCESS_POINTS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_Point_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_POINTS) {
sprintf(text_string, "ACCESS POINT %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
bool Access_Point_Out_Of_Service(
uint32_t instance)
{
unsigned index = 0;
bool oos_flag = false;
index = Access_Point_Instance_To_Index(instance);
if (index < MAX_ACCESS_POINTS) {
oos_flag = ap_descr[index].out_of_service;
}
return oos_flag;
}
void Access_Point_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag)
{
unsigned index = 0;
index = Access_Point_Instance_To_Index(instance);
if (index < MAX_ACCESS_POINTS) {
ap_descr[index].out_of_service = oos_flag;
}
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Point_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Access_Point_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_POINT,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Point_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_POINT);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
state = Access_Point_Out_Of_Service(rpdata->object_instance);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].event_state);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].reliability);
break;
case PROP_OUT_OF_SERVICE:
state = Access_Point_Out_Of_Service(rpdata->object_instance);
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_AUTHENTICATION_STATUS:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].authentication_status);
break;
case PROP_ACTIVE_AUTHENTICATION_POLICY:
apdu_len =
encode_application_unsigned(&apdu[0],
ap_descr[object_index].active_authentication_policy);
break;
case PROP_NUMBER_OF_AUTHENTICATION_POLICIES:
apdu_len =
encode_application_unsigned(&apdu[0],
ap_descr[object_index].number_of_authentication_policies);
break;
case PROP_AUTHORIZATION_MODE:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].authorization_mode);
break;
case PROP_ACCESS_EVENT:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].access_event);
break;
case PROP_ACCESS_EVENT_TAG:
apdu_len =
encode_application_unsigned(&apdu[0],
ap_descr[object_index].access_event_tag);
break;
case PROP_ACCESS_EVENT_TIME:
apdu_len =
bacapp_encode_timestamp(&apdu[0],
&ap_descr[object_index].access_event_time);
break;
case PROP_ACCESS_EVENT_CREDENTIAL:
apdu_len =
bacapp_encode_device_obj_ref(&apdu[0],
&ap_descr[object_index].access_event_credential);
break;
case PROP_ACCESS_DOORS:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ap_descr[object_index].num_doors);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < ap_descr[object_index].num_doors; i++) {
len =
bacapp_encode_device_obj_ref(&apdu[0],
&ap_descr[object_index].access_doors[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <= ap_descr[object_index].num_doors) {
apdu_len =
bacapp_encode_device_obj_ref(&apdu[0],
&ap_descr[object_index].access_doors[rpdata->
array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_ACCESS_DOORS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_Point_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->object_property != PROP_ACCESS_DOORS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
switch (wp_data->object_property) {
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_RELIABILITY:
case PROP_OUT_OF_SERVICE:
case PROP_AUTHENTICATION_STATUS:
case PROP_ACTIVE_AUTHENTICATION_POLICY:
case PROP_NUMBER_OF_AUTHENTICATION_POLICIES:
case PROP_AUTHORIZATION_MODE:
case PROP_ACCESS_EVENT:
case PROP_ACCESS_EVENT_TAG:
case PROP_ACCESS_EVENT_TIME:
case PROP_ACCESS_EVENT_CREDENTIAL:
case PROP_ACCESS_DOORS:
case PROP_PRIORITY_FOR_WRITING:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessPoint(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_Point_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_POINT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Point_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_POINT
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Point", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessPoint);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_POINT */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Access Point Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_point.h"
#include "handlers.h"
static bool Access_Point_Initialized = false;
static ACCESS_POINT_DESCR ap_descr[MAX_ACCESS_POINTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_AUTHENTICATION_STATUS,
PROP_ACTIVE_AUTHENTICATION_POLICY,
PROP_NUMBER_OF_AUTHENTICATION_POLICIES,
PROP_AUTHORIZATION_MODE,
PROP_ACCESS_EVENT,
PROP_ACCESS_EVENT_TAG,
PROP_ACCESS_EVENT_TIME,
PROP_ACCESS_EVENT_CREDENTIAL,
PROP_ACCESS_DOORS,
PROP_PRIORITY_FOR_WRITING,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Point_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_Point_Init(
void)
{
unsigned i;
if (!Access_Point_Initialized) {
Access_Point_Initialized = true;
for (i = 0; i < MAX_ACCESS_POINTS; i++) {
ap_descr[i].event_state = EVENT_STATE_NORMAL;
ap_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
ap_descr[i].out_of_service = false;
ap_descr[i].authentication_status =
AUTHENTICATION_STATUS_NOT_READY;
ap_descr[i].active_authentication_policy = 0;
ap_descr[i].number_of_authentication_policies = 0;
ap_descr[i].authorization_mode = AUTHORIZATION_MODE_AUTHORIZE;
ap_descr[i].access_event = ACCESS_EVENT_NONE;
/* timestamp uninitialized */
/* access_event_credential should be set to some meaningful value */
ap_descr[i].num_doors = 0;
/* fill in the access doors with proper ids */
ap_descr[i].priority_for_writing = 16; /* lowest possible for now */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_Point_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_POINTS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_Point_Count(
void)
{
return MAX_ACCESS_POINTS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_Point_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_Point_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_POINTS;
if (object_instance < MAX_ACCESS_POINTS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_Point_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_POINTS) {
sprintf(text_string, "ACCESS POINT %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
bool Access_Point_Out_Of_Service(
uint32_t instance)
{
unsigned index = 0;
bool oos_flag = false;
index = Access_Point_Instance_To_Index(instance);
if (index < MAX_ACCESS_POINTS) {
oos_flag = ap_descr[index].out_of_service;
}
return oos_flag;
}
void Access_Point_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag)
{
unsigned index = 0;
index = Access_Point_Instance_To_Index(instance);
if (index < MAX_ACCESS_POINTS) {
ap_descr[index].out_of_service = oos_flag;
}
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Point_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Access_Point_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_POINT,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Point_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_POINT);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
state = Access_Point_Out_Of_Service(rpdata->object_instance);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].event_state);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].reliability);
break;
case PROP_OUT_OF_SERVICE:
state = Access_Point_Out_Of_Service(rpdata->object_instance);
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_AUTHENTICATION_STATUS:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].authentication_status);
break;
case PROP_ACTIVE_AUTHENTICATION_POLICY:
apdu_len =
encode_application_unsigned(&apdu[0],
ap_descr[object_index].active_authentication_policy);
break;
case PROP_NUMBER_OF_AUTHENTICATION_POLICIES:
apdu_len =
encode_application_unsigned(&apdu[0],
ap_descr[object_index].number_of_authentication_policies);
break;
case PROP_AUTHORIZATION_MODE:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].authorization_mode);
break;
case PROP_ACCESS_EVENT:
apdu_len =
encode_application_enumerated(&apdu[0],
ap_descr[object_index].access_event);
break;
case PROP_ACCESS_EVENT_TAG:
apdu_len =
encode_application_unsigned(&apdu[0],
ap_descr[object_index].access_event_tag);
break;
case PROP_ACCESS_EVENT_TIME:
apdu_len =
bacapp_encode_timestamp(&apdu[0],
&ap_descr[object_index].access_event_time);
break;
case PROP_ACCESS_EVENT_CREDENTIAL:
apdu_len =
bacapp_encode_device_obj_ref(&apdu[0],
&ap_descr[object_index].access_event_credential);
break;
case PROP_ACCESS_DOORS:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ap_descr[object_index].num_doors);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < ap_descr[object_index].num_doors; i++) {
len =
bacapp_encode_device_obj_ref(&apdu[0],
&ap_descr[object_index].access_doors[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <= ap_descr[object_index].num_doors) {
apdu_len =
bacapp_encode_device_obj_ref(&apdu[0],
&ap_descr[object_index].access_doors[rpdata->
array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_ACCESS_DOORS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_Point_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->object_property != PROP_ACCESS_DOORS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
switch (wp_data->object_property) {
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_RELIABILITY:
case PROP_OUT_OF_SERVICE:
case PROP_AUTHENTICATION_STATUS:
case PROP_ACTIVE_AUTHENTICATION_POLICY:
case PROP_NUMBER_OF_AUTHENTICATION_POLICIES:
case PROP_AUTHORIZATION_MODE:
case PROP_ACCESS_EVENT:
case PROP_ACCESS_EVENT_TAG:
case PROP_ACCESS_EVENT_TIME:
case PROP_ACCESS_EVENT_CREDENTIAL:
case PROP_ACCESS_DOORS:
case PROP_PRIORITY_FOR_WRITING:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessPoint(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_Point_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_POINT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Point_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_POINT
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Point", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessPoint);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_POINT */
#endif /* TEST */
+120 -120
View File
@@ -1,120 +1,120 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_POINT_H
#define ACCESS_POINT_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "timestamp.h"
#include "bacdevobjpropref.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_POINTS
#define MAX_ACCESS_POINTS 4
#endif
#ifndef MAX_ACCESS_DOORS_COUNT
#define MAX_ACCESS_DOORS_COUNT 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
BACNET_EVENT_STATE event_state;
BACNET_RELIABILITY reliability;
bool out_of_service;
BACNET_AUTHENTICATION_STATUS authentication_status;
uint32_t active_authentication_policy,
number_of_authentication_policies;
BACNET_AUTHORIZATION_MODE authorization_mode;
BACNET_ACCESS_EVENT access_event;
uint32_t access_event_tag;
BACNET_TIMESTAMP access_event_time;
BACNET_DEVICE_OBJECT_REFERENCE access_event_credential;
uint32_t num_doors; /* helper value, not a property */
BACNET_DEVICE_OBJECT_REFERENCE access_doors[MAX_ACCESS_DOORS_COUNT];
uint8_t priority_for_writing;
} ACCESS_POINT_DESCR;
void Access_Point_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Point_Valid_Instance(
uint32_t object_instance);
unsigned Access_Point_Count(
void);
uint32_t Access_Point_Index_To_Instance(
unsigned index);
unsigned Access_Point_Instance_To_Index(
uint32_t instance);
bool Access_Point_Object_Instance_Add(
uint32_t instance);
bool Access_Point_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Point_Name_Set(
uint32_t object_instance,
char *new_name);
bool Access_Point_Out_Of_Service(
uint32_t instance);
void Access_Point_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
int Access_Point_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Point_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Point_Create(
uint32_t object_instance);
bool Access_Point_Delete(
uint32_t object_instance);
void Access_Point_Cleanup(
void);
void Access_Point_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessPoint(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_POINT_H
#define ACCESS_POINT_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "timestamp.h"
#include "bacdevobjpropref.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_POINTS
#define MAX_ACCESS_POINTS 4
#endif
#ifndef MAX_ACCESS_DOORS_COUNT
#define MAX_ACCESS_DOORS_COUNT 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
BACNET_EVENT_STATE event_state;
BACNET_RELIABILITY reliability;
bool out_of_service;
BACNET_AUTHENTICATION_STATUS authentication_status;
uint32_t active_authentication_policy,
number_of_authentication_policies;
BACNET_AUTHORIZATION_MODE authorization_mode;
BACNET_ACCESS_EVENT access_event;
uint32_t access_event_tag;
BACNET_TIMESTAMP access_event_time;
BACNET_DEVICE_OBJECT_REFERENCE access_event_credential;
uint32_t num_doors; /* helper value, not a property */
BACNET_DEVICE_OBJECT_REFERENCE access_doors[MAX_ACCESS_DOORS_COUNT];
uint8_t priority_for_writing;
} ACCESS_POINT_DESCR;
void Access_Point_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Point_Valid_Instance(
uint32_t object_instance);
unsigned Access_Point_Count(
void);
uint32_t Access_Point_Index_To_Instance(
unsigned index);
unsigned Access_Point_Instance_To_Index(
uint32_t instance);
bool Access_Point_Object_Instance_Add(
uint32_t instance);
bool Access_Point_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Point_Name_Set(
uint32_t object_instance,
char *new_name);
bool Access_Point_Out_Of_Service(
uint32_t instance);
void Access_Point_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
int Access_Point_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Point_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Point_Create(
uint32_t object_instance);
bool Access_Point_Delete(
uint32_t object_instance);
void Access_Point_Cleanup(
void);
void Access_Point_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessPoint(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+43 -43
View File
@@ -1,43 +1,43 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_POINT
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_point.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(SRC_DIR)/timestamp.c \
$(TEST_DIR)/ctest.c
TARGET = access_point
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_POINT
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_point.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(SRC_DIR)/timestamp.c \
$(TEST_DIR)/ctest.c
TARGET = access_point
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
+435 -435
View File
@@ -1,435 +1,435 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Access Rights Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_rights.h"
#include "handlers.h"
static bool Access_Rights_Initialized = false;
static ACCESS_RIGHTS_DESCR ar_descr[MAX_ACCESS_RIGHTSS];
/* 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_ENABLE,
PROP_NEGATIVE_ACCESS_RULES,
PROP_POSITIVE_ACCESS_RULES,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Rights_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_Rights_Init(
void)
{
unsigned i;
if (!Access_Rights_Initialized) {
Access_Rights_Initialized = true;
for (i = 0; i < MAX_ACCESS_RIGHTSS; i++) {
ar_descr[i].global_identifier = 0; /* set to some meaningful value */
ar_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
ar_descr[i].enable = false;
ar_descr[i].negative_access_rules_count = 0;
ar_descr[i].positive_access_rules_count = 0;
/* fill in the positive and negative access rules with proper ids */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_Rights_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_RIGHTSS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_Rights_Count(
void)
{
return MAX_ACCESS_RIGHTSS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_Rights_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_Rights_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_RIGHTSS;
if (object_instance < MAX_ACCESS_RIGHTSS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_Rights_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_RIGHTSS) {
sprintf(text_string, "ACCESS RIGHTS %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Rights_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Access_Rights_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_RIGHTS,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Rights_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_RIGHTS);
break;
case PROP_GLOBAL_IDENTIFIER:
apdu_len =
encode_application_unsigned(&apdu[0],
ar_descr[object_index].global_identifier);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
ar_descr[object_index].reliability);
break;
case PROP_ENABLE:
apdu_len =
encode_application_boolean(&apdu[0],
ar_descr[object_index].enable);
break;
case PROP_NEGATIVE_ACCESS_RULES:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ar_descr[object_index].negative_access_rules_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0;
i < ar_descr[object_index].negative_access_rules_count;
i++) {
len =
bacapp_encode_access_rule(&apdu[0],
&ar_descr[object_index].negative_access_rules[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
ar_descr[object_index].negative_access_rules_count) {
apdu_len =
bacapp_encode_access_rule(&apdu[0],
&ar_descr[object_index].
negative_access_rules[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_POSITIVE_ACCESS_RULES:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ar_descr[object_index].positive_access_rules_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0;
i < ar_descr[object_index].positive_access_rules_count;
i++) {
len =
bacapp_encode_access_rule(&apdu[0],
&ar_descr[object_index].positive_access_rules[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
ar_descr[object_index].positive_access_rules_count) {
apdu_len =
bacapp_encode_access_rule(&apdu[0],
&ar_descr[object_index].
positive_access_rules[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(rpdata->object_property != PROP_NEGATIVE_ACCESS_RULES)
&& (rpdata->object_property != PROP_POSITIVE_ACCESS_RULES)
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_Rights_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->object_property != PROP_NEGATIVE_ACCESS_RULES)
&& (wp_data->object_property != PROP_POSITIVE_ACCESS_RULES)
&& (wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index = Access_Rights_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_GLOBAL_IDENTIFIER:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
ar_descr[object_index].global_identifier =
value.type.Unsigned_Int;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
case PROP_ENABLE:
case PROP_NEGATIVE_ACCESS_RULES:
case PROP_POSITIVE_ACCESS_RULES:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessRights(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_Rights_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_RIGHTS;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Rights_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_RIGHTS
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Rights", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessRights);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_RIGHTS */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Access Rights Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_rights.h"
#include "handlers.h"
static bool Access_Rights_Initialized = false;
static ACCESS_RIGHTS_DESCR ar_descr[MAX_ACCESS_RIGHTSS];
/* 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_ENABLE,
PROP_NEGATIVE_ACCESS_RULES,
PROP_POSITIVE_ACCESS_RULES,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Rights_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_Rights_Init(
void)
{
unsigned i;
if (!Access_Rights_Initialized) {
Access_Rights_Initialized = true;
for (i = 0; i < MAX_ACCESS_RIGHTSS; i++) {
ar_descr[i].global_identifier = 0; /* set to some meaningful value */
ar_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
ar_descr[i].enable = false;
ar_descr[i].negative_access_rules_count = 0;
ar_descr[i].positive_access_rules_count = 0;
/* fill in the positive and negative access rules with proper ids */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_Rights_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_RIGHTSS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_Rights_Count(
void)
{
return MAX_ACCESS_RIGHTSS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_Rights_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_Rights_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_RIGHTSS;
if (object_instance < MAX_ACCESS_RIGHTSS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_Rights_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_RIGHTSS) {
sprintf(text_string, "ACCESS RIGHTS %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Rights_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Access_Rights_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_RIGHTS,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Rights_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_RIGHTS);
break;
case PROP_GLOBAL_IDENTIFIER:
apdu_len =
encode_application_unsigned(&apdu[0],
ar_descr[object_index].global_identifier);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
ar_descr[object_index].reliability);
break;
case PROP_ENABLE:
apdu_len =
encode_application_boolean(&apdu[0],
ar_descr[object_index].enable);
break;
case PROP_NEGATIVE_ACCESS_RULES:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ar_descr[object_index].negative_access_rules_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0;
i < ar_descr[object_index].negative_access_rules_count;
i++) {
len =
bacapp_encode_access_rule(&apdu[0],
&ar_descr[object_index].negative_access_rules[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
ar_descr[object_index].negative_access_rules_count) {
apdu_len =
bacapp_encode_access_rule(&apdu[0],
&ar_descr[object_index].
negative_access_rules[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_POSITIVE_ACCESS_RULES:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
ar_descr[object_index].positive_access_rules_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0;
i < ar_descr[object_index].positive_access_rules_count;
i++) {
len =
bacapp_encode_access_rule(&apdu[0],
&ar_descr[object_index].positive_access_rules[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
ar_descr[object_index].positive_access_rules_count) {
apdu_len =
bacapp_encode_access_rule(&apdu[0],
&ar_descr[object_index].
positive_access_rules[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) &&
(rpdata->object_property != PROP_NEGATIVE_ACCESS_RULES)
&& (rpdata->object_property != PROP_POSITIVE_ACCESS_RULES)
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_Rights_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->object_property != PROP_NEGATIVE_ACCESS_RULES)
&& (wp_data->object_property != PROP_POSITIVE_ACCESS_RULES)
&& (wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index = Access_Rights_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_GLOBAL_IDENTIFIER:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
ar_descr[object_index].global_identifier =
value.type.Unsigned_Int;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
case PROP_ENABLE:
case PROP_NEGATIVE_ACCESS_RULES:
case PROP_POSITIVE_ACCESS_RULES:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessRights(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_Rights_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_RIGHTS;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Rights_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_RIGHTS
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Rights", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessRights);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_RIGHTS */
#endif /* TEST */
+110 -110
View File
@@ -1,110 +1,110 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_RIGHTS_H
#define ACCESS_RIGHTS_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "bacdevobjpropref.h"
#include "access_rule.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_RIGHTSS
#define MAX_ACCESS_RIGHTSS 4
#endif
#ifndef MAX_NEGATIVE_ACCESS_RIGHTS_RULES
#define MAX_NEGATIVE_ACCESS_RIGHTS_RULES 4
#endif
#ifndef MAX_POSITIVE_ACCESS_RIGHTS_RULES
#define MAX_POSITIVE_ACCESS_RIGHTS_RULES 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t global_identifier;
BACNET_RELIABILITY reliability;
bool enable;
uint32_t negative_access_rules_count, positive_access_rules_count;
BACNET_ACCESS_RULE
negative_access_rules[MAX_NEGATIVE_ACCESS_RIGHTS_RULES];
BACNET_ACCESS_RULE
positive_access_rules[MAX_POSITIVE_ACCESS_RIGHTS_RULES];
} ACCESS_RIGHTS_DESCR;
void Access_Rights_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Rights_Valid_Instance(
uint32_t object_instance);
unsigned Access_Rights_Count(
void);
uint32_t Access_Rights_Index_To_Instance(
unsigned index);
unsigned Access_Rights_Instance_To_Index(
uint32_t instance);
bool Access_Rights_Object_Instance_Add(
uint32_t instance);
bool Access_Rights_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Rights_Name_Set(
uint32_t object_instance,
char *new_name);
int Access_Rights_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Rights_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Rights_Create(
uint32_t object_instance);
bool Access_Rights_Delete(
uint32_t object_instance);
void Access_Rights_Cleanup(
void);
void Access_Rights_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessRights(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_RIGHTS_H
#define ACCESS_RIGHTS_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "bacdevobjpropref.h"
#include "access_rule.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_RIGHTSS
#define MAX_ACCESS_RIGHTSS 4
#endif
#ifndef MAX_NEGATIVE_ACCESS_RIGHTS_RULES
#define MAX_NEGATIVE_ACCESS_RIGHTS_RULES 4
#endif
#ifndef MAX_POSITIVE_ACCESS_RIGHTS_RULES
#define MAX_POSITIVE_ACCESS_RIGHTS_RULES 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t global_identifier;
BACNET_RELIABILITY reliability;
bool enable;
uint32_t negative_access_rules_count, positive_access_rules_count;
BACNET_ACCESS_RULE
negative_access_rules[MAX_NEGATIVE_ACCESS_RIGHTS_RULES];
BACNET_ACCESS_RULE
positive_access_rules[MAX_POSITIVE_ACCESS_RIGHTS_RULES];
} ACCESS_RIGHTS_DESCR;
void Access_Rights_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Rights_Valid_Instance(
uint32_t object_instance);
unsigned Access_Rights_Count(
void);
uint32_t Access_Rights_Index_To_Instance(
unsigned index);
unsigned Access_Rights_Instance_To_Index(
uint32_t instance);
bool Access_Rights_Object_Instance_Add(
uint32_t instance);
bool Access_Rights_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Rights_Name_Set(
uint32_t object_instance,
char *new_name);
int Access_Rights_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Rights_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Rights_Create(
uint32_t object_instance);
bool Access_Rights_Delete(
uint32_t object_instance);
void Access_Rights_Cleanup(
void);
void Access_Rights_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessRights(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+43 -43
View File
@@ -1,43 +1,43 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_RIGHTS
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_rights.c \
$(SRC_DIR)/access_rule.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_rights
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_RIGHTS
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_rights.c \
$(SRC_DIR)/access_rule.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_rights
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
+373 -373
View File
@@ -1,373 +1,373 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Access User Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_user.h"
#include "handlers.h"
static bool Access_User_Initialized = false;
static ACCESS_USER_DESCR au_descr[MAX_ACCESS_USERS];
/* 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_USER_TYPE,
PROP_CREDENTIALS,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_User_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_User_Init(
void)
{
unsigned i;
if (!Access_User_Initialized) {
Access_User_Initialized = true;
for (i = 0; i < MAX_ACCESS_USERS; i++) {
au_descr[i].global_identifier = 0; /* set to some meaningful value */
au_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
au_descr[i].user_type = ACCESS_USER_TYPE_PERSON;
au_descr[i].credentials_count = 0;
/* fill in the credentials with proper ids */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_User_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_USERS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_User_Count(
void)
{
return MAX_ACCESS_USERS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_User_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_User_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_USERS;
if (object_instance < MAX_ACCESS_USERS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_User_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_USERS) {
sprintf(text_string, "ACCESS USER %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_User_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Access_User_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_USER,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_User_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_USER);
break;
case PROP_GLOBAL_IDENTIFIER:
apdu_len =
encode_application_unsigned(&apdu[0],
au_descr[object_index].global_identifier);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
au_descr[object_index].reliability);
break;
case PROP_USER_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
au_descr[object_index].user_type);
break;
case PROP_CREDENTIALS:
for (i = 0; i < au_descr[object_index].credentials_count; i++) {
len =
bacapp_encode_device_obj_ref(&apdu[0],
&au_descr[object_index].credentials[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_User_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index = Access_User_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_GLOBAL_IDENTIFIER:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
au_descr[object_index].global_identifier =
value.type.Unsigned_Int;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
case PROP_USER_TYPE:
case PROP_CREDENTIALS:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessUser(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_User_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_USER;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_User_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_USER
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access User", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessUser);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_USER */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Access User Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_user.h"
#include "handlers.h"
static bool Access_User_Initialized = false;
static ACCESS_USER_DESCR au_descr[MAX_ACCESS_USERS];
/* 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_USER_TYPE,
PROP_CREDENTIALS,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_User_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_User_Init(
void)
{
unsigned i;
if (!Access_User_Initialized) {
Access_User_Initialized = true;
for (i = 0; i < MAX_ACCESS_USERS; i++) {
au_descr[i].global_identifier = 0; /* set to some meaningful value */
au_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
au_descr[i].user_type = ACCESS_USER_TYPE_PERSON;
au_descr[i].credentials_count = 0;
/* fill in the credentials with proper ids */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_User_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_USERS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_User_Count(
void)
{
return MAX_ACCESS_USERS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_User_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_User_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_USERS;
if (object_instance < MAX_ACCESS_USERS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_User_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_USERS) {
sprintf(text_string, "ACCESS USER %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_User_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Access_User_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_USER,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_User_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_USER);
break;
case PROP_GLOBAL_IDENTIFIER:
apdu_len =
encode_application_unsigned(&apdu[0],
au_descr[object_index].global_identifier);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
au_descr[object_index].reliability);
break;
case PROP_USER_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
au_descr[object_index].user_type);
break;
case PROP_CREDENTIALS:
for (i = 0; i < au_descr[object_index].credentials_count; i++) {
len =
bacapp_encode_device_obj_ref(&apdu[0],
&au_descr[object_index].credentials[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_User_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index = Access_User_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_GLOBAL_IDENTIFIER:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
au_descr[object_index].global_identifier =
value.type.Unsigned_Int;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
case PROP_USER_TYPE:
case PROP_CREDENTIALS:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessUser(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_User_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_USER;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_User_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_USER
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access User", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessUser);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_USER */
#endif /* TEST */
+103 -103
View File
@@ -1,103 +1,103 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_USER_H
#define ACCESS_USER_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "bacdevobjpropref.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_USERS
#define MAX_ACCESS_USERS 4
#endif
#ifndef MAX_ACCESS_USER_CREDENTIALS_COUNT
#define MAX_ACCESS_USER_CREDENTIALS_COUNT 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t global_identifier;
BACNET_RELIABILITY reliability;
BACNET_ACCESS_USER_TYPE user_type;
uint32_t credentials_count;
BACNET_DEVICE_OBJECT_REFERENCE
credentials[MAX_ACCESS_USER_CREDENTIALS_COUNT];
} ACCESS_USER_DESCR;
void Access_User_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_User_Valid_Instance(
uint32_t object_instance);
unsigned Access_User_Count(
void);
uint32_t Access_User_Index_To_Instance(
unsigned index);
unsigned Access_User_Instance_To_Index(
uint32_t instance);
bool Access_User_Object_Instance_Add(
uint32_t instance);
bool Access_User_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_User_Name_Set(
uint32_t object_instance,
char *new_name);
int Access_User_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_User_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_User_Create(
uint32_t object_instance);
bool Access_User_Delete(
uint32_t object_instance);
void Access_User_Cleanup(
void);
void Access_User_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessUser(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_USER_H
#define ACCESS_USER_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "bacdevobjpropref.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_USERS
#define MAX_ACCESS_USERS 4
#endif
#ifndef MAX_ACCESS_USER_CREDENTIALS_COUNT
#define MAX_ACCESS_USER_CREDENTIALS_COUNT 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t global_identifier;
BACNET_RELIABILITY reliability;
BACNET_ACCESS_USER_TYPE user_type;
uint32_t credentials_count;
BACNET_DEVICE_OBJECT_REFERENCE
credentials[MAX_ACCESS_USER_CREDENTIALS_COUNT];
} ACCESS_USER_DESCR;
void Access_User_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_User_Valid_Instance(
uint32_t object_instance);
unsigned Access_User_Count(
void);
uint32_t Access_User_Index_To_Instance(
unsigned index);
unsigned Access_User_Instance_To_Index(
uint32_t instance);
bool Access_User_Object_Instance_Add(
uint32_t instance);
bool Access_User_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_User_Name_Set(
uint32_t object_instance,
char *new_name);
int Access_User_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_User_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_User_Create(
uint32_t object_instance);
bool Access_User_Delete(
uint32_t object_instance);
void Access_User_Cleanup(
void);
void Access_User_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessUser(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+42 -42
View File
@@ -1,42 +1,42 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_USER
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_user.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_user
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_USER
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_user.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_user
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
+446 -446
View File
@@ -1,446 +1,446 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Access Zone Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_zone.h"
#include "handlers.h"
static bool Access_Zone_Initialized = false;
static ACCESS_ZONE_DESCR az_descr[MAX_ACCESS_ZONES];
/* 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_OCCUPANCY_STATE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_ENTRY_POINTS,
PROP_EXIT_POINTS,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Zone_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_Zone_Init(
void)
{
unsigned i;
if (!Access_Zone_Initialized) {
Access_Zone_Initialized = true;
for (i = 0; i < MAX_ACCESS_ZONES; i++) {
az_descr[i].global_identifier = 0; /* set to some meaningful value */
az_descr[i].occupancy_state = ACCESS_ZONE_OCCUPANCY_STATE_DISABLED;
az_descr[i].event_state = EVENT_STATE_NORMAL;
az_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
az_descr[i].out_of_service = false;
az_descr[i].entry_points_count = 0;
az_descr[i].exit_points_count = 0;
/* fill in the entry points and exit points with proper ids */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_Zone_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_ZONES)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_Zone_Count(
void)
{
return MAX_ACCESS_ZONES;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_Zone_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_Zone_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_ZONES;
if (object_instance < MAX_ACCESS_ZONES)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_Zone_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_ZONES) {
sprintf(text_string, "ACCESS ZONE %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
bool Access_Zone_Out_Of_Service(
uint32_t instance)
{
unsigned index = 0;
bool oos_flag = false;
index = Access_Zone_Instance_To_Index(instance);
if (index < MAX_ACCESS_ZONES) {
oos_flag = az_descr[index].out_of_service;
}
return oos_flag;
}
void Access_Zone_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag)
{
unsigned index = 0;
index = Access_Zone_Instance_To_Index(instance);
if (index < MAX_ACCESS_ZONES) {
az_descr[index].out_of_service = oos_flag;
}
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Zone_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Access_Zone_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_ZONE,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Zone_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_ZONE);
break;
case PROP_GLOBAL_IDENTIFIER:
apdu_len =
encode_application_unsigned(&apdu[0],
az_descr[object_index].global_identifier);
break;
case PROP_OCCUPANCY_STATE:
apdu_len =
encode_application_enumerated(&apdu[0],
az_descr[object_index].occupancy_state);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
state = Access_Zone_Out_Of_Service(rpdata->object_instance);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
apdu_len =
encode_application_enumerated(&apdu[0],
az_descr[object_index].event_state);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
az_descr[object_index].reliability);
break;
case PROP_OUT_OF_SERVICE:
state = Access_Zone_Out_Of_Service(rpdata->object_instance);
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_ENTRY_POINTS:
for (i = 0; i < az_descr[object_index].entry_points_count; i++) {
len =
bacapp_encode_device_obj_ref(&apdu[0],
&az_descr[object_index].entry_points[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
break;
case PROP_EXIT_POINTS:
for (i = 0; i < az_descr[object_index].exit_points_count; i++) {
len =
bacapp_encode_device_obj_ref(&apdu[0],
&az_descr[object_index].exit_points[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_Zone_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index = Access_Zone_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_GLOBAL_IDENTIFIER:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
az_descr[object_index].global_identifier =
value.type.Unsigned_Int;
}
break;
case PROP_RELIABILITY:
if (Access_Zone_Out_Of_Service(wp_data->object_instance)) {
status =
WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
&wp_data->error_code);
if (status) {
az_descr[object_index].reliability = value.type.Enumerated;
}
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_OCCUPANCY_STATE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_OUT_OF_SERVICE:
case PROP_ENTRY_POINTS:
case PROP_EXIT_POINTS:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessZone(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_Zone_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_ZONE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Zone_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_ZONE
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Zone", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessZone);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_ZONE */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Access Zone Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "access_zone.h"
#include "handlers.h"
static bool Access_Zone_Initialized = false;
static ACCESS_ZONE_DESCR az_descr[MAX_ACCESS_ZONES];
/* 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_OCCUPANCY_STATE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_ENTRY_POINTS,
PROP_EXIT_POINTS,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Zone_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Access_Zone_Init(
void)
{
unsigned i;
if (!Access_Zone_Initialized) {
Access_Zone_Initialized = true;
for (i = 0; i < MAX_ACCESS_ZONES; i++) {
az_descr[i].global_identifier = 0; /* set to some meaningful value */
az_descr[i].occupancy_state = ACCESS_ZONE_OCCUPANCY_STATE_DISABLED;
az_descr[i].event_state = EVENT_STATE_NORMAL;
az_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
az_descr[i].out_of_service = false;
az_descr[i].entry_points_count = 0;
az_descr[i].exit_points_count = 0;
/* fill in the entry points and exit points with proper ids */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Access_Zone_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_ZONES)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Access_Zone_Count(
void)
{
return MAX_ACCESS_ZONES;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Access_Zone_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Access_Zone_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_ZONES;
if (object_instance < MAX_ACCESS_ZONES)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Access_Zone_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ACCESS_ZONES) {
sprintf(text_string, "ACCESS ZONE %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
bool Access_Zone_Out_Of_Service(
uint32_t instance)
{
unsigned index = 0;
bool oos_flag = false;
index = Access_Zone_Instance_To_Index(instance);
if (index < MAX_ACCESS_ZONES) {
oos_flag = az_descr[index].out_of_service;
}
return oos_flag;
}
void Access_Zone_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag)
{
unsigned index = 0;
index = Access_Zone_Instance_To_Index(instance);
if (index < MAX_ACCESS_ZONES) {
az_descr[index].out_of_service = oos_flag;
}
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Zone_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index = Access_Zone_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_ZONE,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Zone_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_ZONE);
break;
case PROP_GLOBAL_IDENTIFIER:
apdu_len =
encode_application_unsigned(&apdu[0],
az_descr[object_index].global_identifier);
break;
case PROP_OCCUPANCY_STATE:
apdu_len =
encode_application_enumerated(&apdu[0],
az_descr[object_index].occupancy_state);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
state = Access_Zone_Out_Of_Service(rpdata->object_instance);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
apdu_len =
encode_application_enumerated(&apdu[0],
az_descr[object_index].event_state);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
az_descr[object_index].reliability);
break;
case PROP_OUT_OF_SERVICE:
state = Access_Zone_Out_Of_Service(rpdata->object_instance);
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_ENTRY_POINTS:
for (i = 0; i < az_descr[object_index].entry_points_count; i++) {
len =
bacapp_encode_device_obj_ref(&apdu[0],
&az_descr[object_index].entry_points[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
break;
case PROP_EXIT_POINTS:
for (i = 0; i < az_descr[object_index].exit_points_count; i++) {
len =
bacapp_encode_device_obj_ref(&apdu[0],
&az_descr[object_index].exit_points[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Access_Zone_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index = Access_Zone_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_GLOBAL_IDENTIFIER:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
az_descr[object_index].global_identifier =
value.type.Unsigned_Int;
}
break;
case PROP_RELIABILITY:
if (Access_Zone_Out_Of_Service(wp_data->object_instance)) {
status =
WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
&wp_data->error_code);
if (status) {
az_descr[object_index].reliability = value.type.Enumerated;
}
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_OCCUPANCY_STATE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_OUT_OF_SERVICE:
case PROP_ENTRY_POINTS:
case PROP_EXIT_POINTS:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testAccessZone(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Access_Zone_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_ZONE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Zone_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_ACCESS_ZONE
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Zone", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessZone);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_ZONE */
#endif /* TEST */
+117 -117
View File
@@ -1,117 +1,117 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_ZONE_H
#define ACCESS_ZONE_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "bacdevobjpropref.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_ZONES
#define MAX_ACCESS_ZONES 4
#endif
#ifndef MAX_ACCESS_ZONE_ENTRY_POINTS
#define MAX_ACCESS_ZONE_ENTRY_POINTS 4
#endif
#ifndef MAX_ACCESS_ZONE_EXIT_POINTS
#define MAX_ACCESS_ZONE_EXIT_POINTS 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t global_identifier;
BACNET_ACCESS_ZONE_OCCUPANCY_STATE occupancy_state;
BACNET_EVENT_STATE event_state;
BACNET_RELIABILITY reliability;
bool out_of_service;
uint32_t entry_points_count, exit_points_count;
BACNET_DEVICE_OBJECT_REFERENCE
entry_points[MAX_ACCESS_ZONE_ENTRY_POINTS];
BACNET_DEVICE_OBJECT_REFERENCE
exit_points[MAX_ACCESS_ZONE_EXIT_POINTS];
} ACCESS_ZONE_DESCR;
void Access_Zone_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Zone_Valid_Instance(
uint32_t object_instance);
unsigned Access_Zone_Count(
void);
uint32_t Access_Zone_Index_To_Instance(
unsigned index);
unsigned Access_Zone_Instance_To_Index(
uint32_t instance);
bool Access_Zone_Object_Instance_Add(
uint32_t instance);
bool Access_Zone_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Zone_Name_Set(
uint32_t object_instance,
char *new_name);
bool Access_Zone_Out_Of_Service(
uint32_t instance);
void Access_Zone_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
int Access_Zone_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Zone_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Zone_Create(
uint32_t object_instance);
bool Access_Zone_Delete(
uint32_t object_instance);
void Access_Zone_Cleanup(
void);
void Access_Zone_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessZone(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 ACCESS_ZONE_H
#define ACCESS_ZONE_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "bacdevobjpropref.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_ACCESS_ZONES
#define MAX_ACCESS_ZONES 4
#endif
#ifndef MAX_ACCESS_ZONE_ENTRY_POINTS
#define MAX_ACCESS_ZONE_ENTRY_POINTS 4
#endif
#ifndef MAX_ACCESS_ZONE_EXIT_POINTS
#define MAX_ACCESS_ZONE_EXIT_POINTS 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
uint32_t global_identifier;
BACNET_ACCESS_ZONE_OCCUPANCY_STATE occupancy_state;
BACNET_EVENT_STATE event_state;
BACNET_RELIABILITY reliability;
bool out_of_service;
uint32_t entry_points_count, exit_points_count;
BACNET_DEVICE_OBJECT_REFERENCE
entry_points[MAX_ACCESS_ZONE_ENTRY_POINTS];
BACNET_DEVICE_OBJECT_REFERENCE
exit_points[MAX_ACCESS_ZONE_EXIT_POINTS];
} ACCESS_ZONE_DESCR;
void Access_Zone_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Access_Zone_Valid_Instance(
uint32_t object_instance);
unsigned Access_Zone_Count(
void);
uint32_t Access_Zone_Index_To_Instance(
unsigned index);
unsigned Access_Zone_Instance_To_Index(
uint32_t instance);
bool Access_Zone_Object_Instance_Add(
uint32_t instance);
bool Access_Zone_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Access_Zone_Name_Set(
uint32_t object_instance,
char *new_name);
bool Access_Zone_Out_Of_Service(
uint32_t instance);
void Access_Zone_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
int Access_Zone_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Access_Zone_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Access_Zone_Create(
uint32_t object_instance);
bool Access_Zone_Delete(
uint32_t object_instance);
void Access_Zone_Cleanup(
void);
void Access_Zone_Init(
void);
#ifdef TEST
#include "ctest.h"
void testAccessZone(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+42 -42
View File
@@ -1,42 +1,42 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_ZONE
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_zone.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_zone
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_ZONE
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = access_zone.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = access_zone
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
File diff suppressed because it is too large Load Diff
+203 -203
View File
@@ -1,203 +1,203 @@
/**
* @file
* @author Steve Karg
* @date 2013
* @brief Channel objects, customize for your use
*
* @section DESCRIPTION
*
* The Channel object is a command object without a priority array, and the
* present-value property uses a priority array and a single precision floating point
* data type.
*
* @section LICENSE
*
* 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 CHANNEL_H
#define CHANNEL_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "rp.h"
#include "wp.h"
#include "lo.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* BACNET_CHANNEL_VALUE decodes WriteProperty service requests
Choose the datatypes that your application supports */
#if !(defined(CHANNEL_NUMERIC) || \
defined(CHANNEL_NULL) || \
defined(CHANNEL_BOOLEAN) || \
defined(CHANNEL_UNSIGNED) || \
defined(CHANNEL_SIGNED) || \
defined(CHANNEL_REAL) || \
defined(CHANNEL_DOUBLE) || \
defined(CHANNEL_OCTET_STRING) || \
defined(CHANNEL_CHARACTER_STRING) || \
defined(CHANNEL_BIT_STRING) || \
defined(CHANNEL_ENUMERATED) || \
defined(CHANNEL_DATE) || \
defined(CHANNEL_TIME) || \
defined(CHANNEL_OBJECT_ID) || \
defined(CHANNEL_LIGHTING_COMMAND))
#define CHANNEL_NUMERIC
#endif
#if defined (CHANNEL_NUMERIC)
#define CHANNEL_NULL
#define CHANNEL_BOOLEAN
#define CHANNEL_UNSIGNED
#define CHANNEL_SIGNED
#define CHANNEL_REAL
#define CHANNEL_DOUBLE
#define CHANNEL_ENUMERATED
#define CHANNEL_LIGHTING_COMMAND
#endif
typedef struct BACnet_Channel_Value_t {
uint8_t tag;
union {
/* NULL - not needed as it is encoded in the tag alone */
#if defined (CHANNEL_BOOLEAN)
bool Boolean;
#endif
#if defined (CHANNEL_UNSIGNED)
uint32_t Unsigned_Int;
#endif
#if defined (CHANNEL_SIGNED)
int32_t Signed_Int;
#endif
#if defined (CHANNEL_REAL)
float Real;
#endif
#if defined (CHANNEL_DOUBLE)
double Double;
#endif
#if defined (CHANNEL_OCTET_STRING)
BACNET_OCTET_STRING Octet_String;
#endif
#if defined (CHANNEL_CHARACTER_STRING)
BACNET_CHARACTER_STRING Character_String;
#endif
#if defined (CHANNEL_BIT_STRING)
BACNET_BIT_STRING Bit_String;
#endif
#if defined (CHANNEL_ENUMERATED)
uint32_t Enumerated;
#endif
#if defined (CHANNEL_DATE)
BACNET_DATE Date;
#endif
#if defined (CHANNEL_TIME)
BACNET_TIME Time;
#endif
#if defined (CHANNEL_OBJECT_ID)
BACNET_OBJECT_ID Object_Id;
#endif
#if defined (CHANNEL_LIGHTING_COMMAND)
BACNET_LIGHTING_COMMAND Lighting_Command;
#endif
} type;
/* simple linked list if needed */
struct BACnet_Channel_Value_t *next;
} BACNET_CHANNEL_VALUE;
void Channel_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Channel_Valid_Instance(uint32_t object_instance);
unsigned Channel_Count(void);
uint32_t Channel_Index_To_Instance(unsigned index);
unsigned Channel_Instance_To_Index(uint32_t instance);
bool Channel_Object_Instance_Add(uint32_t instance);
bool Channel_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Channel_Name_Set(uint32_t object_instance,
char *new_name);
int Channel_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
bool Channel_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data);
BACNET_CHANNEL_VALUE * Channel_Present_Value(uint32_t object_instance);
bool Channel_Present_Value_Set(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_APPLICATION_DATA_VALUE * value);
bool Channel_Out_Of_Service(uint32_t object_instance);
void Channel_Out_Of_Service_Set(uint32_t object_instance,
bool oos_flag);
unsigned Channel_Last_Priority(uint32_t object_instance);
BACNET_WRITE_STATUS Channel_Write_Status(uint32_t object_instance);
uint16_t Channel_Number(uint32_t object_instance);
bool Channel_Number_Set(uint32_t object_instance, uint16_t value);
unsigned Channel_Reference_List_Member_Count(uint32_t object_instance);
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *
Channel_Reference_List_Member_Element(uint32_t object_instance,
unsigned element);
bool Channel_Reference_List_Member_Element_Set(uint32_t object_instance,
unsigned array_index,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMemberSrc);
unsigned Channel_Reference_List_Member_Element_Add(uint32_t object_instance,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMemberSrc);
unsigned Channel_Reference_List_Member_Local_Add(
uint32_t object_instance,
uint16_t type,
uint32_t instance,
BACNET_PROPERTY_ID propertyIdentifier,
uint32_t arrayIndex);
uint16_t Channel_Control_Groups_Element(
uint32_t object_instance,
int32_t array_index);
bool Channel_Control_Groups_Element_Set(
uint32_t object_instance,
int32_t array_index,
uint16_t value);
bool Channel_Value_Copy(BACNET_CHANNEL_VALUE * cvalue,
BACNET_APPLICATION_DATA_VALUE * value);
int Channel_Value_Encode(uint8_t *apdu, int apdu_max,
BACNET_CHANNEL_VALUE * value);
int Channel_Coerce_Data_Encode(
uint8_t * apdu,
unsigned max_apdu,
BACNET_APPLICATION_DATA_VALUE * value,
BACNET_APPLICATION_TAG tag);
bool Channel_Write_Member_Value(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_APPLICATION_DATA_VALUE * value);
void Channel_Init(void);
#ifdef TEST
#include "ctest.h"
void testChannelObject(Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**
* @file
* @author Steve Karg
* @date 2013
* @brief Channel objects, customize for your use
*
* @section DESCRIPTION
*
* The Channel object is a command object without a priority array, and the
* present-value property uses a priority array and a single precision floating point
* data type.
*
* @section LICENSE
*
* 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 CHANNEL_H
#define CHANNEL_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "rp.h"
#include "wp.h"
#include "lo.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* BACNET_CHANNEL_VALUE decodes WriteProperty service requests
Choose the datatypes that your application supports */
#if !(defined(CHANNEL_NUMERIC) || \
defined(CHANNEL_NULL) || \
defined(CHANNEL_BOOLEAN) || \
defined(CHANNEL_UNSIGNED) || \
defined(CHANNEL_SIGNED) || \
defined(CHANNEL_REAL) || \
defined(CHANNEL_DOUBLE) || \
defined(CHANNEL_OCTET_STRING) || \
defined(CHANNEL_CHARACTER_STRING) || \
defined(CHANNEL_BIT_STRING) || \
defined(CHANNEL_ENUMERATED) || \
defined(CHANNEL_DATE) || \
defined(CHANNEL_TIME) || \
defined(CHANNEL_OBJECT_ID) || \
defined(CHANNEL_LIGHTING_COMMAND))
#define CHANNEL_NUMERIC
#endif
#if defined (CHANNEL_NUMERIC)
#define CHANNEL_NULL
#define CHANNEL_BOOLEAN
#define CHANNEL_UNSIGNED
#define CHANNEL_SIGNED
#define CHANNEL_REAL
#define CHANNEL_DOUBLE
#define CHANNEL_ENUMERATED
#define CHANNEL_LIGHTING_COMMAND
#endif
typedef struct BACnet_Channel_Value_t {
uint8_t tag;
union {
/* NULL - not needed as it is encoded in the tag alone */
#if defined (CHANNEL_BOOLEAN)
bool Boolean;
#endif
#if defined (CHANNEL_UNSIGNED)
uint32_t Unsigned_Int;
#endif
#if defined (CHANNEL_SIGNED)
int32_t Signed_Int;
#endif
#if defined (CHANNEL_REAL)
float Real;
#endif
#if defined (CHANNEL_DOUBLE)
double Double;
#endif
#if defined (CHANNEL_OCTET_STRING)
BACNET_OCTET_STRING Octet_String;
#endif
#if defined (CHANNEL_CHARACTER_STRING)
BACNET_CHARACTER_STRING Character_String;
#endif
#if defined (CHANNEL_BIT_STRING)
BACNET_BIT_STRING Bit_String;
#endif
#if defined (CHANNEL_ENUMERATED)
uint32_t Enumerated;
#endif
#if defined (CHANNEL_DATE)
BACNET_DATE Date;
#endif
#if defined (CHANNEL_TIME)
BACNET_TIME Time;
#endif
#if defined (CHANNEL_OBJECT_ID)
BACNET_OBJECT_ID Object_Id;
#endif
#if defined (CHANNEL_LIGHTING_COMMAND)
BACNET_LIGHTING_COMMAND Lighting_Command;
#endif
} type;
/* simple linked list if needed */
struct BACnet_Channel_Value_t *next;
} BACNET_CHANNEL_VALUE;
void Channel_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Channel_Valid_Instance(uint32_t object_instance);
unsigned Channel_Count(void);
uint32_t Channel_Index_To_Instance(unsigned index);
unsigned Channel_Instance_To_Index(uint32_t instance);
bool Channel_Object_Instance_Add(uint32_t instance);
bool Channel_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Channel_Name_Set(uint32_t object_instance,
char *new_name);
int Channel_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
bool Channel_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data);
BACNET_CHANNEL_VALUE * Channel_Present_Value(uint32_t object_instance);
bool Channel_Present_Value_Set(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_APPLICATION_DATA_VALUE * value);
bool Channel_Out_Of_Service(uint32_t object_instance);
void Channel_Out_Of_Service_Set(uint32_t object_instance,
bool oos_flag);
unsigned Channel_Last_Priority(uint32_t object_instance);
BACNET_WRITE_STATUS Channel_Write_Status(uint32_t object_instance);
uint16_t Channel_Number(uint32_t object_instance);
bool Channel_Number_Set(uint32_t object_instance, uint16_t value);
unsigned Channel_Reference_List_Member_Count(uint32_t object_instance);
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *
Channel_Reference_List_Member_Element(uint32_t object_instance,
unsigned element);
bool Channel_Reference_List_Member_Element_Set(uint32_t object_instance,
unsigned array_index,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMemberSrc);
unsigned Channel_Reference_List_Member_Element_Add(uint32_t object_instance,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMemberSrc);
unsigned Channel_Reference_List_Member_Local_Add(
uint32_t object_instance,
uint16_t type,
uint32_t instance,
BACNET_PROPERTY_ID propertyIdentifier,
uint32_t arrayIndex);
uint16_t Channel_Control_Groups_Element(
uint32_t object_instance,
int32_t array_index);
bool Channel_Control_Groups_Element_Set(
uint32_t object_instance,
int32_t array_index,
uint16_t value);
bool Channel_Value_Copy(BACNET_CHANNEL_VALUE * cvalue,
BACNET_APPLICATION_DATA_VALUE * value);
int Channel_Value_Encode(uint8_t *apdu, int apdu_max,
BACNET_CHANNEL_VALUE * value);
int Channel_Coerce_Data_Encode(
uint8_t * apdu,
unsigned max_apdu,
BACNET_APPLICATION_DATA_VALUE * value,
BACNET_APPLICATION_TAG tag);
bool Channel_Write_Member_Value(
BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_APPLICATION_DATA_VALUE * value);
void Channel_Init(void);
#ifdef TEST
#include "ctest.h"
void testChannelObject(Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+462 -462
View File
@@ -1,462 +1,462 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Credential Data Input Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "credential_data_input.h"
#include "handlers.h"
static bool Credential_Data_Input_Initialized = false;
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[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_SUPPORTED_FORMATS,
PROP_UPDATE_TIME,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Credential_Data_Input_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Credential_Data_Input_Init(
void)
{
unsigned i;
if (!Credential_Data_Input_Initialized) {
Credential_Data_Input_Initialized = true;
for (i = 0; i < MAX_CREDENTIAL_DATA_INPUTS; i++) {
/* there should be a meaningful setup for present value */
cdi_descr[i].present_value.format_type =
AUTHENTICATION_FACTOR_UNDEFINED;
cdi_descr[i].present_value.format_class = 0;
octetstring_init(&cdi_descr[i].present_value.value, NULL, 0);
cdi_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
cdi_descr[i].out_of_service = false;
/* set supported formats */
cdi_descr[i].supported_formats_count = 0;
/* timestamp uninitialized */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Credential_Data_Input_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Credential_Data_Input_Count(
void)
{
return MAX_CREDENTIAL_DATA_INPUTS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Credential_Data_Input_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Credential_Data_Input_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_CREDENTIAL_DATA_INPUTS;
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Credential_Data_Input_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS) {
sprintf(text_string, "CREDENTIAL DATA INPUT %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
bool Credential_Data_Input_Out_Of_Service(
uint32_t instance)
{
unsigned index = 0;
bool oos_flag = false;
index = Credential_Data_Input_Instance_To_Index(instance);
if (index < MAX_CREDENTIAL_DATA_INPUTS) {
oos_flag = cdi_descr[index].out_of_service;
}
return oos_flag;
}
void Credential_Data_Input_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag)
{
unsigned index = 0;
index = Credential_Data_Input_Instance_To_Index(instance);
if (index < MAX_CREDENTIAL_DATA_INPUTS) {
cdi_descr[index].out_of_service = oos_flag;
}
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Credential_Data_Input_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index =
Credential_Data_Input_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_CREDENTIAL_DATA_INPUT, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Credential_Data_Input_Object_Name(rpdata->object_instance,
&char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
OBJECT_CREDENTIAL_DATA_INPUT);
break;
case PROP_PRESENT_VALUE:
apdu_len =
bacapp_encode_authentication_factor(&apdu[apdu_len],
&cdi_descr[object_index].present_value);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
state =
Credential_Data_Input_Out_Of_Service(rpdata->object_instance);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
cdi_descr[object_index].reliability);
break;
case PROP_OUT_OF_SERVICE:
state =
Credential_Data_Input_Out_Of_Service(rpdata->object_instance);
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_SUPPORTED_FORMATS:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
cdi_descr[object_index].supported_formats_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < cdi_descr[object_index].supported_formats_count;
i++) {
len =
bacapp_encode_authentication_factor_format(&apdu[0],
&cdi_descr[object_index].supported_formats[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
cdi_descr[object_index].supported_formats_count) {
apdu_len =
bacapp_encode_authentication_factor_format(&apdu[0],
&cdi_descr[object_index].
supported_formats[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_UPDATE_TIME:
apdu_len =
bacapp_encode_timestamp(&apdu[0],
&cdi_descr[object_index].timestamp);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_SUPPORTED_FORMATS)
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Credential_Data_Input_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->object_property != PROP_SUPPORTED_FORMATS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index = Credential_Data_Input_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if (Credential_Data_Input_Out_Of_Service(wp_data->object_instance)) {
BACNET_AUTHENTICATION_FACTOR tmp;
len =
bacapp_decode_authentication_factor(wp_data->
application_data, &tmp);
if (len > 0) {
memcpy(&cdi_descr[object_index].present_value, &tmp,
sizeof(BACNET_AUTHENTICATION_FACTOR));
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
}
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
break;
case PROP_RELIABILITY:
if (Credential_Data_Input_Out_Of_Service(wp_data->object_instance)) {
status =
WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
&wp_data->error_code);
if (status) {
cdi_descr[object_index].reliability =
value.type.Enumerated;
}
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_OUT_OF_SERVICE:
case PROP_SUPPORTED_FORMATS:
case PROP_UPDATE_TIME:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testCredentialDataInput(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Credential_Data_Input_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_CREDENTIAL_DATA_INPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Credential_Data_Input_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_CREDENTIAL_DATA_INPUT
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Credential Data Input", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testCredentialDataInput);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_CREDENTIAL_DATA_INPUT */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Credential Data Input Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "credential_data_input.h"
#include "handlers.h"
static bool Credential_Data_Input_Initialized = false;
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[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_SUPPORTED_FORMATS,
PROP_UPDATE_TIME,
-1
};
static const int Properties_Optional[] = {
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Credential_Data_Input_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Properties_Required;
if (pOptional)
*pOptional = Properties_Optional;
if (pProprietary)
*pProprietary = Properties_Proprietary;
return;
}
void Credential_Data_Input_Init(
void)
{
unsigned i;
if (!Credential_Data_Input_Initialized) {
Credential_Data_Input_Initialized = true;
for (i = 0; i < MAX_CREDENTIAL_DATA_INPUTS; i++) {
/* there should be a meaningful setup for present value */
cdi_descr[i].present_value.format_type =
AUTHENTICATION_FACTOR_UNDEFINED;
cdi_descr[i].present_value.format_class = 0;
octetstring_init(&cdi_descr[i].present_value.value, NULL, 0);
cdi_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
cdi_descr[i].out_of_service = false;
/* set supported formats */
cdi_descr[i].supported_formats_count = 0;
/* timestamp uninitialized */
}
}
return;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Credential_Data_Input_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Credential_Data_Input_Count(
void)
{
return MAX_CREDENTIAL_DATA_INPUTS;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Credential_Data_Input_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Credential_Data_Input_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_CREDENTIAL_DATA_INPUTS;
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
index = object_instance;
return index;
}
/* note: the object name must be unique within this device */
bool Credential_Data_Input_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS) {
sprintf(text_string, "CREDENTIAL DATA INPUT %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
bool Credential_Data_Input_Out_Of_Service(
uint32_t instance)
{
unsigned index = 0;
bool oos_flag = false;
index = Credential_Data_Input_Instance_To_Index(instance);
if (index < MAX_CREDENTIAL_DATA_INPUTS) {
oos_flag = cdi_descr[index].out_of_service;
}
return oos_flag;
}
void Credential_Data_Input_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag)
{
unsigned index = 0;
index = Credential_Data_Input_Instance_To_Index(instance);
if (index < MAX_CREDENTIAL_DATA_INPUTS) {
cdi_descr[index].out_of_service = oos_flag;
}
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Credential_Data_Input_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index =
Credential_Data_Input_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_CREDENTIAL_DATA_INPUT, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Credential_Data_Input_Object_Name(rpdata->object_instance,
&char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
OBJECT_CREDENTIAL_DATA_INPUT);
break;
case PROP_PRESENT_VALUE:
apdu_len =
bacapp_encode_authentication_factor(&apdu[apdu_len],
&cdi_descr[object_index].present_value);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
state =
Credential_Data_Input_Out_Of_Service(rpdata->object_instance);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
cdi_descr[object_index].reliability);
break;
case PROP_OUT_OF_SERVICE:
state =
Credential_Data_Input_Out_Of_Service(rpdata->object_instance);
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_SUPPORTED_FORMATS:
if (rpdata->array_index == 0) {
apdu_len =
encode_application_unsigned(&apdu[0],
cdi_descr[object_index].supported_formats_count);
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < cdi_descr[object_index].supported_formats_count;
i++) {
len =
bacapp_encode_authentication_factor_format(&apdu[0],
&cdi_descr[object_index].supported_formats[i]);
if (apdu_len + len < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
if (rpdata->array_index <=
cdi_descr[object_index].supported_formats_count) {
apdu_len =
bacapp_encode_authentication_factor_format(&apdu[0],
&cdi_descr[object_index].
supported_formats[rpdata->array_index - 1]);
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_UPDATE_TIME:
apdu_len =
bacapp_encode_timestamp(&apdu[0],
&cdi_descr[object_index].timestamp);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_SUPPORTED_FORMATS)
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool Credential_Data_Input_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
unsigned object_index = 0;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
/* only array properties can have array options */
if ((wp_data->object_property != PROP_SUPPORTED_FORMATS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index = Credential_Data_Input_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if (Credential_Data_Input_Out_Of_Service(wp_data->object_instance)) {
BACNET_AUTHENTICATION_FACTOR tmp;
len =
bacapp_decode_authentication_factor(wp_data->
application_data, &tmp);
if (len > 0) {
memcpy(&cdi_descr[object_index].present_value, &tmp,
sizeof(BACNET_AUTHENTICATION_FACTOR));
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
}
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
break;
case PROP_RELIABILITY:
if (Credential_Data_Input_Out_Of_Service(wp_data->object_instance)) {
status =
WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
&wp_data->error_code);
if (status) {
cdi_descr[object_index].reliability =
value.type.Enumerated;
}
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_OUT_OF_SERVICE:
case PROP_SUPPORTED_FORMATS:
case PROP_UPDATE_TIME:
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;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(
BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testCredentialDataInput(
Test * pTest)
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint32_t decoded_instance = 0;
uint16_t decoded_type = 0;
BACNET_READ_PROPERTY_DATA rpdata;
Credential_Data_Input_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_CREDENTIAL_DATA_INPUT;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Credential_Data_Input_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_CREDENTIAL_DATA_INPUT
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Credential Data Input", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testCredentialDataInput);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_CREDENTIAL_DATA_INPUT */
#endif /* TEST */
+116 -116
View File
@@ -1,116 +1,116 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 CREDENTIAL_DATA_INPUT_H
#define CREDENTIAL_DATA_INPUT_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "timestamp.h"
#include "bacdevobjpropref.h"
#include "authentication_factor.h"
#include "authentication_factor_format.h"
#include "timestamp.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_CREDENTIAL_DATA_INPUTS
#define MAX_CREDENTIAL_DATA_INPUTS 4
#endif
#ifndef MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT
#define MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
BACNET_AUTHENTICATION_FACTOR present_value;
BACNET_RELIABILITY reliability;
bool out_of_service;
uint32_t supported_formats_count;
BACNET_AUTHENTICATION_FACTOR_FORMAT
supported_formats[MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT];
BACNET_TIMESTAMP timestamp;
} CREDENTIAL_DATA_INPUT_DESCR;
void Credential_Data_Input_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Credential_Data_Input_Valid_Instance(
uint32_t object_instance);
unsigned Credential_Data_Input_Count(
void);
uint32_t Credential_Data_Input_Index_To_Instance(
unsigned index);
unsigned Credential_Data_Input_Instance_To_Index(
uint32_t instance);
bool Credential_Data_Input_Object_Instance_Add(
uint32_t instance);
bool Credential_Data_Input_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Credential_Data_Input_Name_Set(
uint32_t object_instance,
char *new_name);
bool Credential_Data_Input_Out_Of_Service(
uint32_t instance);
void Credential_Data_Input_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
int Credential_Data_Input_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Credential_Data_Input_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Credential_Data_Input_Create(
uint32_t object_instance);
bool Credential_Data_Input_Delete(
uint32_t object_instance);
void Credential_Data_Input_Cleanup(
void);
void Credential_Data_Input_Init(
void);
#ifdef TEST
#include "ctest.h"
void testCredentialDataInput(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 CREDENTIAL_DATA_INPUT_H
#define CREDENTIAL_DATA_INPUT_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "timestamp.h"
#include "bacdevobjpropref.h"
#include "authentication_factor.h"
#include "authentication_factor_format.h"
#include "timestamp.h"
#include "rp.h"
#include "wp.h"
#ifndef MAX_CREDENTIAL_DATA_INPUTS
#define MAX_CREDENTIAL_DATA_INPUTS 4
#endif
#ifndef MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT
#define MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT 4
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
BACNET_AUTHENTICATION_FACTOR present_value;
BACNET_RELIABILITY reliability;
bool out_of_service;
uint32_t supported_formats_count;
BACNET_AUTHENTICATION_FACTOR_FORMAT
supported_formats[MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT];
BACNET_TIMESTAMP timestamp;
} CREDENTIAL_DATA_INPUT_DESCR;
void Credential_Data_Input_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Credential_Data_Input_Valid_Instance(
uint32_t object_instance);
unsigned Credential_Data_Input_Count(
void);
uint32_t Credential_Data_Input_Index_To_Instance(
unsigned index);
unsigned Credential_Data_Input_Instance_To_Index(
uint32_t instance);
bool Credential_Data_Input_Object_Instance_Add(
uint32_t instance);
bool Credential_Data_Input_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
bool Credential_Data_Input_Name_Set(
uint32_t object_instance,
char *new_name);
bool Credential_Data_Input_Out_Of_Service(
uint32_t instance);
void Credential_Data_Input_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag);
int Credential_Data_Input_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Credential_Data_Input_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data);
bool Credential_Data_Input_Create(
uint32_t object_instance);
bool Credential_Data_Input_Delete(
uint32_t object_instance);
void Credential_Data_Input_Cleanup(
void);
void Credential_Data_Input_Init(
void);
#ifdef TEST
#include "ctest.h"
void testCredentialDataInput(
Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
@@ -1,45 +1,45 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_CREDENTIAL_DATA_INPUT
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = credential_data_input.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(SRC_DIR)/authentication_factor.c \
$(SRC_DIR)/authentication_factor_format.c \
$(SRC_DIR)/timestamp.c \
$(TEST_DIR)/ctest.c
TARGET = credential_data_input
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_CREDENTIAL_DATA_INPUT
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = credential_data_input.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(SRC_DIR)/authentication_factor.c \
$(SRC_DIR)/authentication_factor_format.c \
$(SRC_DIR)/timestamp.c \
$(TEST_DIR)/ctest.c
TARGET = credential_data_input
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
+438 -438
View File
@@ -1,438 +1,438 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* OctetString Value Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "bactext.h"
#include "config.h" /* the custom stuff */
#include "device.h"
#include "handlers.h"
#include "osv.h"
#ifndef MAX_OCTETSTRING_VALUES
#define MAX_OCTETSTRING_VALUES 4
#endif
OCTETSTRING_VALUE_DESCR AV_Descr[MAX_OCTETSTRING_VALUES];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int OctetString_Value_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
-1
};
static const int OctetString_Value_Properties_Optional[] = {
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_DESCRIPTION,
-1
};
static const int OctetString_Value_Properties_Proprietary[] = {
-1
};
void OctetString_Value_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = OctetString_Value_Properties_Required;
if (pOptional)
*pOptional = OctetString_Value_Properties_Optional;
if (pProprietary)
*pProprietary = OctetString_Value_Properties_Proprietary;
return;
}
void OctetString_Value_Init(void)
{
unsigned i;
for (i = 0; i < MAX_OCTETSTRING_VALUES; i++) {
memset(&AV_Descr[i], 0x00, sizeof(OCTETSTRING_VALUE_DESCR));
octetstring_init(&AV_Descr[i].Present_Value, NULL, 0);
}
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool OctetString_Value_Valid_Instance(uint32_t object_instance)
{
if (object_instance < MAX_OCTETSTRING_VALUES)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned OctetString_Value_Count(void)
{
return MAX_OCTETSTRING_VALUES;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t OctetString_Value_Index_To_Instance(unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance)
{
unsigned index = MAX_OCTETSTRING_VALUES;
if (object_instance < MAX_OCTETSTRING_VALUES)
index = object_instance;
return index;
}
/**
* For a given object instance-number, sets the present-value at a given
* priority 1..16.
*
* @param object_instance - object-instance number of the object
* @param value - octetstring value
* @param priority - priority 1..16
*
* @return true if values are within range and present-value is set.
*/
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
BACNET_OCTET_STRING * value,
uint8_t priority)
{
unsigned index = 0;
bool status = false;
index = OctetString_Value_Instance_To_Index(object_instance);
if (index < MAX_OCTETSTRING_VALUES) {
octetstring_copy(&AV_Descr[index].Present_Value, value);
status = true;
}
return status;
}
BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t object_instance)
{
BACNET_OCTET_STRING *value = NULL;
unsigned index = 0;
index = OctetString_Value_Instance_To_Index(object_instance);
if (index < MAX_OCTETSTRING_VALUES) {
value = &AV_Descr[index].Present_Value;
}
return value;
}
/* note: the object name must be unique within this device */
bool OctetString_Value_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_OCTETSTRING_VALUES) {
sprintf(text_string, "OCTETSTRING VALUE %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
BACNET_OCTET_STRING *real_value = NULL;
unsigned object_index = 0;
bool state = false;
uint8_t *apdu = NULL;
OCTETSTRING_VALUE_DESCR *CurrentAV;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index =
OctetString_Value_Instance_To_Index(rpdata->object_instance);
if (object_index < MAX_OCTETSTRING_VALUES)
CurrentAV = &AV_Descr[object_index];
else
return BACNET_STATUS_ERROR;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_OCTETSTRING_VALUE, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
OctetString_Value_Object_Name(rpdata->object_instance,
&char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
OBJECT_OCTETSTRING_VALUE);
break;
case PROP_PRESENT_VALUE:
real_value =
OctetString_Value_Present_Value(rpdata->object_instance);
apdu_len = encode_application_octet_string(&apdu[0], real_value);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
CurrentAV->Out_Of_Service);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
apdu_len =
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
state = CurrentAV->Out_Of_Service;
apdu_len = encode_application_boolean(&apdu[0], state);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
OCTETSTRING_VALUE_DESCR *CurrentAV;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
/* only array properties can have array options */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index =
OctetString_Value_Instance_To_Index(wp_data->object_instance);
if (object_index < MAX_OCTETSTRING_VALUES)
CurrentAV = &AV_Descr[object_index];
else
return false;
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if (value.tag == BACNET_APPLICATION_TAG_OCTET_STRING) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
if (OctetString_Value_Present_Value_Set(wp_data->
object_instance, &value.type.Octet_String,
wp_data->priority)) {
status = true;
} else if (wp_data->priority == 6) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
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_VALUE_OUT_OF_RANGE;
}
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
break;
case PROP_OUT_OF_SERVICE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAV->Out_Of_Service = value.type.Boolean;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_DESCRIPTION:
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;
break;
}
return status;
}
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance)
{
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testOctetString_Value(Test * pTest)
{
BACNET_READ_PROPERTY_DATA rpdata;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
OctetString_Value_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_OCTETSTRING_VALUE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = OctetString_Value_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_OCTETSTRING_VALUE
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet OctetString Value", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testOctetString_Value);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_OCTETSTRING_VALUE */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* OctetString Value Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "bactext.h"
#include "config.h" /* the custom stuff */
#include "device.h"
#include "handlers.h"
#include "osv.h"
#ifndef MAX_OCTETSTRING_VALUES
#define MAX_OCTETSTRING_VALUES 4
#endif
OCTETSTRING_VALUE_DESCR AV_Descr[MAX_OCTETSTRING_VALUES];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int OctetString_Value_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
-1
};
static const int OctetString_Value_Properties_Optional[] = {
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_DESCRIPTION,
-1
};
static const int OctetString_Value_Properties_Proprietary[] = {
-1
};
void OctetString_Value_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = OctetString_Value_Properties_Required;
if (pOptional)
*pOptional = OctetString_Value_Properties_Optional;
if (pProprietary)
*pProprietary = OctetString_Value_Properties_Proprietary;
return;
}
void OctetString_Value_Init(void)
{
unsigned i;
for (i = 0; i < MAX_OCTETSTRING_VALUES; i++) {
memset(&AV_Descr[i], 0x00, sizeof(OCTETSTRING_VALUE_DESCR));
octetstring_init(&AV_Descr[i].Present_Value, NULL, 0);
}
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool OctetString_Value_Valid_Instance(uint32_t object_instance)
{
if (object_instance < MAX_OCTETSTRING_VALUES)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned OctetString_Value_Count(void)
{
return MAX_OCTETSTRING_VALUES;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t OctetString_Value_Index_To_Instance(unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance)
{
unsigned index = MAX_OCTETSTRING_VALUES;
if (object_instance < MAX_OCTETSTRING_VALUES)
index = object_instance;
return index;
}
/**
* For a given object instance-number, sets the present-value at a given
* priority 1..16.
*
* @param object_instance - object-instance number of the object
* @param value - octetstring value
* @param priority - priority 1..16
*
* @return true if values are within range and present-value is set.
*/
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
BACNET_OCTET_STRING * value,
uint8_t priority)
{
unsigned index = 0;
bool status = false;
index = OctetString_Value_Instance_To_Index(object_instance);
if (index < MAX_OCTETSTRING_VALUES) {
octetstring_copy(&AV_Descr[index].Present_Value, value);
status = true;
}
return status;
}
BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t object_instance)
{
BACNET_OCTET_STRING *value = NULL;
unsigned index = 0;
index = OctetString_Value_Instance_To_Index(object_instance);
if (index < MAX_OCTETSTRING_VALUES) {
value = &AV_Descr[index].Present_Value;
}
return value;
}
/* note: the object name must be unique within this device */
bool OctetString_Value_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_OCTETSTRING_VALUES) {
sprintf(text_string, "OCTETSTRING VALUE %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
BACNET_OCTET_STRING *real_value = NULL;
unsigned object_index = 0;
bool state = false;
uint8_t *apdu = NULL;
OCTETSTRING_VALUE_DESCR *CurrentAV;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index =
OctetString_Value_Instance_To_Index(rpdata->object_instance);
if (object_index < MAX_OCTETSTRING_VALUES)
CurrentAV = &AV_Descr[object_index];
else
return BACNET_STATUS_ERROR;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_OCTETSTRING_VALUE, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
OctetString_Value_Object_Name(rpdata->object_instance,
&char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
OBJECT_OCTETSTRING_VALUE);
break;
case PROP_PRESENT_VALUE:
real_value =
OctetString_Value_Present_Value(rpdata->object_instance);
apdu_len = encode_application_octet_string(&apdu[0], real_value);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
CurrentAV->Out_Of_Service);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
apdu_len =
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
break;
case PROP_OUT_OF_SERVICE:
state = CurrentAV->Out_Of_Service;
apdu_len = encode_application_boolean(&apdu[0], state);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
OCTETSTRING_VALUE_DESCR *CurrentAV;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
/* only array properties can have array options */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index =
OctetString_Value_Instance_To_Index(wp_data->object_instance);
if (object_index < MAX_OCTETSTRING_VALUES)
CurrentAV = &AV_Descr[object_index];
else
return false;
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if (value.tag == BACNET_APPLICATION_TAG_OCTET_STRING) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
if (OctetString_Value_Present_Value_Set(wp_data->
object_instance, &value.type.Octet_String,
wp_data->priority)) {
status = true;
} else if (wp_data->priority == 6) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
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_VALUE_OUT_OF_RANGE;
}
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
break;
case PROP_OUT_OF_SERVICE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAV->Out_Of_Service = value.type.Boolean;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_DESCRIPTION:
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;
break;
}
return status;
}
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance)
{
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testOctetString_Value(Test * pTest)
{
BACNET_READ_PROPERTY_DATA rpdata;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
OctetString_Value_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_OCTETSTRING_VALUE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = OctetString_Value_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_OCTETSTRING_VALUE
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet OctetString Value", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testOctetString_Value);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_OCTETSTRING_VALUE */
#endif /* TEST */
+95 -95
View File
@@ -1,95 +1,95 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 OSV_H
#define OSV_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "wp.h"
#include "rp.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct octetstring_value_descr {
unsigned Event_State:3;
bool Out_Of_Service;
BACNET_OCTET_STRING Present_Value;
} OCTETSTRING_VALUE_DESCR;
void OctetString_Value_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool OctetString_Value_Valid_Instance(uint32_t object_instance);
unsigned OctetString_Value_Count(void);
uint32_t OctetString_Value_Index_To_Instance(unsigned index);
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance);
bool OctetString_Value_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *
wp_data);
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
BACNET_OCTET_STRING * value,
uint8_t priority);
BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t
object_instance);
bool OctetString_Value_Change_Of_Value(uint32_t instance);
void OctetString_Value_Change_Of_Value_Clear(uint32_t instance);
bool OctetString_Value_Encode_Value_List(uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
char *OctetString_Value_Description(uint32_t instance);
bool OctetString_Value_Description_Set(uint32_t instance,
char *new_name);
bool OctetString_Value_Out_Of_Service(uint32_t instance);
void OctetString_Value_Out_Of_Service_Set(uint32_t instance,
bool oos_flag);
/* note: header of Intrinsic_Reporting function is required
even when INTRINSIC_REPORTING is not defined */
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance);
void OctetString_Value_Init(void);
#ifdef TEST
#include "ctest.h"
void testOctetString_Value(Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 OSV_H
#define OSV_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "wp.h"
#include "rp.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct octetstring_value_descr {
unsigned Event_State:3;
bool Out_Of_Service;
BACNET_OCTET_STRING Present_Value;
} OCTETSTRING_VALUE_DESCR;
void OctetString_Value_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool OctetString_Value_Valid_Instance(uint32_t object_instance);
unsigned OctetString_Value_Count(void);
uint32_t OctetString_Value_Index_To_Instance(unsigned index);
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance);
bool OctetString_Value_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *
wp_data);
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
BACNET_OCTET_STRING * value,
uint8_t priority);
BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t
object_instance);
bool OctetString_Value_Change_Of_Value(uint32_t instance);
void OctetString_Value_Change_Of_Value_Clear(uint32_t instance);
bool OctetString_Value_Encode_Value_List(uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
char *OctetString_Value_Description(uint32_t instance);
bool OctetString_Value_Description_Set(uint32_t instance,
char *new_name);
bool OctetString_Value_Out_Of_Service(uint32_t instance);
void OctetString_Value_Out_Of_Service_Set(uint32_t instance,
bool oos_flag);
/* note: header of Intrinsic_Reporting function is required
even when INTRINSIC_REPORTING is not defined */
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance);
void OctetString_Value_Init(void);
#ifdef TEST
#include "ctest.h"
void testOctetString_Value(Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+43 -43
View File
@@ -1,43 +1,43 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DBACNET_PROPERTY_LISTS -DTEST_OCTETSTRING_VALUE
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = osv.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/proplist.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = octetstring_value
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DBACNET_PROPERTY_LISTS -DTEST_OCTETSTRING_VALUE
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = osv.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/proplist.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = octetstring_value
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
+442 -442
View File
@@ -1,442 +1,442 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Positiveinteger Value Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "bactext.h"
#include "config.h" /* the custom stuff */
#include "device.h"
#include "handlers.h"
#include "piv.h"
#ifndef MAX_POSITIVEINTEGER_VALUES
#define MAX_POSITIVEINTEGER_VALUES 4
#endif
POSITIVEINTEGER_VALUE_DESCR PIV_Descr[MAX_POSITIVEINTEGER_VALUES];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int PositiveInteger_Value_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_UNITS,
- 1
};
static const int PositiveInteger_Value_Properties_Optional[] = {
PROP_OUT_OF_SERVICE,
-1
};
static const int PositiveInteger_Value_Properties_Proprietary[] = {
-1
};
void PositiveInteger_Value_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = PositiveInteger_Value_Properties_Required;
if (pOptional)
*pOptional = PositiveInteger_Value_Properties_Optional;
if (pProprietary)
*pProprietary = PositiveInteger_Value_Properties_Proprietary;
return;
}
void PositiveInteger_Value_Init(void)
{
unsigned i;
for (i = 0; i < MAX_POSITIVEINTEGER_VALUES; i++) {
memset(&PIV_Descr[i], 0x00, sizeof(POSITIVEINTEGER_VALUE_DESCR));
}
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance)
{
if (object_instance < MAX_POSITIVEINTEGER_VALUES)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned PositiveInteger_Value_Count(void)
{
return MAX_POSITIVEINTEGER_VALUES;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance)
{
unsigned index = MAX_POSITIVEINTEGER_VALUES;
if (object_instance < MAX_POSITIVEINTEGER_VALUES)
index = object_instance;
return index;
}
/**
* For a given object instance-number, sets the present-value at a given
* priority 1..16.
*
* @param object_instance - object-instance number of the object
* @param value - positiveinteger value
* @param priority - priority 1..16
*
* @return true if values are within range and present-value is set.
*/
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
uint32_t value,
uint8_t priority)
{
unsigned index = 0;
bool status = false;
index = PositiveInteger_Value_Instance_To_Index(object_instance);
if (index < MAX_POSITIVEINTEGER_VALUES) {
PIV_Descr[index].Present_Value = value;
status = true;
}
return status;
}
uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance)
{
uint32_t value = 0;
unsigned index = 0;
index = PositiveInteger_Value_Instance_To_Index(object_instance);
if (index < MAX_POSITIVEINTEGER_VALUES) {
value = PIV_Descr[index].Present_Value;
}
return value;
}
/* note: the object name must be unique within this device */
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_POSITIVEINTEGER_VALUES) {
sprintf(text_string, "POSITIVEINTEGER VALUE %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
bool state = false;
uint8_t *apdu = NULL;
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index =
PositiveInteger_Value_Instance_To_Index(rpdata->object_instance);
if (object_index < MAX_POSITIVEINTEGER_VALUES)
CurrentAV = &PIV_Descr[object_index];
else
return BACNET_STATUS_ERROR;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_POSITIVE_INTEGER_VALUE, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
PositiveInteger_Value_Object_Name(rpdata->object_instance,
&char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
OBJECT_POSITIVE_INTEGER_VALUE);
break;
case PROP_PRESENT_VALUE:
apdu_len =
encode_application_unsigned(&apdu[0],
PositiveInteger_Value_Present_Value(rpdata->object_instance));
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
CurrentAV->Out_Of_Service);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_UNITS:
apdu_len =
encode_application_enumerated(&apdu[0], CurrentAV->Units);
break;
/* BACnet Testing Observed Incident oi00109
Positive Integer Value / Units returned wrong datatype - missing break.
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00031
BC 135.1: 9.20.1.7
BC 135.1: 9.20.1.9
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes have been reviewed
by all interested parties. Say 6 months -> September 2016 */
case PROP_OUT_OF_SERVICE:
state = CurrentAV->Out_Of_Service;
apdu_len = encode_application_boolean(&apdu[0], state);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
/* only array properties can have array options */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index =
PositiveInteger_Value_Instance_To_Index(wp_data->object_instance);
if (object_index < MAX_POSITIVEINTEGER_VALUES)
CurrentAV = &PIV_Descr[object_index];
else
return false;
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
if (PositiveInteger_Value_Present_Value_Set(wp_data->
object_instance, value.type.Unsigned_Int,
wp_data->priority)) {
status = true;
} else if (wp_data->priority == 6) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
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_VALUE_OUT_OF_RANGE;
}
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
break;
case PROP_OUT_OF_SERVICE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAV->Out_Of_Service = value.type.Boolean;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_UNITS:
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;
break;
}
return status;
}
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance)
{
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testPositiveInteger_Value(Test * pTest)
{
BACNET_READ_PROPERTY_DATA rpdata;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
PositiveInteger_Value_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_POSITIVE_INTEGER_VALUE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = PositiveInteger_Value_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_POSITIVEINTEGER_VALUE
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet PositiveInteger Value", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testPositiveInteger_Value);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_POSITIVEINTEGER_VALUE */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
/* Positiveinteger Value Objects - customize for your use */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "bactext.h"
#include "config.h" /* the custom stuff */
#include "device.h"
#include "handlers.h"
#include "piv.h"
#ifndef MAX_POSITIVEINTEGER_VALUES
#define MAX_POSITIVEINTEGER_VALUES 4
#endif
POSITIVEINTEGER_VALUE_DESCR PIV_Descr[MAX_POSITIVEINTEGER_VALUES];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int PositiveInteger_Value_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_UNITS,
- 1
};
static const int PositiveInteger_Value_Properties_Optional[] = {
PROP_OUT_OF_SERVICE,
-1
};
static const int PositiveInteger_Value_Properties_Proprietary[] = {
-1
};
void PositiveInteger_Value_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = PositiveInteger_Value_Properties_Required;
if (pOptional)
*pOptional = PositiveInteger_Value_Properties_Optional;
if (pProprietary)
*pProprietary = PositiveInteger_Value_Properties_Proprietary;
return;
}
void PositiveInteger_Value_Init(void)
{
unsigned i;
for (i = 0; i < MAX_POSITIVEINTEGER_VALUES; i++) {
memset(&PIV_Descr[i], 0x00, sizeof(POSITIVEINTEGER_VALUE_DESCR));
}
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance)
{
if (object_instance < MAX_POSITIVEINTEGER_VALUES)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned PositiveInteger_Value_Count(void)
{
return MAX_POSITIVEINTEGER_VALUES;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance)
{
unsigned index = MAX_POSITIVEINTEGER_VALUES;
if (object_instance < MAX_POSITIVEINTEGER_VALUES)
index = object_instance;
return index;
}
/**
* For a given object instance-number, sets the present-value at a given
* priority 1..16.
*
* @param object_instance - object-instance number of the object
* @param value - positiveinteger value
* @param priority - priority 1..16
*
* @return true if values are within range and present-value is set.
*/
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
uint32_t value,
uint8_t priority)
{
unsigned index = 0;
bool status = false;
index = PositiveInteger_Value_Instance_To_Index(object_instance);
if (index < MAX_POSITIVEINTEGER_VALUES) {
PIV_Descr[index].Present_Value = value;
status = true;
}
return status;
}
uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance)
{
uint32_t value = 0;
unsigned index = 0;
index = PositiveInteger_Value_Instance_To_Index(object_instance);
if (index < MAX_POSITIVEINTEGER_VALUES) {
value = PIV_Descr[index].Present_Value;
}
return value;
}
/* note: the object name must be unique within this device */
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_POSITIVEINTEGER_VALUES) {
sprintf(text_string, "POSITIVEINTEGER VALUE %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
unsigned object_index = 0;
bool state = false;
uint8_t *apdu = NULL;
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
object_index =
PositiveInteger_Value_Instance_To_Index(rpdata->object_instance);
if (object_index < MAX_POSITIVEINTEGER_VALUES)
CurrentAV = &PIV_Descr[object_index];
else
return BACNET_STATUS_ERROR;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0],
OBJECT_POSITIVE_INTEGER_VALUE, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
PositiveInteger_Value_Object_Name(rpdata->object_instance,
&char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0],
OBJECT_POSITIVE_INTEGER_VALUE);
break;
case PROP_PRESENT_VALUE:
apdu_len =
encode_application_unsigned(&apdu[0],
PositiveInteger_Value_Present_Value(rpdata->object_instance));
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
CurrentAV->Out_Of_Service);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_UNITS:
apdu_len =
encode_application_enumerated(&apdu[0], CurrentAV->Units);
break;
/* BACnet Testing Observed Incident oi00109
Positive Integer Value / Units returned wrong datatype - missing break.
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00031
BC 135.1: 9.20.1.7
BC 135.1: 9.20.1.9
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes have been reviewed
by all interested parties. Say 6 months -> September 2016 */
case PROP_OUT_OF_SERVICE:
state = CurrentAV->Out_Of_Service;
apdu_len = encode_application_boolean(&apdu[0], state);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/* returns true if successful */
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
/* only array properties can have array options */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
object_index =
PositiveInteger_Value_Instance_To_Index(wp_data->object_instance);
if (object_index < MAX_POSITIVEINTEGER_VALUES)
CurrentAV = &PIV_Descr[object_index];
else
return false;
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
if (PositiveInteger_Value_Present_Value_Set(wp_data->
object_instance, value.type.Unsigned_Int,
wp_data->priority)) {
status = true;
} else if (wp_data->priority == 6) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
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_VALUE_OUT_OF_RANGE;
}
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
break;
case PROP_OUT_OF_SERVICE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAV->Out_Of_Service = value.type.Boolean;
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_UNITS:
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;
break;
}
return status;
}
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance)
{
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
uint8_t ucExpectedTag,
BACNET_ERROR_CLASS * pErrorClass,
BACNET_ERROR_CODE * pErrorCode)
{
pValue = pValue;
ucExpectedTag = ucExpectedTag;
pErrorClass = pErrorClass;
pErrorCode = pErrorCode;
return false;
}
void testPositiveInteger_Value(Test * pTest)
{
BACNET_READ_PROPERTY_DATA rpdata;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
PositiveInteger_Value_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_POSITIVE_INTEGER_VALUE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = PositiveInteger_Value_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_POSITIVEINTEGER_VALUE
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet PositiveInteger Value", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testPositiveInteger_Value);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_POSITIVEINTEGER_VALUE */
#endif /* TEST */
+95 -95
View File
@@ -1,95 +1,95 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 PIV_H
#define PIV_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "wp.h"
#include "rp.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct positiveinteger_value_descr {
bool Out_Of_Service:1;
uint32_t Present_Value;
uint16_t Units;
} POSITIVEINTEGER_VALUE_DESCR;
void PositiveInteger_Value_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance);
unsigned PositiveInteger_Value_Count(void);
uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index);
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance);
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *
rpdata);
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *
wp_data);
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
uint32_t value,
uint8_t priority);
uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance);
bool PositiveInteger_Value_Change_Of_Value(uint32_t instance);
void PositiveInteger_Value_Change_Of_Value_Clear(uint32_t instance);
bool PositiveInteger_Value_Encode_Value_List(uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
char *PositiveInteger_Value_Description(uint32_t instance);
bool PositiveInteger_Value_Description_Set(uint32_t instance,
char *new_name);
bool PositiveInteger_Value_Out_Of_Service(uint32_t instance);
void PositiveInteger_Value_Out_Of_Service_Set(uint32_t instance,
bool oos_flag);
/* note: header of Intrinsic_Reporting function is required
even when INTRINSIC_REPORTING is not defined */
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance);
void PositiveInteger_Value_Init(void);
#ifdef TEST
#include "ctest.h"
void testPositiveInteger_Value(Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 PIV_H
#define PIV_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacerror.h"
#include "wp.h"
#include "rp.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct positiveinteger_value_descr {
bool Out_Of_Service:1;
uint32_t Present_Value;
uint16_t Units;
} POSITIVEINTEGER_VALUE_DESCR;
void PositiveInteger_Value_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance);
unsigned PositiveInteger_Value_Count(void);
uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index);
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance);
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *
rpdata);
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *
wp_data);
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
uint32_t value,
uint8_t priority);
uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance);
bool PositiveInteger_Value_Change_Of_Value(uint32_t instance);
void PositiveInteger_Value_Change_Of_Value_Clear(uint32_t instance);
bool PositiveInteger_Value_Encode_Value_List(uint32_t object_instance,
BACNET_PROPERTY_VALUE * value_list);
char *PositiveInteger_Value_Description(uint32_t instance);
bool PositiveInteger_Value_Description_Set(uint32_t instance,
char *new_name);
bool PositiveInteger_Value_Out_Of_Service(uint32_t instance);
void PositiveInteger_Value_Out_Of_Service_Set(uint32_t instance,
bool oos_flag);
/* note: header of Intrinsic_Reporting function is required
even when INTRINSIC_REPORTING is not defined */
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance);
void PositiveInteger_Value_Init(void);
#ifdef TEST
#include "ctest.h"
void testPositiveInteger_Value(Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+42 -42
View File
@@ -1,42 +1,42 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_POSITIVEINTEGER_VALUE
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = piv.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = positiveinteger_value
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_POSITIVEINTEGER_VALUE
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = piv.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = positiveinteger_value
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
+492 -492
View File
@@ -1,492 +1,492 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bactext.h"
#include "config.h"
#include "device.h"
#include "handlers.h"
#include "proplist.h"
#include "timestamp.h"
#include "schedule.h"
#ifndef MAX_SCHEDULES
#define MAX_SCHEDULES 4
#endif
SCHEDULE_DESCR Schedule_Descr[MAX_SCHEDULES];
static const int Schedule_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_EFFECTIVE_PERIOD,
PROP_SCHEDULE_DEFAULT,
PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES,
PROP_PRIORITY_FOR_WRITING,
PROP_STATUS_FLAGS,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
-1
};
static const int Schedule_Properties_Optional[] = {
PROP_WEEKLY_SCHEDULE,
-1
};
static const int Schedule_Properties_Proprietary[] = {
-1
};
void Schedule_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Schedule_Properties_Required;
if (pOptional)
*pOptional = Schedule_Properties_Optional;
if (pProprietary)
*pProprietary = Schedule_Properties_Proprietary;
}
void Schedule_Init(void)
{
unsigned i, j;
for (i = 0; i < MAX_SCHEDULES; i++) {
/* whole year, change as neccessary */
Schedule_Descr[i].Start_Date.year = 0xFF;
Schedule_Descr[i].Start_Date.month = 1;
Schedule_Descr[i].Start_Date.day = 1;
Schedule_Descr[i].Start_Date.wday = 0xFF;
Schedule_Descr[i].End_Date.year = 0xFF;
Schedule_Descr[i].End_Date.month = 12;
Schedule_Descr[i].End_Date.day = 31;
Schedule_Descr[i].End_Date.wday = 0xFF;
for (j = 0; j < 7; j++) {
Schedule_Descr[i].Weekly_Schedule[j].TV_Count = 0;
}
Schedule_Descr[i].Present_Value = &Schedule_Descr[i].Schedule_Default;
Schedule_Descr[i].Schedule_Default.context_specific = false;
Schedule_Descr[i].Schedule_Default.tag = BACNET_APPLICATION_TAG_REAL;
Schedule_Descr[i].Schedule_Default.type.Real = 21.0; /* 21 C, room temperature */
Schedule_Descr[i].obj_prop_ref_cnt = 0; /* no references, add as needed */
Schedule_Descr[i].Priority_For_Writing = 16; /* lowest priority */
Schedule_Descr[i].Out_Of_Service = false;
}
}
bool Schedule_Valid_Instance(uint32_t object_instance)
{
unsigned int index = Schedule_Instance_To_Index(object_instance);
if (index < MAX_SCHEDULES)
return true;
else
return false;
}
unsigned Schedule_Count(void)
{
return MAX_SCHEDULES;
}
uint32_t Schedule_Index_To_Instance(unsigned index)
{
return index;
}
unsigned Schedule_Instance_To_Index(uint32_t instance)
{
unsigned index = MAX_SCHEDULES;
if (instance < MAX_SCHEDULES)
index = instance;
return index;
}
bool Schedule_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
unsigned int index;
bool status = false;
index = Schedule_Instance_To_Index(object_instance);
if (index < MAX_SCHEDULES) {
sprintf(text_string, "SCHEDULE %lu", (unsigned long) index);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* BACnet Testing Observed Incident oi00106
Out of service was not supported by Schedule object
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00032
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
void Schedule_Out_Of_Service_Set(
uint32_t object_instance,
bool value)
{
unsigned index = 0;
index = Schedule_Instance_To_Index(object_instance);
if (index < MAX_SCHEDULES) {
Schedule_Descr[index].Out_Of_Service = value;
}
}
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0;
unsigned object_index = 0;
SCHEDULE_DESCR *CurrentSC;
uint8_t *apdu = NULL;
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
int i;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
object_index = Schedule_Instance_To_Index(rpdata->object_instance);
if (object_index < MAX_SCHEDULES)
CurrentSC = &Schedule_Descr[object_index];
else
return BACNET_STATUS_ERROR;
apdu = rpdata->application_data;
switch ((int) rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_SCHEDULE,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Schedule_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_SCHEDULE);
break;
case PROP_PRESENT_VALUE:
apdu_len = bacapp_encode_data(&apdu[0], CurrentSC->Present_Value);
break;
case PROP_EFFECTIVE_PERIOD:
/* BACnet Testing Observed Incident oi00110
Effective Period of Schedule object not correctly formatted
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00031
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
apdu_len = encode_application_date(&apdu[0], &CurrentSC->Start_Date);
apdu_len +=
encode_application_date(&apdu[apdu_len], &CurrentSC->End_Date);
break;
case PROP_WEEKLY_SCHEDULE:
if (rpdata->array_index == 0) /* count, always 7 */
apdu_len = encode_application_unsigned(&apdu[0], 7);
else if (rpdata->array_index == BACNET_ARRAY_ALL) { /* full array */
int day;
for (day = 0; day < 7; day++) {
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count;
i++) {
apdu_len +=
bacapp_encode_time_value(&apdu[apdu_len],
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
}
} else if (rpdata->array_index <= 7) { /* some array element */
int day = rpdata->array_index - 1;
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count; i++) {
apdu_len +=
bacapp_encode_time_value(&apdu[apdu_len],
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
} else { /* out of bounds */
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
break;
case PROP_SCHEDULE_DEFAULT:
apdu_len =
bacapp_encode_data(&apdu[0], &CurrentSC->Schedule_Default);
break;
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
for (i = 0; i < CurrentSC->obj_prop_ref_cnt; i++) {
apdu_len +=
bacapp_encode_device_obj_property_ref(&apdu[apdu_len],
&CurrentSC->Object_Property_References[i]);
}
break;
case PROP_PRIORITY_FOR_WRITING:
apdu_len =
encode_application_unsigned(&apdu[0],
CurrentSC->Priority_For_Writing);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
RELIABILITY_NO_FAULT_DETECTED);
break;
case PROP_OUT_OF_SERVICE:
/* BACnet Testing Observed Incident oi00106
Out of service was not supported by Schedule object
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00032
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
apdu_len = encode_application_boolean(&apdu[0],
CurrentSC->Out_Of_Service );
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
if ((apdu_len >= 0) && (rpdata->object_property != PROP_WEEKLY_SCHEDULE)
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
{
/* Ed->Steve, I know that initializing stack values used to be 'safer', but warnings in latest compilers indicate when
uninitialized values are being used, and I think that the warnings are more useful to reveal bad code flow than the
"safety: of pre-intializing variables. Please give this some thought let me know if you agree we should start to
remove initializations */
unsigned object_index ;
bool status = false; /* return value */
int len ;
BACNET_APPLICATION_DATA_VALUE value;
/* BACnet Testing Observed Incident oi00106
Out of service was not supported by Schedule object
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00032
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
object_index = Schedule_Instance_To_Index(wp_data->object_instance);
if (object_index >= MAX_SCHEDULES) {
return false;
}
switch ((int) wp_data->object_property) {
case PROP_OUT_OF_SERVICE:
/* BACnet Testing Observed Incident oi00106
Out of service was not supported by Schedule object
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00032
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
Schedule_Out_Of_Service_Set(
wp_data->object_instance,
value.type.Boolean);
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_PRESENT_VALUE:
case PROP_EFFECTIVE_PERIOD:
case PROP_WEEKLY_SCHEDULE:
case PROP_SCHEDULE_DEFAULT:
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
case PROP_PRIORITY_FOR_WRITING:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
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;
break;
}
return status;
}
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
BACNET_DATE * date)
{
bool res = false;
if (desc && date) {
if (datetime_wildcard_compare_date(&desc->Start_Date, date) <= 0 &&
datetime_wildcard_compare_date(&desc->End_Date, date) >= 0)
res = true;
}
return res;
}
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
BACNET_WEEKDAY wday,
BACNET_TIME * time)
{
int i;
desc->Present_Value = NULL;
/* for future development, here should be the loop for Exception Schedule */
/* Just a note to developers: We have a paying customer who has asked us to fully implement the Schedule Object.
In good spirit, they have agreed to allow us to release the code we develop back to the Open Source community after a 6-12 month waiting period.
However, if you are about to work on this yourself, please ping us at info@connect-ex.com, we may be able to broker an early release on a
case-by-case basis. */
for (i = 0;
i < desc->Weekly_Schedule[wday - 1].TV_Count &&
desc->Present_Value == NULL; i++) {
int diff = datetime_wildcard_compare_time(time,
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Time);
if (diff >= 0 &&
desc->Weekly_Schedule[wday - 1].Time_Values[i].Value.tag !=
BACNET_APPLICATION_TAG_NULL) {
desc->Present_Value =
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Value;
}
}
if (desc->Present_Value == NULL)
desc->Present_Value = &desc->Schedule_Default;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
void testSchedule(Test * pTest)
{
BACNET_READ_PROPERTY_DATA rpdata;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
Schedule_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_SCHEDULE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Schedule_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_SCHEDULE
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Schedule", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testSchedule);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_SCHEDULE */
#endif /* TEST */
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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.
*
*********************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bactext.h"
#include "config.h"
#include "device.h"
#include "handlers.h"
#include "proplist.h"
#include "timestamp.h"
#include "schedule.h"
#ifndef MAX_SCHEDULES
#define MAX_SCHEDULES 4
#endif
SCHEDULE_DESCR Schedule_Descr[MAX_SCHEDULES];
static const int Schedule_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_EFFECTIVE_PERIOD,
PROP_SCHEDULE_DEFAULT,
PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES,
PROP_PRIORITY_FOR_WRITING,
PROP_STATUS_FLAGS,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
-1
};
static const int Schedule_Properties_Optional[] = {
PROP_WEEKLY_SCHEDULE,
-1
};
static const int Schedule_Properties_Proprietary[] = {
-1
};
void Schedule_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Schedule_Properties_Required;
if (pOptional)
*pOptional = Schedule_Properties_Optional;
if (pProprietary)
*pProprietary = Schedule_Properties_Proprietary;
}
void Schedule_Init(void)
{
unsigned i, j;
for (i = 0; i < MAX_SCHEDULES; i++) {
/* whole year, change as neccessary */
Schedule_Descr[i].Start_Date.year = 0xFF;
Schedule_Descr[i].Start_Date.month = 1;
Schedule_Descr[i].Start_Date.day = 1;
Schedule_Descr[i].Start_Date.wday = 0xFF;
Schedule_Descr[i].End_Date.year = 0xFF;
Schedule_Descr[i].End_Date.month = 12;
Schedule_Descr[i].End_Date.day = 31;
Schedule_Descr[i].End_Date.wday = 0xFF;
for (j = 0; j < 7; j++) {
Schedule_Descr[i].Weekly_Schedule[j].TV_Count = 0;
}
Schedule_Descr[i].Present_Value = &Schedule_Descr[i].Schedule_Default;
Schedule_Descr[i].Schedule_Default.context_specific = false;
Schedule_Descr[i].Schedule_Default.tag = BACNET_APPLICATION_TAG_REAL;
Schedule_Descr[i].Schedule_Default.type.Real = 21.0; /* 21 C, room temperature */
Schedule_Descr[i].obj_prop_ref_cnt = 0; /* no references, add as needed */
Schedule_Descr[i].Priority_For_Writing = 16; /* lowest priority */
Schedule_Descr[i].Out_Of_Service = false;
}
}
bool Schedule_Valid_Instance(uint32_t object_instance)
{
unsigned int index = Schedule_Instance_To_Index(object_instance);
if (index < MAX_SCHEDULES)
return true;
else
return false;
}
unsigned Schedule_Count(void)
{
return MAX_SCHEDULES;
}
uint32_t Schedule_Index_To_Instance(unsigned index)
{
return index;
}
unsigned Schedule_Instance_To_Index(uint32_t instance)
{
unsigned index = MAX_SCHEDULES;
if (instance < MAX_SCHEDULES)
index = instance;
return index;
}
bool Schedule_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
unsigned int index;
bool status = false;
index = Schedule_Instance_To_Index(object_instance);
if (index < MAX_SCHEDULES) {
sprintf(text_string, "SCHEDULE %lu", (unsigned long) index);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* BACnet Testing Observed Incident oi00106
Out of service was not supported by Schedule object
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00032
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
void Schedule_Out_Of_Service_Set(
uint32_t object_instance,
bool value)
{
unsigned index = 0;
index = Schedule_Instance_To_Index(object_instance);
if (index < MAX_SCHEDULES) {
Schedule_Descr[index].Out_Of_Service = value;
}
}
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0;
unsigned object_index = 0;
SCHEDULE_DESCR *CurrentSC;
uint8_t *apdu = NULL;
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
int i;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
object_index = Schedule_Instance_To_Index(rpdata->object_instance);
if (object_index < MAX_SCHEDULES)
CurrentSC = &Schedule_Descr[object_index];
else
return BACNET_STATUS_ERROR;
apdu = rpdata->application_data;
switch ((int) rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_SCHEDULE,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Schedule_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_SCHEDULE);
break;
case PROP_PRESENT_VALUE:
apdu_len = bacapp_encode_data(&apdu[0], CurrentSC->Present_Value);
break;
case PROP_EFFECTIVE_PERIOD:
/* BACnet Testing Observed Incident oi00110
Effective Period of Schedule object not correctly formatted
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00031
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
apdu_len = encode_application_date(&apdu[0], &CurrentSC->Start_Date);
apdu_len +=
encode_application_date(&apdu[apdu_len], &CurrentSC->End_Date);
break;
case PROP_WEEKLY_SCHEDULE:
if (rpdata->array_index == 0) /* count, always 7 */
apdu_len = encode_application_unsigned(&apdu[0], 7);
else if (rpdata->array_index == BACNET_ARRAY_ALL) { /* full array */
int day;
for (day = 0; day < 7; day++) {
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count;
i++) {
apdu_len +=
bacapp_encode_time_value(&apdu[apdu_len],
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
}
} else if (rpdata->array_index <= 7) { /* some array element */
int day = rpdata->array_index - 1;
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count; i++) {
apdu_len +=
bacapp_encode_time_value(&apdu[apdu_len],
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
} else { /* out of bounds */
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
break;
case PROP_SCHEDULE_DEFAULT:
apdu_len =
bacapp_encode_data(&apdu[0], &CurrentSC->Schedule_Default);
break;
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
for (i = 0; i < CurrentSC->obj_prop_ref_cnt; i++) {
apdu_len +=
bacapp_encode_device_obj_property_ref(&apdu[apdu_len],
&CurrentSC->Object_Property_References[i]);
}
break;
case PROP_PRIORITY_FOR_WRITING:
apdu_len =
encode_application_unsigned(&apdu[0],
CurrentSC->Priority_For_Writing);
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
RELIABILITY_NO_FAULT_DETECTED);
break;
case PROP_OUT_OF_SERVICE:
/* BACnet Testing Observed Incident oi00106
Out of service was not supported by Schedule object
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00032
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
apdu_len = encode_application_boolean(&apdu[0],
CurrentSC->Out_Of_Service );
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
if ((apdu_len >= 0) && (rpdata->object_property != PROP_WEEKLY_SCHEDULE)
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
{
/* Ed->Steve, I know that initializing stack values used to be 'safer', but warnings in latest compilers indicate when
uninitialized values are being used, and I think that the warnings are more useful to reveal bad code flow than the
"safety: of pre-intializing variables. Please give this some thought let me know if you agree we should start to
remove initializations */
unsigned object_index ;
bool status = false; /* return value */
int len ;
BACNET_APPLICATION_DATA_VALUE value;
/* BACnet Testing Observed Incident oi00106
Out of service was not supported by Schedule object
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00032
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
object_index = Schedule_Instance_To_Index(wp_data->object_instance);
if (object_index >= MAX_SCHEDULES) {
return false;
}
switch ((int) wp_data->object_property) {
case PROP_OUT_OF_SERVICE:
/* BACnet Testing Observed Incident oi00106
Out of service was not supported by Schedule object
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
BITS: BIT00032
Any discussions can be directed to edward@bac-test.com
Please feel free to remove this comment when my changes accepted after suitable time for
review by all interested parties. Say 6 months -> September 2016 */
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
Schedule_Out_Of_Service_Set(
wp_data->object_instance,
value.type.Boolean);
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_PRESENT_VALUE:
case PROP_EFFECTIVE_PERIOD:
case PROP_WEEKLY_SCHEDULE:
case PROP_SCHEDULE_DEFAULT:
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
case PROP_PRIORITY_FOR_WRITING:
case PROP_STATUS_FLAGS:
case PROP_RELIABILITY:
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;
break;
}
return status;
}
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
BACNET_DATE * date)
{
bool res = false;
if (desc && date) {
if (datetime_wildcard_compare_date(&desc->Start_Date, date) <= 0 &&
datetime_wildcard_compare_date(&desc->End_Date, date) >= 0)
res = true;
}
return res;
}
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
BACNET_WEEKDAY wday,
BACNET_TIME * time)
{
int i;
desc->Present_Value = NULL;
/* for future development, here should be the loop for Exception Schedule */
/* Just a note to developers: We have a paying customer who has asked us to fully implement the Schedule Object.
In good spirit, they have agreed to allow us to release the code we develop back to the Open Source community after a 6-12 month waiting period.
However, if you are about to work on this yourself, please ping us at info@connect-ex.com, we may be able to broker an early release on a
case-by-case basis. */
for (i = 0;
i < desc->Weekly_Schedule[wday - 1].TV_Count &&
desc->Present_Value == NULL; i++) {
int diff = datetime_wildcard_compare_time(time,
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Time);
if (diff >= 0 &&
desc->Weekly_Schedule[wday - 1].Time_Values[i].Value.tag !=
BACNET_APPLICATION_TAG_NULL) {
desc->Present_Value =
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Value;
}
}
if (desc->Present_Value == NULL)
desc->Present_Value = &desc->Schedule_Default;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
void testSchedule(Test * pTest)
{
BACNET_READ_PROPERTY_DATA rpdata;
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0;
uint32_t len_value = 0;
uint8_t tag_number = 0;
uint16_t decoded_type = 0;
uint32_t decoded_instance = 0;
Schedule_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_SCHEDULE;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Schedule_Read_Property(&rpdata);
ct_test(pTest, len != 0);
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
ct_test(pTest, decoded_type == rpdata.object_type);
ct_test(pTest, decoded_instance == rpdata.object_instance);
return;
}
#ifdef TEST_SCHEDULE
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Schedule", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testSchedule);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_SCHEDULE */
#endif /* TEST */
+101 -101
View File
@@ -1,101 +1,101 @@
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 SCHEDULE_H
#define SCHEDULE_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacapp.h"
#include "datetime.h"
#include "bacerror.h"
#include "wp.h"
#include "rp.h"
#include "bacdevobjpropref.h"
#include "bactimevalue.h"
#ifndef BACNET_WEEKLY_SCHEDULE_SIZE
#define BACNET_WEEKLY_SCHEDULE_SIZE 8 /* maximum number of data points for each day */
#endif
#ifndef BACNET_SCHEDULE_OBJ_PROP_REF_SIZE
#define BACNET_SCHEDULE_OBJ_PROP_REF_SIZE 4 /* maximum number of obj prop references */
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct bacnet_daily_schedule {
BACNET_TIME_VALUE Time_Values[BACNET_WEEKLY_SCHEDULE_SIZE];
uint16_t TV_Count; /* the number of time values actually used */
} BACNET_DAILY_SCHEDULE;
typedef struct schedule {
/* Effective Period: Start and End Date */
BACNET_DATE Start_Date;
BACNET_DATE End_Date;
/* Properties concerning Present Value */
BACNET_DAILY_SCHEDULE Weekly_Schedule[7];
BACNET_APPLICATION_DATA_VALUE Schedule_Default;
BACNET_APPLICATION_DATA_VALUE *Present_Value; /* must be set to a valid value
* default is Schedule_Default */
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE
Object_Property_References[BACNET_SCHEDULE_OBJ_PROP_REF_SIZE];
uint8_t obj_prop_ref_cnt; /* actual number of obj_prop references */
uint8_t Priority_For_Writing; /* (1..16) */
bool Out_Of_Service;
} SCHEDULE_DESCR;
void Schedule_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Schedule_Valid_Instance(uint32_t object_instance);
unsigned Schedule_Count(void);
uint32_t Schedule_Index_To_Instance(unsigned index);
unsigned Schedule_Instance_To_Index(uint32_t instance);
void Schedule_Init(void);
bool Schedule_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data);
/* utility functions for calculating current Present Value
* if Exception Schedule is to be added, these functions must take that into account */
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
BACNET_DATE * date);
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
BACNET_WEEKDAY wday,
BACNET_TIME * time);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
/**************************************************************************
*
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
*
* 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 SCHEDULE_H
#define SCHEDULE_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacapp.h"
#include "datetime.h"
#include "bacerror.h"
#include "wp.h"
#include "rp.h"
#include "bacdevobjpropref.h"
#include "bactimevalue.h"
#ifndef BACNET_WEEKLY_SCHEDULE_SIZE
#define BACNET_WEEKLY_SCHEDULE_SIZE 8 /* maximum number of data points for each day */
#endif
#ifndef BACNET_SCHEDULE_OBJ_PROP_REF_SIZE
#define BACNET_SCHEDULE_OBJ_PROP_REF_SIZE 4 /* maximum number of obj prop references */
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct bacnet_daily_schedule {
BACNET_TIME_VALUE Time_Values[BACNET_WEEKLY_SCHEDULE_SIZE];
uint16_t TV_Count; /* the number of time values actually used */
} BACNET_DAILY_SCHEDULE;
typedef struct schedule {
/* Effective Period: Start and End Date */
BACNET_DATE Start_Date;
BACNET_DATE End_Date;
/* Properties concerning Present Value */
BACNET_DAILY_SCHEDULE Weekly_Schedule[7];
BACNET_APPLICATION_DATA_VALUE Schedule_Default;
BACNET_APPLICATION_DATA_VALUE *Present_Value; /* must be set to a valid value
* default is Schedule_Default */
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE
Object_Property_References[BACNET_SCHEDULE_OBJ_PROP_REF_SIZE];
uint8_t obj_prop_ref_cnt; /* actual number of obj_prop references */
uint8_t Priority_For_Writing; /* (1..16) */
bool Out_Of_Service;
} SCHEDULE_DESCR;
void Schedule_Property_Lists(const int **pRequired,
const int **pOptional,
const int **pProprietary);
bool Schedule_Valid_Instance(uint32_t object_instance);
unsigned Schedule_Count(void);
uint32_t Schedule_Index_To_Instance(unsigned index);
unsigned Schedule_Instance_To_Index(uint32_t instance);
void Schedule_Init(void);
bool Schedule_Object_Name(uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name);
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data);
/* utility functions for calculating current Present Value
* if Exception Schedule is to be added, these functions must take that into account */
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
BACNET_DATE * date);
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
BACNET_WEEKDAY wday,
BACNET_TIME * time);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+43 -43
View File
@@ -1,43 +1,43 @@
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_SCHEDULE
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = schedule.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactimevalue.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = schedule
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend
#Makefile to build test case
CC = gcc
SRC_DIR = ../../src
TEST_DIR = ../../test
INCLUDES = -I../../include -I$(TEST_DIR) -I.
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_SCHEDULE
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
SRCS = schedule.c \
$(SRC_DIR)/bacdcode.c \
$(SRC_DIR)/bacint.c \
$(SRC_DIR)/bacstr.c \
$(SRC_DIR)/bacreal.c \
$(SRC_DIR)/bacdevobjpropref.c \
$(SRC_DIR)/bactimevalue.c \
$(SRC_DIR)/datetime.c \
$(SRC_DIR)/lighting.c \
$(SRC_DIR)/bacapp.c \
$(SRC_DIR)/bactext.c \
$(SRC_DIR)/indtext.c \
$(TEST_DIR)/ctest.c
TARGET = schedule
all: ${TARGET}
OBJS = ${SRCS:.c=.o}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS)
include: .depend