Nikola Jelić implemented the Access Objects for BACnet (Access Door, Access Point, Access Credential, Access Rights, Access User, Access Zone, and Credential Data Input).

This commit is contained in:
skarg
2016-07-17 19:23:19 +00:00
parent a97bc78ade
commit 1302c1be7b
36 changed files with 5850 additions and 4 deletions
@@ -0,0 +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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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 */
@@ -0,0 +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
@@ -0,0 +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
+690
View File
@@ -0,0 +1,690 @@
/**************************************************************************
*
* 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 Door 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_door.h"
#include "handlers.h"
static bool Access_Door_Initialized = false;
static ACCESS_DOOR_DESCR ad_descr[MAX_ACCESS_DOORS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_PRIORITY_ARRAY,
PROP_RELINQUISH_DEFAULT,
PROP_DOOR_PULSE_TIME,
PROP_DOOR_EXTENDED_PULSE_TIME,
PROP_DOOR_OPEN_TOO_LONG_TIME,
-1
};
static const int Properties_Optional[] = {
PROP_DOOR_STATUS,
PROP_LOCK_STATUS,
PROP_SECURED_STATUS,
PROP_DOOR_UNLOCK_DELAY_TIME,
PROP_DOOR_ALARM_STATE,
-1
};
static const int Properties_Proprietary[] = {
-1
};
void Access_Door_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_Door_Init(
void)
{
unsigned i, j;
if (!Access_Door_Initialized) {
Access_Door_Initialized = true;
/* initialize all the access door priority arrays to NULL */
for (i = 0; i < MAX_ACCESS_DOORS; i++) {
ad_descr[i].relinquish_default = DOOR_VALUE_LOCK;
ad_descr[i].event_state = EVENT_STATE_NORMAL;
ad_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
ad_descr[i].out_of_service = false;
ad_descr[i].door_status = DOOR_STATUS_CLOSED;
ad_descr[i].lock_status = LOCK_STATUS_LOCKED;
ad_descr[i].secured_status = DOOR_SECURED_STATUS_SECURED;
ad_descr[i].door_pulse_time = 30; /* 3s */
ad_descr[i].door_extended_pulse_time = 50; /* 5s */
ad_descr[i].door_unlock_delay_time = 0; /* 0s */
ad_descr[i].door_open_too_long_time = 300; /* 30s */
ad_descr[i].door_alarm_state = DOOR_ALARM_STATE_NORMAL;
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
ad_descr[i].value_active[j] = false;
/* just to fill in */
ad_descr[i].priority_array[j] = DOOR_VALUE_LOCK;
}
}
}
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_Door_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_ACCESS_DOORS)
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_Door_Count(
void)
{
return MAX_ACCESS_DOORS;
}
/* 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_Door_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_Door_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ACCESS_DOORS;
if (object_instance < MAX_ACCESS_DOORS)
index = object_instance;
return index;
}
BACNET_DOOR_VALUE Access_Door_Present_Value(
uint32_t object_instance)
{
unsigned index = 0;
unsigned i = 0;
BACNET_DOOR_VALUE value = DOOR_VALUE_LOCK;
index = Access_Door_Instance_To_Index(object_instance);
if (index < MAX_ACCESS_DOORS) {
value = ad_descr[i].relinquish_default;
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
if (ad_descr[index].value_active[i]) {
value = ad_descr[index].priority_array[i];
break;
}
}
}
return value;
}
unsigned Access_Door_Present_Value_Priority(
uint32_t object_instance)
{
unsigned index = 0; /* instance to index conversion */
unsigned i = 0; /* loop counter */
unsigned priority = 0; /* return value */
index = Access_Door_Instance_To_Index(object_instance);
if (index < MAX_ACCESS_DOORS) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
if (ad_descr[index].value_active[i]) {
priority = i + 1;
break;
}
}
}
return priority;
}
bool Access_Door_Present_Value_Set(
uint32_t object_instance,
BACNET_DOOR_VALUE value,
unsigned priority)
{
unsigned index = 0;
bool status = false;
index = Access_Door_Instance_To_Index(object_instance);
if (index < MAX_ACCESS_DOORS) {
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
(priority != 6 /* reserved */ ) &&
(value >= DOOR_VALUE_LOCK) &&
(value <= DOOR_VALUE_EXTENDED_PULSE_UNLOCK)) {
ad_descr[index].value_active[priority - 1] = true;
ad_descr[index].priority_array[priority - 1] = value;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
status = true;
}
}
return status;
}
bool Access_Door_Present_Value_Relinquish(
uint32_t object_instance,
unsigned priority)
{
unsigned index = 0;
bool status = false;
index = Access_Door_Instance_To_Index(object_instance);
if (index < MAX_ACCESS_DOORS) {
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
(priority != 6 /* reserved */ )) {
ad_descr[index].value_active[priority - 1] = false;
/* Note: you could set the physical output here to the next
highest priority, or to the relinquish default if no
priorities are set.
However, if Out of Service is TRUE, then don't set the
physical output. This comment may apply to the
main loop (i.e. check out of service before changing output) */
status = true;
}
}
return status;
}
BACNET_DOOR_VALUE Access_Door_Relinquish_Default(
uint32_t object_instance)
{
BACNET_DOOR_VALUE status = -1;
unsigned index = 0;
index = Access_Door_Instance_To_Index(object_instance);
if (index < MAX_ACCESS_DOORS) {
return ad_descr[index].relinquish_default;
}
return status;
}
/* note: the object name must be unique within this device */
bool Access_Door_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_DOORS) {
sprintf(text_string, "ACCESS DOOR %lu",
(unsigned long) object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
bool Access_Door_Out_Of_Service(
uint32_t instance)
{
unsigned index = 0;
bool oos_flag = false;
index = Access_Door_Instance_To_Index(instance);
if (index < MAX_ACCESS_DOORS) {
oos_flag = ad_descr[index].out_of_service;
}
return oos_flag;
}
void Access_Door_Out_Of_Service_Set(
uint32_t instance,
bool oos_flag)
{
unsigned index = 0;
index = Access_Door_Instance_To_Index(instance);
if (index < MAX_ACCESS_DOORS) {
ad_descr[index].out_of_service = oos_flag;
}
}
/* return apdu len, or BACNET_STATUS_ERROR on error */
int Access_Door_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_Door_Instance_To_Index(rpdata->object_instance);
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], OBJECT_ACCESS_DOOR,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Access_Door_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_DOOR);
break;
case PROP_PRESENT_VALUE:
apdu_len =
encode_application_enumerated(&apdu[0],
Access_Door_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);
state = Access_Door_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],
ad_descr[object_index].event_state);
break;
case PROP_RELIABILITY:
apdu_len =
encode_application_enumerated(&apdu[0],
ad_descr[object_index].reliability);
break;
case PROP_OUT_OF_SERVICE:
state = Access_Door_Out_Of_Service(rpdata->object_instance);
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (rpdata->array_index == 0)
apdu_len =
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
/* if no index was specified, then try to encode the entire list */
/* into one packet. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
if (ad_descr[object_index].value_active[i])
len = encode_application_null(&apdu[apdu_len]);
else
len =
encode_application_enumerated(&apdu[apdu_len],
ad_descr[object_index].priority_array[i]);
/* add it if we have room */
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (ad_descr[object_index].value_active[i])
apdu_len = encode_application_null(&apdu[0]);
else {
apdu_len =
encode_application_enumerated(&apdu[apdu_len],
ad_descr[object_index].priority_array[i]);
}
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_RELINQUISH_DEFAULT:
apdu_len =
encode_application_enumerated(&apdu[0],
Access_Door_Relinquish_Default(rpdata->object_instance));
break;
case PROP_DOOR_STATUS:
apdu_len =
encode_application_enumerated(&apdu[0],
ad_descr[object_index].door_status);
break;
case PROP_LOCK_STATUS:
apdu_len =
encode_application_enumerated(&apdu[0],
ad_descr[object_index].lock_status);
break;
case PROP_SECURED_STATUS:
apdu_len =
encode_application_enumerated(&apdu[0],
ad_descr[object_index].secured_status);
break;
case PROP_DOOR_PULSE_TIME:
apdu_len =
encode_application_unsigned(&apdu[0],
ad_descr[object_index].door_pulse_time);
break;
case PROP_DOOR_EXTENDED_PULSE_TIME:
apdu_len =
encode_application_unsigned(&apdu[0],
ad_descr[object_index].door_extended_pulse_time);
break;
case PROP_DOOR_UNLOCK_DELAY_TIME:
apdu_len =
encode_application_unsigned(&apdu[0],
ad_descr[object_index].door_unlock_delay_time);
break;
case PROP_DOOR_OPEN_TOO_LONG_TIME:
apdu_len =
encode_application_unsigned(&apdu[0],
ad_descr[object_index].door_open_too_long_time);
break;
case PROP_DOOR_ALARM_STATE:
apdu_len =
encode_application_enumerated(&apdu[0],
ad_descr[object_index].door_alarm_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->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_Door_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_PRIORITY_ARRAY) &&
(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_Door_Instance_To_Index(wp_data->object_instance);
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
status =
Access_Door_Present_Value_Set(wp_data->object_instance,
value.type.Enumerated, wp_data->priority);
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 if (!status) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else {
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class, &wp_data->error_code);
if (status) {
status =
Access_Door_Present_Value_Relinquish
(wp_data->object_instance, wp_data->priority);
if (!status) {
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) {
Access_Door_Out_Of_Service_Set(wp_data->object_instance,
value.type.Boolean);
}
break;
case PROP_DOOR_STATUS:
if (Access_Door_Out_Of_Service(wp_data->object_instance)) {
status =
WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
&wp_data->error_code);
if (status) {
ad_descr[object_index].door_status = value.type.Enumerated;
}
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
break;
case PROP_LOCK_STATUS:
if (Access_Door_Out_Of_Service(wp_data->object_instance)) {
status =
WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
&wp_data->error_code);
if (status) {
ad_descr[object_index].lock_status = value.type.Enumerated;
}
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
break;
case PROP_DOOR_ALARM_STATE:
if (Access_Door_Out_Of_Service(wp_data->object_instance)) {
status =
WPValidateArgType(&value,
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
&wp_data->error_code);
if (status) {
ad_descr[object_index].door_alarm_state =
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_EVENT_STATE:
case PROP_RELIABILITY:
case PROP_PRIORITY_ARRAY:
case PROP_RELINQUISH_DEFAULT:
case PROP_SECURED_STATUS:
case PROP_DOOR_PULSE_TIME:
case PROP_DOOR_EXTENDED_PULSE_TIME:
case PROP_DOOR_UNLOCK_DELAY_TIME:
case PROP_DOOR_OPEN_TOO_LONG_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 testAccessDoor(
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_Door_Init();
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_ACCESS_DOOR;
rpdata.object_instance = 1;
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Access_Door_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_DOOR
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Access Door", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testAccessDoor);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_ACCESS_DOOR */
#endif /* TEST */
+143
View File
@@ -0,0 +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
+42
View File
@@ -0,0 +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
+476
View File
@@ -0,0 +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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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
View File
@@ -0,0 +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
+43
View File
@@ -0,0 +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
+435
View File
@@ -0,0 +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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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
View File
@@ -0,0 +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
@@ -0,0 +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
+373
View File
@@ -0,0 +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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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
View File
@@ -0,0 +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
+42
View File
@@ -0,0 +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
+446
View File
@@ -0,0 +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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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
View File
@@ -0,0 +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
+42
View File
@@ -0,0 +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
@@ -0,0 +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_TYPE_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_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
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 */
@@ -0,0 +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
@@ -0,0 +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
+7
View File
@@ -34,6 +34,13 @@ OBJECT_SRC = \
$(BACNET_OBJECT)/nc.c \
$(BACNET_OBJECT)/trendlog.c \
$(BACNET_OBJECT)/schedule.c \
$(BACNET_OBJECT)/access_credential.c \
$(BACNET_OBJECT)/access_door.c \
$(BACNET_OBJECT)/access_point.c \
$(BACNET_OBJECT)/access_rights.c \
$(BACNET_OBJECT)/access_user.c \
$(BACNET_OBJECT)/access_zone.c \
$(BACNET_OBJECT)/credential_data_input.c \
$(BACNET_OBJECT)/bacfile.c
SRCS = ${SRC} ${OBJECT_SRC}
+76
View File
@@ -0,0 +1,76 @@
/**************************************************************************
*
* 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_RULE_H
#define ACCESS_RULE_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacapp.h"
#include "bacdevobjpropref.h"
typedef enum {
TIME_RANGE_SPECIFIER_SPECIFIED = 0,
TIME_RANGE_SPECIFIER_ALWAYS = 1
} BACNET_ACCESS_RULE_TIME_RANGE_SPECIFIER;
typedef enum {
LOCATION_SPECIFIER_SPECIFIED = 0,
LOCATION_SPECIFIER_ALL = 1
} BACNET_ACCESS_RULE_LOCATION_SPECIFIER;
typedef struct {
BACNET_ACCESS_RULE_TIME_RANGE_SPECIFIER time_range_specifier;
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE time_range;
BACNET_ACCESS_RULE_LOCATION_SPECIFIER location_specifier;
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE location;
bool enable;
} BACNET_ACCESS_RULE;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bacapp_encode_access_rule(
uint8_t * apdu,
BACNET_ACCESS_RULE * rule);
int bacapp_encode_context_access_rule(
uint8_t * apdu,
uint8_t tag_number,
BACNET_ACCESS_RULE * rule);
int bacapp_decode_access_rule(
uint8_t * apdu,
BACNET_ACCESS_RULE * rule);
int bacapp_decode_context_access_rule(
uint8_t * apdu,
uint8_t tag_number,
BACNET_ACCESS_RULE * rule);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
@@ -0,0 +1,62 @@
/**************************************************************************
*
* 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 BACNET_ASSIGNED_ACCESS_RIGHTS_H
#define BACNET_ASSIGNED_ACCESS_RIGHTS_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacapp.h"
#include "bacdevobjpropref.h"
typedef struct {
BACNET_DEVICE_OBJECT_REFERENCE assigned_access_rights;
bool enable;
} BACNET_ASSIGNED_ACCESS_RIGHTS;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bacapp_encode_assigned_access_rights(
uint8_t * apdu,
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
int bacapp_encode_context_assigned_access_rights(
uint8_t * apdu,
uint8_t tag,
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
int bacapp_decode_assigned_access_rights(
uint8_t * apdu,
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
int bacapp_decode_context_assigned_access_rights(
uint8_t * apdu,
uint8_t tag,
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
@@ -0,0 +1,64 @@
/**************************************************************************
*
* 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 BACNET_AUTHENTICATION_FACTOR_H
#define BACNET_AUTHENTICATION_FACTOR_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacapp.h"
typedef struct {
BACNET_AUTHENTICATION_FACTOR_TYPE format_type;
uint32_t format_class;
BACNET_OCTET_STRING value;
} BACNET_AUTHENTICATION_FACTOR;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bacapp_encode_authentication_factor(
uint8_t * apdu,
BACNET_AUTHENTICATION_FACTOR * af);
int bacapp_encode_context_authentication_factor(
uint8_t * apdu,
uint8_t tag,
BACNET_AUTHENTICATION_FACTOR * af);
int bacapp_decode_authentication_factor(
uint8_t * apdu,
BACNET_AUTHENTICATION_FACTOR * af);
int bacapp_decode_context_authentication_factor(
uint8_t * apdu,
uint8_t tag,
BACNET_AUTHENTICATION_FACTOR * af);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
@@ -0,0 +1,60 @@
/**************************************************************************
*
* 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 BACNET_AUTHENTICATION_FACTOR_FORMAT_H
#define BACNET_AUTHENTICATION_FACTOR_FORMAT_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
typedef struct {
BACNET_AUTHENTICATION_FACTOR_TYPE format_type;
uint32_t vendor_id, vendor_format;
} BACNET_AUTHENTICATION_FACTOR_FORMAT;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bacapp_encode_authentication_factor_format(
uint8_t * apdu,
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
int bacapp_encode_context_authentication_factor_format(
uint8_t * apdu,
uint8_t tag_number,
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
int bacapp_decode_authentication_factor_format(
uint8_t * apdu,
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
int bacapp_decode_context_authentication_factor_format(
uint8_t * apdu,
uint8_t tag_number,
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+235 -2
View File
@@ -290,7 +290,7 @@ typedef enum {
PROP_DAYS_REMAINING = 267,
PROP_ENTRY_POINTS = 268,
PROP_EXIT_POINTS = 269,
PROP_EXPIRY_TIME = 270,
PROP_EXPIRATION_TIME = 270,
PROP_EXTENDED_TIME_ENABLE = 271,
PROP_FAILED_ATTEMPT_EVENTS = 272,
PROP_FAILED_ATTEMPTS = 273,
@@ -876,13 +876,23 @@ typedef enum {
EVENT_EXTENDED = 9,
EVENT_BUFFER_READY = 10,
EVENT_UNSIGNED_RANGE = 11,
EVENT_ACCESS_EVENT = 13,
EVENT_DOUBLE_OUT_OF_RANGE = 14,
EVENT_SIGNED_OUT_OF_RANGE = 15,
EVENT_UNSIGNED_OUT_OF_RANGE = 16,
EVENT_CHANGE_OF_CHARACTERSTRING = 17,
EVENT_CHANGE_OF_STATUS_FLAGS = 18,
EVENT_CHANGE_OF_RELIABILITY = 19,
EVENT_NONE = 20,
EVENT_CHANGE_OF_DISCRETE_VALUE = 21,
EVENT_CHANGE_OF_TIMER = 22,
/* Enumerated values 0-63 are reserved for definition by ASHRAE. */
/* Enumerated values 64-65535 may be used by others subject to */
/* the procedures and constraints described in Clause 23. */
/* It is expected that these enumerated values will correspond to */
/* the use of the complex-event-type CHOICE [6] of the */
/* BACnetNotificationParameters production. */
/* The last enumeration used in this version is 11. */
/* The last enumeration used in this version is 22. */
/* do the max range inside of enum so that
compilers will allocate adequate sized datatype for enum
which is used to store decoding */
@@ -1783,6 +1793,229 @@ typedef enum BACnetEventTransitionMask {
TRANSITION_TO_NORMAL_MASKED = 4
} BACNET_EVENT_TRANSITION_MASK;
/* Access Enumerations */
/* Door Alarm State */
typedef enum {
DOOR_ALARM_STATE_NORMAL = 0,
DOOR_ALARM_STATE_ALARM = 1,
DOOR_ALARM_STATE_DOOR_OPEN_TOO_LONG = 2,
DOOR_ALARM_STATE_FORCED_OPEN = 3,
DOOR_ALARM_STATE_TAMPER = 4,
DOOR_ALARM_STATE_DOOR_FAULT = 5,
DOOR_ALARM_STATE_LOCK_DOWN = 6,
DOOR_ALARM_STATE_FREE_ACCESS = 7,
DOOR_ALARM_STATE_EGRESS_OPEN = 8
} BACNET_DOOR_ALARM_STATE;
/* Door Secured Status */
typedef enum {
DOOR_SECURED_STATUS_SECURED = 0,
DOOR_SECURED_STATUS_UNSECURED = 1,
DOOR_SECURED_STATUS_UNKNOWN = 2
} BACNET_DOOR_SECURED_STATUS;
/* Door Status */
typedef enum {
DOOR_STATUS_CLOSED = 0,
DOOR_STATUS_OPENED = 1,
DOOR_STATUS_UNKNOWN = 2,
DOOR_STATUS_DOOR_FAULT = 4,
DOOR_STATUS_UNUSED = 5
} BACNET_DOOR_STATUS;
/* Door Value */
typedef enum {
DOOR_VALUE_LOCK = 0,
DOOR_VALUE_UNLOCK = 1,
DOOR_VALUE_PULSE_UNLOCK = 2,
DOOR_VALUE_EXTENDED_PULSE_UNLOCK = 3
} BACNET_DOOR_VALUE;
/* Lock Status */
typedef enum {
LOCK_STATUS_LOCKED = 0,
LOCK_STATUS_UNLOCKED = 1,
LOCK_STATUS_LOCK_FAULT = 2,
LOCK_STATUS_UNUSED = 3,
LOCK_STATUS_UNKNOWN = 4
} BACNET_LOCK_STATUS;
/* Access Event */
typedef enum {
ACCESS_EVENT_NONE = 0,
ACCESS_EVENT_GRANTED = 1,
ACCESS_EVENT_MUSTER = 2,
ACCESS_EVENT_PASSBACK_DETECTED = 3,
ACCESS_EVENT_DURESS = 4,
ACCESS_EVENT_TRACE = 5,
ACCESS_EVENT_LOCKOUT_MAX_ATTEMPTS = 6,
ACCESS_EVENT_LOCKOUT_OTHER = 7,
ACCESS_EVENT_LOCKOUT_RELINQUISHED = 8,
ACCESS_EVENT_LOCKED_BY_HIGHER_AUTHORITY = 9,
ACCESS_EVENT_OUT_OF_SERVICE = 10,
ACCESS_EVENT_OUT_OF_SERVICE_RELINQUISHED = 11,
ACCESS_EVENT_ACCOMPANIMENT_BY = 12,
ACCESS_EVENT_AUTHENTICATION_FACTOR_READ = 13,
ACCESS_EVENT_AUTHORIZATION_DELAYED = 14,
ACCESS_EVENT_VERIFICATION_REQUIRED = 15,
/* values over 128 indicate that access is denied */
ACCESS_EVENT_DENIED_DENY_ALL = 128,
ACCESS_EVENT_DENIED_UNKNOWN_CREDENTIAL = 129,
ACCESS_EVENT_DENIED_AUTHENTICATION_UNAVAILABLE = 130,
ACCESS_EVENT_DENIED_AUTHENTICATION_FACTOR_TIMEOUT = 131,
ACCESS_EVENT_DENIED_INCORRECT_AUTHENTICATION_FACTOR = 132,
ACCESS_EVENT_DENIED_ZONE_NO_ACCESS_RIGHTS = 133,
ACCESS_EVENT_DENIED_POINT_NO_ACCESS_RIGHTS = 134,
ACCESS_EVENT_DENIED_NO_ACCESS_RIGHTS = 135,
ACCESS_EVENT_DENIED_OUT_OF_TIME_RANGE = 136,
ACCESS_EVENT_DENIED_THREAT_LEVEL = 137,
ACCESS_EVENT_DENIED_PASSBACK = 138,
ACCESS_EVENT_DENIED_UNEXPECTED_LOCATION_USAGE = 139,
ACCESS_EVENT_DENIED_MAX_ATTEMPTS = 140,
ACCESS_EVENT_DENIED_LOWER_OCCUPANCY_LIMIT = 141,
ACCESS_EVENT_DENIED_UPPER_OCCUPANCY_LIMIT = 142,
ACCESS_EVENT_DENIED_AUTHENTICATION_FACTOR_LOST = 143,
ACCESS_EVENT_DENIED_AUTHENTICATION_FACTOR_STOLEN = 144,
ACCESS_EVENT_DENIED_AUTHENTICATION_FACTOR_DAMAGED = 145,
ACCESS_EVENT_DENIED_AUTHENTICATION_FACTOR_DESTROYED = 146,
ACCESS_EVENT_DENIED_AUTHENTICATION_FACTOR_DISABLED = 147,
ACCESS_EVENT_DENIED_AUTHENTICATION_FACTOR_ERROR = 148,
ACCESS_EVENT_DENIED_CREDENTIAL_UNASSIGNED = 149,
ACCESS_EVENT_DENIED_CREDENTIAL_NOT_PROVISIONED = 150,
ACCESS_EVENT_DENIED_CREDENTIAL_NOT_YET_ACTIVE = 151,
ACCESS_EVENT_DENIED_CREDENTIAL_EXPIRED = 152,
ACCESS_EVENT_DENIED_CREDENTIAL_MANUAL_DISABLE = 153,
ACCESS_EVENT_DENIED_CREDENTIAL_LOCKOUT = 154,
ACCESS_EVENT_DENIED_CREDENTIAL_MAX_DAYS = 155,
ACCESS_EVENT_DENIED_CREDENTIAL_MAX_USES = 156,
ACCESS_EVENT_DENIED_CREDENTIAL_INACTIVITY = 157,
ACCESS_EVENT_DENIED_CREDENTIAL_DISABLED = 158,
ACCESS_EVENT_DENIED_NO_ACCOMPANIMENT = 159,
ACCESS_EVENT_DENIED_INCORRECT_ACCOMPANIMENT = 160,
ACCESS_EVENT_DENIED_LOCKOUT = 161,
ACCESS_EVENT_DENIED_VERIFICATION_FAILED = 162,
ACCESS_EVENT_DENIED_VERIFICATION_TIMEOUT = 163,
ACCESS_EVENT_DENIED_OTHER = 164
} BACNET_ACCESS_EVENT;
/* Authentication Status */
typedef enum {
AUTHENTICATION_STATUS_NOT_READY = 0,
AUTHENTICATION_STATUS_READY = 1,
AUTHENTICATION_STATUS_DISABLED = 2,
AUTHENTICATION_STATUS_WAITING_FOR_AUTHENTICATION_FACTOR = 3,
AUTHENTICATION_STATUS_WAITING_FOR_ACCOMPANIMENT = 4,
AUTHENTICATION_STATUS_WAITING_FOR_VERIFICATION = 5,
AUTHENTICATION_STATUS_IN_PROGRESS = 6
} BACNET_AUTHENTICATION_STATUS;
/* Authorization Mode */
typedef enum {
AUTHORIZATION_MODE_AUTHORIZE = 0,
AUTHORIZATION_MODE_GRANT_ACTIVE = 1,
AUTHORIZATION_MODE_DENY_ALL = 2,
AUTHORIZATION_MODE_VERIFICATION_REQUIRED = 3,
AUTHORIZATION_MODE_AUTHORIZATION_DELAYED = 4,
AUTHORIZATION_MODE_NONE = 5
} BACNET_AUTHORIZATION_MODE;
/* Access Passback Mode */
typedef enum {
ACCESS_PASSBACK_MODE_PASSBACK_OFF = 0,
ACCESS_PASSBACK_MODE_HARD_PASSBACK = 1,
ACCESS_PASSBACK_MODE_SOFT_PASSBACK = 2
} BACNET_ACCESS_PASSBACK_MODE;
/* Access Zone Occupancy State */
typedef enum {
ACCESS_ZONE_OCCUPANCY_STATE_NORMAL = 0,
ACCESS_ZONE_OCCUPANCY_STATE_BELOW_LOWER_LIMIT = 1,
ACCESS_ZONE_OCCUPANCY_STATE_AT_LOWER_LIMIT = 2,
ACCESS_ZONE_OCCUPANCY_STATE_AT_UPPER_LIMIT = 3,
ACCESS_ZONE_OCCUPANCY_STATE_ABOVE_UPPER_LIMIT = 4,
ACCESS_ZONE_OCCUPANCY_STATE_DISABLED = 5,
ACCESS_ZONE_OCCUPANCY_STATE_NOT_SUPPORTED = 6
} BACNET_ACCESS_ZONE_OCCUPANCY_STATE;
/* Access User Type */
typedef enum {
ACCESS_USER_TYPE_ASSET = 0,
ACCESS_USER_TYPE_GROUP = 1,
ACCESS_USER_TYPE_PERSON = 2
} BACNET_ACCESS_USER_TYPE;
/* Access Authentication Factor Disable */
typedef enum {
ACCESS_AUTHENTICATION_FACTOR_DISABLE_NONE = 0,
ACCESS_AUTHENTICATION_FACTOR_DISABLE_DISABLED = 1,
ACCESS_AUTHENTICATION_FACTOR_DISABLE_DISABLED_LOST = 2,
ACCESS_AUTHENTICATION_FACTOR_DISABLE_DISABLED_STOLEN = 3,
ACCESS_AUTHENTICATION_FACTOR_DISABLE_DISABLED_DAMAGED = 4,
ACCESS_AUTHENTICATION_FACTOR_DISABLE_DISABLED_DESTROYED = 5
} BACNET_ACCESS_AUTHENTICATION_FACTOR_DISABLE;
/* Access Credential Disable */
typedef enum {
ACCESS_CREDENTIAL_DISABLE_NONE = 0,
ACCESS_CREDENTIAL_DISABLE_DISABLE = 1,
ACCESS_CREDENTIAL_DISABLE_DISABLE_MANUAL = 2,
ACCESS_CREDENTIAL_DISABLE_DISABLE_LOCKOUT = 3
} BACNET_ACCESS_CREDENTIAL_DISABLE;
/* Access Credential Disable Reason */
typedef enum {
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED = 0,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_NEEDS_PROVISIONING = 1,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_UNASSIGNED = 2,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_NOT_YET_ACTIVE = 3,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_EXPIRED = 4,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_LOCKOUT = 5,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_MAX_DAYS = 6,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_MAX_USES = 7,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_INACTIVITY = 8,
ACCESS_CREDENTIAL_DISABLE_REASON_DISABLED_MANUAL = 9
} BACNET_ACCESS_CREDENTIAL_DISABLE_REASON;
/* Authentication Factor Type */
typedef enum {
AUTHENTICATION_FACTOR_TYPE_UNDEFINED = 0,
AUTHENTICATION_FACTOR_TYPE_ERROR = 1,
AUTHENTICATION_FACTOR_TYPE_CUSTOM = 2,
AUTHENTICATION_FACTOR_TYPE_SIMPLE_NUMBER16 = 3,
AUTHENTICATION_FACTOR_TYPE_SIMPLE_NUMBER32 = 4,
AUTHENTICATION_FACTOR_TYPE_SIMPLE_NUMBER56 = 5,
AUTHENTICATION_FACTOR_TYPE_SIMPLE_ALPHA_NUMERIC = 6,
AUTHENTICATION_FACTOR_TYPE_ABA_TRACK2 = 7,
AUTHENTICATION_FACTOR_TYPE_WIEGAND26 = 8,
AUTHENTICATION_FACTOR_TYPE_WIEGAND37 = 9,
AUTHENTICATION_FACTOR_TYPE_WIEGAND37_FACILITY = 10,
AUTHENTICATION_FACTOR_TYPE_FACILITY16_CARD32 = 11,
AUTHENTICATION_FACTOR_TYPE_FACILITY32_CARD32 = 12,
AUTHENTICATION_FACTOR_TYPE_FASC_N = 13,
AUTHENTICATION_FACTOR_TYPE_FASC_N_BCD = 14,
AUTHENTICATION_FACTOR_TYPE_FASC_N_LARGE = 15,
AUTHENTICATION_FACTOR_TYPE_FASC_N_LARGE_BCD = 16,
AUTHENTICATION_FACTOR_TYPE_GSA75 = 17,
AUTHENTICATION_FACTOR_TYPE_CHUID = 18,
AUTHENTICATION_FACTOR_TYPE_CHUID_FULL = 19,
AUTHENTICATION_FACTOR_TYPE_GUID = 20,
AUTHENTICATION_FACTOR_TYPE_CBEFF_A = 21,
AUTHENTICATION_FACTOR_TYPE_CBEFF_B = 22,
AUTHENTICATION_FACTOR_TYPE_CBEFF_C = 23,
AUTHENTICATION_FACTOR_TYPE_USER_PASSWORD = 24
} BACNET_AUTHENTICATION_FACTOR_TYPE;
/* Authorization Exemption */
typedef enum {
AUTHORIZATION_EXEMPTION_PASSBACK = 0,
AUTHORIZATION_EXEMPTION_OCCUPANCY_CHECK = 1,
AUTHORIZATION_EXEMPTION_ACCESS_RIGHTS = 2,
AUTHORIZATION_EXEMPTION_LOCKOUT = 3,
AUTHORIZATION_EXEMPTION_DENY = 4,
AUTHORIZATION_EXEMPTION_VERIFICATION = 5,
AUTHORIZATION_EXEMPTION_AUTHORIZATION_DELAY = 6
} BACNET_AUTHORIZATION_EXEMPTION;
/* The Network Reject Reasons for NETWORK_MESSAGE_REJECT_MESSAGE_TO_NETWORK */
typedef enum {
NETWORK_REJECT_UNKNOWN_ERROR = 0,
@@ -0,0 +1,63 @@
/**************************************************************************
*
* 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 BACNET_CREDENTIAL_AUTHENTICATION_FACTOR_H
#define BACNET_CREDENTIAL_AUTHENTICATION_FACTOR_H
#include <stdbool.h>
#include <stdint.h>
#include "bacdef.h"
#include "bacapp.h"
#include "authentication_factor.h"
typedef struct {
BACNET_ACCESS_AUTHENTICATION_FACTOR_DISABLE disable;
BACNET_AUTHENTICATION_FACTOR authentication_factor;
} BACNET_CREDENTIAL_AUTHENTICATION_FACTOR;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bacapp_encode_credential_authentication_factor(
uint8_t * apdu,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
int bacapp_encode_context_credential_authentication_factor(
uint8_t * apdu,
uint8_t tag,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
int bacapp_decode_credential_authentication_factor(
uint8_t * apdu,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
int bacapp_decode_context_credential_authentication_factor(
uint8_t * apdu,
uint8_t tag,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+5
View File
@@ -75,6 +75,11 @@ CORE_SRC = \
$(BACNET_CORE)/timestamp.c \
$(BACNET_CORE)/lighting.c \
$(BACNET_CORE)/bacsec.c \
$(BACNET_CORE)/access_rule.c \
$(BACNET_CORE)/assigned_access_rights.c \
$(BACNET_CORE)/authentication_factor_format.c \
$(BACNET_CORE)/authentication_factor.c \
$(BACNET_CORE)/credential_authentication_factor.c \
$(BACNET_CORE)/version.c
HANDLER_SRC = \
+185
View File
@@ -0,0 +1,185 @@
/**************************************************************************
*
* 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 <stdint.h>
#include <stdbool.h>
#include "access_rule.h"
#include "bacdcode.h"
int bacapp_encode_access_rule(
uint8_t * apdu,
BACNET_ACCESS_RULE * rule)
{
int len;
int apdu_len = 0;
len = encode_context_enumerated(&apdu[0], 0, rule->time_range_specifier);
apdu_len += len;
if (rule->time_range_specifier == TIME_RANGE_SPECIFIER_SPECIFIED) {
len =
bacapp_encode_context_device_obj_property_ref(&apdu[apdu_len], 1,
&rule->time_range);
if (len > 0)
apdu_len += len;
else
return -1;
}
len =
encode_context_enumerated(&apdu[apdu_len], 2,
rule->location_specifier);
apdu_len += len;
if (rule->location_specifier == LOCATION_SPECIFIER_SPECIFIED) {
len =
bacapp_encode_context_device_obj_property_ref(&apdu[apdu_len], 3,
&rule->location);
if (len > 0)
apdu_len += len;
else
return -1;
}
len = encode_context_boolean(&apdu[apdu_len], 4, rule->enable);
apdu_len += len;
return apdu_len;
}
int bacapp_encode_context_access_rule(
uint8_t * apdu,
uint8_t tag_number,
BACNET_ACCESS_RULE * rule)
{
int len;
int apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
len = bacapp_encode_access_rule(&apdu[apdu_len], rule);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
return apdu_len;
}
int bacapp_decode_access_rule(
uint8_t * apdu,
BACNET_ACCESS_RULE * rule)
{
int len;
int apdu_len = 0;
if (decode_is_context_tag(&apdu[apdu_len], 0)) {
len =
decode_context_enumerated(&apdu[apdu_len], 0,
&rule->time_range_specifier);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
if (rule->time_range_specifier == TIME_RANGE_SPECIFIER_SPECIFIED) {
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
len =
bacapp_decode_context_device_obj_property_ref(&apdu[apdu_len],
1, &rule->time_range);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
}
if (decode_is_context_tag(&apdu[apdu_len], 2)) {
len =
decode_context_enumerated(&apdu[apdu_len], 2,
&rule->location_specifier);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
if (rule->location_specifier == LOCATION_SPECIFIER_SPECIFIED) {
if (decode_is_context_tag(&apdu[apdu_len], 3)) {
len =
bacapp_decode_context_device_obj_property_ref(&apdu[apdu_len],
3, &rule->location);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
}
if (decode_is_context_tag(&apdu[apdu_len], 4)) {
len = decode_context_boolean2(&apdu[apdu_len], 4, &rule->enable);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
return apdu_len;
}
int bacapp_decode_context_access_rule(
uint8_t * apdu,
uint8_t tag_number,
BACNET_ACCESS_RULE * rule)
{
int len = 0;
int section_length;
if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
len++;
section_length = bacapp_decode_access_rule(&apdu[len], rule);
if (section_length == -1) {
len = -1;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
len++;
} else {
len = -1;
}
}
} else {
len = -1;
}
return len;
}
+131
View File
@@ -0,0 +1,131 @@
/**************************************************************************
*
* 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 "assigned_access_rights.h"
#include "bacdcode.h"
int bacapp_encode_assigned_access_rights(
uint8_t * apdu,
BACNET_ASSIGNED_ACCESS_RIGHTS * aar)
{
int len;
int apdu_len = 0;
len =
bacapp_encode_context_device_obj_ref(&apdu[apdu_len], 0,
&aar->assigned_access_rights);
if (len < 0)
return -1;
else
apdu_len += len;
len = encode_context_boolean(&apdu[apdu_len], 1, aar->enable);
if (len < 0)
return -1;
else
apdu_len += len;
return apdu_len;
}
int bacapp_encode_context_assigned_access_rights(
uint8_t * apdu,
uint8_t tag,
BACNET_ASSIGNED_ACCESS_RIGHTS * aar)
{
int len;
int apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], tag);
apdu_len += len;
len = bacapp_encode_assigned_access_rights(&apdu[apdu_len], aar);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag);
apdu_len += len;
return apdu_len;
}
int bacapp_decode_assigned_access_rights(
uint8_t * apdu,
BACNET_ASSIGNED_ACCESS_RIGHTS * aar)
{
int len;
int apdu_len = 0;
if (decode_is_context_tag(&apdu[apdu_len], 0)) {
len =
bacapp_decode_context_device_obj_ref(&apdu[apdu_len], 0,
&aar->assigned_access_rights);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
len = decode_context_boolean2(&apdu[apdu_len], 1, &aar->enable);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
return apdu_len;
}
int bacapp_decode_context_assigned_access_rights(
uint8_t * apdu,
uint8_t tag,
BACNET_ASSIGNED_ACCESS_RIGHTS * aar)
{
int len = 0;
int section_length;
if (decode_is_opening_tag_number(&apdu[len], tag)) {
len++;
section_length = bacapp_decode_assigned_access_rights(&apdu[len], aar);
if (section_length == -1) {
len = -1;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag)) {
len++;
} else {
len = -1;
}
}
} else {
len = -1;
}
return len;
}
+142
View File
@@ -0,0 +1,142 @@
/**************************************************************************
*
* 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 "authentication_factor.h"
#include "bacdcode.h"
int bacapp_encode_authentication_factor(
uint8_t * apdu,
BACNET_AUTHENTICATION_FACTOR * af)
{
int len;
int apdu_len = 0;
len = encode_context_enumerated(&apdu[apdu_len], 0, af->format_type);
if (len < 0)
return -1;
else
apdu_len += len;
len = encode_context_unsigned(&apdu[apdu_len], 1, af->format_class);
if (len < 0)
return -1;
else
apdu_len += len;
len = encode_context_octet_string(&apdu[apdu_len], 2, &af->value);
if (len < 0)
return -1;
else
apdu_len += len;
return apdu_len;
}
int bacapp_encode_context_authentication_factor(
uint8_t * apdu,
uint8_t tag,
BACNET_AUTHENTICATION_FACTOR * af)
{
int len;
int apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], tag);
apdu_len += len;
len = bacapp_encode_authentication_factor(&apdu[apdu_len], af);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag);
apdu_len += len;
return apdu_len;
}
int bacapp_decode_authentication_factor(
uint8_t * apdu,
BACNET_AUTHENTICATION_FACTOR * af)
{
int len;
int apdu_len = 0;
if (decode_is_context_tag(&apdu[apdu_len], 0)) {
len = decode_context_enumerated(&apdu[apdu_len], 0, &af->format_type);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
len = decode_context_unsigned(&apdu[apdu_len], 1, &af->format_class);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
if (decode_is_context_tag(&apdu[apdu_len], 2)) {
len = decode_context_octet_string(&apdu[apdu_len], 2, &af->value);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
return apdu_len;
}
int bacapp_decode_context_authentication_factor(
uint8_t * apdu,
uint8_t tag,
BACNET_AUTHENTICATION_FACTOR * af)
{
int len = 0;
int section_length;
if (decode_is_opening_tag_number(&apdu[len], tag)) {
len++;
section_length = bacapp_decode_authentication_factor(&apdu[len], af);
if (section_length == -1) {
len = -1;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag)) {
len++;
} else {
len = -1;
}
}
} else {
len = -1;
}
return len;
}
@@ -0,0 +1,151 @@
/**************************************************************************
*
* 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 "bacdcode.h"
#include "authentication_factor_format.h"
int bacapp_encode_authentication_factor_format(
uint8_t * apdu,
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff)
{
int len;
int apdu_len = 0;
len = encode_context_enumerated(&apdu[apdu_len], 0, aff->format_type);
if (len < 0)
return -1;
else
apdu_len += len;
if (aff->format_type == AUTHENTICATION_FACTOR_TYPE_CUSTOM) {
len = encode_context_unsigned(&apdu[apdu_len], 1, aff->vendor_id);
if (len < 0)
return -1;
else
apdu_len += len;
len = encode_context_unsigned(&apdu[apdu_len], 2, aff->vendor_format);
if (len < 0)
return -1;
else
apdu_len += len;
}
return apdu_len;
}
int bacapp_encode_context_authentication_factor_format(
uint8_t * apdu,
uint8_t tag,
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff)
{
int len;
int apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], tag);
apdu_len += len;
len = bacapp_encode_authentication_factor_format(&apdu[apdu_len], aff);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag);
apdu_len += len;
return apdu_len;
}
int bacapp_decode_authentication_factor_format(
uint8_t * apdu,
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff)
{
int len;
int apdu_len = 0;
if (decode_is_context_tag(&apdu[apdu_len], 0)) {
len =
decode_context_enumerated(&apdu[apdu_len], 0,
&aff->format_type);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
len = decode_context_unsigned(&apdu[apdu_len], 1, &aff->vendor_id);
if (len < 0)
return -1;
else
apdu_len += len;
if ((aff->format_type != AUTHENTICATION_FACTOR_TYPE_CUSTOM)
&& (aff->vendor_id != 0))
return -1;
}
if (decode_is_context_tag(&apdu[apdu_len], 2)) {
len = decode_context_unsigned(&apdu[apdu_len], 2, &aff->vendor_format);
if (len < 0)
return -1;
else
apdu_len += len;
if ((aff->format_type != AUTHENTICATION_FACTOR_TYPE_CUSTOM)
&& (aff->vendor_format != 0))
return -1;
}
return apdu_len;
}
int bacapp_decode_context_authentication_factor_format(
uint8_t * apdu,
uint8_t tag,
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff)
{
int len = 0;
int section_length;
if (decode_is_opening_tag_number(&apdu[len], tag)) {
len++;
section_length =
bacapp_decode_authentication_factor_format(&apdu[len], aff);
if (section_length == -1) {
len = -1;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag)) {
len++;
} else {
len = -1;
}
}
} else {
len = -1;
}
return len;
}
+1 -1
View File
@@ -812,7 +812,7 @@ INDTEXT_DATA bacnet_property_names[] = {
,
{PROP_EXIT_POINTS, "exit-points"}
,
{PROP_EXPIRY_TIME, "expiry-time"}
{PROP_EXPIRATION_TIME, "expiration-time"}
,
{PROP_EXTENDED_TIME_ENABLE, "extended-time-enable"}
,
@@ -0,0 +1,132 @@
/**************************************************************************
*
* 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 "credential_authentication_factor.h"
#include "bacdcode.h"
int bacapp_encode_credential_authentication_factor(
uint8_t * apdu,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf)
{
int len;
int apdu_len = 0;
len = encode_context_enumerated(&apdu[apdu_len], 0, caf->disable);
if (len < 0)
return -1;
else
apdu_len += len;
len =
bacapp_encode_context_authentication_factor(&apdu[apdu_len], 1,
&caf->authentication_factor);
if (len < 0)
return -1;
else
apdu_len += len;
return apdu_len;
}
int bacapp_encode_context_credential_authentication_factor(
uint8_t * apdu,
uint8_t tag,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf)
{
int len;
int apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], tag);
apdu_len += len;
len = bacapp_encode_credential_authentication_factor(&apdu[apdu_len], caf);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag);
apdu_len += len;
return apdu_len;
}
int bacapp_decode_credential_authentication_factor(
uint8_t * apdu,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf)
{
int len;
int apdu_len = 0;
if (decode_is_context_tag(&apdu[apdu_len], 0)) {
len = decode_context_enumerated(&apdu[apdu_len], 0, &caf->disable);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
len =
bacapp_decode_context_authentication_factor(&apdu[apdu_len], 1,
&caf->authentication_factor);
if (len < 0)
return -1;
else
apdu_len += len;
} else
return -1;
return apdu_len;
}
int bacapp_decode_context_credential_authentication_factor(
uint8_t * apdu,
uint8_t tag,
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf)
{
int len = 0;
int section_length;
if (decode_is_opening_tag_number(&apdu[len], tag)) {
len++;
section_length =
bacapp_decode_credential_authentication_factor(&apdu[len], caf);
if (section_length == -1) {
len = -1;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag)) {
len++;
} else {
len = -1;
}
}
} else {
len = -1;
}
return len;
}
+39 -1
View File
@@ -206,7 +206,45 @@ wp: logfile test/wp.mak
( ./test/wp >> ${LOGFILE} )
$(MAKE) -s -C test -f wp.mak clean
objects: ai ao av bi bo bv csv lc lo lso lsp mso msv ms-input osv piv command
objects: ai ao av bi bo bv csv lc lo lso lsp \
mso msv ms-input osv piv command \
access_credential access_door access_point access_rights \
access_user access_zone credential_data_input
access_credential: logfile demo/object/access_credential.mak
$(MAKE) -s -C demo/object -f access_credential.mak clean all
( ./demo/object/access_credential >> ${LOGFILE} )
$(MAKE) -s -C demo/object -f access_credential.mak clean
access_door: logfile demo/object/access_door.mak
$(MAKE) -s -C demo/object -f access_door.mak clean all
( ./demo/object/access_door >> ${LOGFILE} )
$(MAKE) -s -C demo/object -f access_door.mak clean
access_point: logfile demo/object/access_point.mak
$(MAKE) -s -C demo/object -f access_point.mak clean all
( ./demo/object/access_point >> ${LOGFILE} )
$(MAKE) -s -C demo/object -f access_point.mak clean
access_rights: logfile demo/object/access_rights.mak
$(MAKE) -s -C demo/object -f access_rights.mak clean all
( ./demo/object/access_rights >> ${LOGFILE} )
$(MAKE) -s -C demo/object -f access_rights.mak clean
access_user: logfile demo/object/access_user.mak
$(MAKE) -s -C demo/object -f access_user.mak clean all
( ./demo/object/access_user >> ${LOGFILE} )
$(MAKE) -s -C demo/object -f access_user.mak clean
access_zone: logfile demo/object/access_zone.mak
$(MAKE) -s -C demo/object -f access_zone.mak clean all
( ./demo/object/access_zone >> ${LOGFILE} )
$(MAKE) -s -C demo/object -f access_zone.mak clean
credential_data_input: logfile demo/object/credential_data_input.mak
$(MAKE) -s -C demo/object -f credential_data_input.mak clean all
( ./demo/object/credential_data_input >> ${LOGFILE} )
$(MAKE) -s -C demo/object -f credential_data_input.mak clean
ai: logfile demo/object/ai.mak
$(MAKE) -s -C demo/object -f ai.mak clean all