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:
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 = \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user