added clang format C and H files.
This commit is contained in:
+113
-146
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* 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 */
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_credential.h"
|
||||
#include "handlers.h"
|
||||
@@ -43,35 +43,28 @@ static bool Access_Credential_Initialized = false;
|
||||
static ACCESS_CREDENTIAL_DESCR ac_descr[MAX_ACCESS_CREDENTIALS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_CREDENTIAL_STATUS,
|
||||
PROP_REASON_FOR_DISABLE,
|
||||
PROP_AUTHENTICATION_FACTORS,
|
||||
PROP_ACTIVATION_TIME,
|
||||
PROP_EXPIRATION_TIME,
|
||||
PROP_CREDENTIAL_DISABLE,
|
||||
PROP_ASSIGNED_ACCESS_RIGHTS,
|
||||
-1
|
||||
};
|
||||
static const int Properties_Required[] = {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_Optional[] = {-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Access_Credential_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Access_Credential_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -83,8 +76,7 @@ void Access_Credential_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Credential_Init(
|
||||
void)
|
||||
void Access_Credential_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -92,7 +84,8 @@ void Access_Credential_Init(
|
||||
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].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;
|
||||
@@ -110,8 +103,7 @@ void Access_Credential_Init(
|
||||
/* 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)
|
||||
bool Access_Credential_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_CREDENTIALS)
|
||||
return true;
|
||||
@@ -121,8 +113,7 @@ bool Access_Credential_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Credential_Count(
|
||||
void)
|
||||
unsigned Access_Credential_Count(void)
|
||||
{
|
||||
return MAX_ACCESS_CREDENTIALS;
|
||||
}
|
||||
@@ -130,8 +121,7 @@ unsigned Access_Credential_Count(
|
||||
/* 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)
|
||||
uint32_t Access_Credential_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -139,8 +129,7 @@ uint32_t Access_Credential_Index_To_Instance(
|
||||
/* 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 Access_Credential_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_CREDENTIALS;
|
||||
|
||||
@@ -151,16 +140,15 @@ unsigned Access_Credential_Instance_To_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)
|
||||
bool Access_Credential_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
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);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -168,11 +156,10 @@ bool Access_Credential_Object_Name(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Credential_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Access_Credential_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -184,29 +171,25 @@ int Access_Credential_Read_Property(
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index =
|
||||
Access_Credential_Instance_To_Index(rpdata->object_instance);
|
||||
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);
|
||||
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);
|
||||
&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);
|
||||
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);
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0], ac_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
@@ -217,20 +200,17 @@ int Access_Credential_Read_Property(
|
||||
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);
|
||||
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);
|
||||
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]);
|
||||
len = encode_application_enumerated(
|
||||
&apdu[0], ac_descr[object_index].reason_for_disable[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
@@ -243,14 +223,13 @@ int Access_Credential_Read_Property(
|
||||
break;
|
||||
case PROP_AUTHENTICATION_FACTORS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ac_descr[object_index].auth_factors_count);
|
||||
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]);
|
||||
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 {
|
||||
@@ -263,11 +242,9 @@ int Access_Credential_Read_Property(
|
||||
} 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]);
|
||||
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;
|
||||
@@ -276,31 +253,28 @@ int Access_Credential_Read_Property(
|
||||
}
|
||||
break;
|
||||
case PROP_ACTIVATION_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_datetime(&apdu[0],
|
||||
&ac_descr[object_index].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);
|
||||
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);
|
||||
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],
|
||||
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],
|
||||
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;
|
||||
@@ -314,10 +288,10 @@ int Access_Credential_Read_Property(
|
||||
} 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]);
|
||||
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;
|
||||
@@ -333,9 +307,9 @@ int Access_Credential_Read_Property(
|
||||
}
|
||||
/* 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->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;
|
||||
@@ -345,18 +319,16 @@ int Access_Credential_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Credential_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Access_Credential_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -365,9 +337,9 @@ bool Access_Credential_Write_Property(
|
||||
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)) {
|
||||
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;
|
||||
@@ -378,7 +350,7 @@ bool Access_Credential_Write_Property(
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
ac_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
@@ -408,17 +380,14 @@ bool Access_Credential_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -428,10 +397,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessCredential(
|
||||
Test * pTest)
|
||||
void testAccessCredential(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -458,8 +426,7 @@ void testAccessCredential(
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_CREDENTIAL
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -471,7 +438,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+133
-184
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* 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 */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_door.h"
|
||||
#include "handlers.h"
|
||||
@@ -42,40 +42,30 @@ static bool Access_Door_Initialized = false;
|
||||
static ACCESS_DOOR_DESCR ad_descr[MAX_ACCESS_DOORS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_PRIORITY_ARRAY,
|
||||
PROP_RELINQUISH_DEFAULT,
|
||||
PROP_DOOR_PULSE_TIME,
|
||||
PROP_DOOR_EXTENDED_PULSE_TIME,
|
||||
PROP_DOOR_OPEN_TOO_LONG_TIME,
|
||||
-1
|
||||
};
|
||||
static const int Properties_Required[] = {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
|
||||
};
|
||||
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
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Access_Door_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Access_Door_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -87,8 +77,7 @@ void Access_Door_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Door_Init(
|
||||
void)
|
||||
void Access_Door_Init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
@@ -104,10 +93,10 @@ void Access_Door_Init(
|
||||
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_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;
|
||||
@@ -123,8 +112,7 @@ void Access_Door_Init(
|
||||
/* 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)
|
||||
bool Access_Door_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_DOORS)
|
||||
return true;
|
||||
@@ -134,8 +122,7 @@ bool Access_Door_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Door_Count(
|
||||
void)
|
||||
unsigned Access_Door_Count(void)
|
||||
{
|
||||
return MAX_ACCESS_DOORS;
|
||||
}
|
||||
@@ -143,8 +130,7 @@ unsigned Access_Door_Count(
|
||||
/* 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)
|
||||
uint32_t Access_Door_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -152,8 +138,7 @@ uint32_t Access_Door_Index_To_Instance(
|
||||
/* 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 Access_Door_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_DOORS;
|
||||
|
||||
@@ -163,8 +148,7 @@ unsigned Access_Door_Instance_To_Index(
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_DOOR_VALUE Access_Door_Present_Value(
|
||||
uint32_t object_instance)
|
||||
BACNET_DOOR_VALUE Access_Door_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
unsigned i = 0;
|
||||
@@ -183,12 +167,11 @@ BACNET_DOOR_VALUE Access_Door_Present_Value(
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned Access_Door_Present_Value_Priority(
|
||||
uint32_t object_instance)
|
||||
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 */
|
||||
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) {
|
||||
@@ -203,10 +186,8 @@ unsigned Access_Door_Present_Value_Priority(
|
||||
return priority;
|
||||
}
|
||||
|
||||
bool Access_Door_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_DOOR_VALUE value,
|
||||
unsigned priority)
|
||||
bool Access_Door_Present_Value_Set(uint32_t object_instance,
|
||||
BACNET_DOOR_VALUE value, unsigned priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -214,8 +195,7 @@ bool Access_Door_Present_Value_Set(
|
||||
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) &&
|
||||
(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;
|
||||
@@ -232,9 +212,8 @@ bool Access_Door_Present_Value_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Access_Door_Present_Value_Relinquish(
|
||||
uint32_t object_instance,
|
||||
unsigned priority)
|
||||
bool Access_Door_Present_Value_Relinquish(uint32_t object_instance,
|
||||
unsigned priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -242,7 +221,7 @@ bool Access_Door_Present_Value_Relinquish(
|
||||
index = Access_Door_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ACCESS_DOORS) {
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ )) {
|
||||
(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
|
||||
@@ -257,8 +236,7 @@ bool Access_Door_Present_Value_Relinquish(
|
||||
return status;
|
||||
}
|
||||
|
||||
BACNET_DOOR_VALUE Access_Door_Relinquish_Default(
|
||||
uint32_t object_instance)
|
||||
BACNET_DOOR_VALUE Access_Door_Relinquish_Default(uint32_t object_instance)
|
||||
{
|
||||
BACNET_DOOR_VALUE status = -1;
|
||||
unsigned index = 0;
|
||||
@@ -271,24 +249,21 @@ BACNET_DOOR_VALUE Access_Door_Relinquish_Default(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Door_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Access_Door_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
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);
|
||||
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)
|
||||
bool Access_Door_Out_Of_Service(uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
@@ -301,9 +276,7 @@ bool Access_Door_Out_Of_Service(
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Access_Door_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
void Access_Door_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -314,11 +287,10 @@ void Access_Door_Out_Of_Service_Set(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Door_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Access_Door_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -334,9 +306,8 @@ int Access_Door_Read_Property(
|
||||
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);
|
||||
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);
|
||||
@@ -348,9 +319,8 @@ int Access_Door_Read_Property(
|
||||
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));
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], Access_Door_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
@@ -362,14 +332,12 @@ int Access_Door_Read_Property(
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
@@ -388,8 +356,8 @@ int Access_Door_Read_Property(
|
||||
if (ad_descr[object_index].value_active[i])
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else
|
||||
len =
|
||||
encode_application_enumerated(&apdu[apdu_len],
|
||||
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)
|
||||
@@ -406,8 +374,8 @@ int Access_Door_Read_Property(
|
||||
if (ad_descr[object_index].value_active[i])
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[apdu_len],
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[apdu_len],
|
||||
ad_descr[object_index].priority_array[i]);
|
||||
}
|
||||
} else {
|
||||
@@ -418,49 +386,41 @@ int Access_Door_Read_Property(
|
||||
}
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], ad_descr[object_index].door_alarm_state);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -480,18 +440,16 @@ int Access_Door_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Door_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Access_Door_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -513,9 +471,9 @@ bool Access_Door_Write_Property(
|
||||
/* 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);
|
||||
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
|
||||
@@ -527,13 +485,12 @@ bool Access_Door_Write_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);
|
||||
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);
|
||||
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;
|
||||
@@ -544,18 +501,17 @@ bool Access_Door_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Access_Door_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@@ -566,10 +522,9 @@ bool Access_Door_Write_Property(
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@@ -580,10 +535,9 @@ bool Access_Door_Write_Property(
|
||||
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);
|
||||
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;
|
||||
@@ -618,17 +572,14 @@ bool Access_Door_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -638,10 +589,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessDoor(
|
||||
Test * pTest)
|
||||
void testAccessDoor(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -668,8 +618,7 @@ void testAccessDoor(
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_DOOR
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -681,7 +630,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+84
-122
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* 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 */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_point.h"
|
||||
#include "handlers.h"
|
||||
@@ -60,21 +60,14 @@ static const int Properties_Required[] = {
|
||||
PROP_ACCESS_EVENT_CREDENTIAL,
|
||||
PROP_ACCESS_DOORS,
|
||||
PROP_PRIORITY_FOR_WRITING,
|
||||
-1
|
||||
};
|
||||
-1};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Optional[] = {-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Access_Point_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Access_Point_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -86,8 +79,7 @@ void Access_Point_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Point_Init(
|
||||
void)
|
||||
void Access_Point_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -98,8 +90,7 @@ void Access_Point_Init(
|
||||
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].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;
|
||||
@@ -108,7 +99,7 @@ void Access_Point_Init(
|
||||
/* 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 */
|
||||
ap_descr[i].priority_for_writing = 16; /* lowest possible for now */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,8 +109,7 @@ void Access_Point_Init(
|
||||
/* 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)
|
||||
bool Access_Point_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_POINTS)
|
||||
return true;
|
||||
@@ -129,8 +119,7 @@ bool Access_Point_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Point_Count(
|
||||
void)
|
||||
unsigned Access_Point_Count(void)
|
||||
{
|
||||
return MAX_ACCESS_POINTS;
|
||||
}
|
||||
@@ -138,8 +127,7 @@ unsigned Access_Point_Count(
|
||||
/* 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)
|
||||
uint32_t Access_Point_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -147,8 +135,7 @@ uint32_t Access_Point_Index_To_Instance(
|
||||
/* 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 Access_Point_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_POINTS;
|
||||
|
||||
@@ -159,24 +146,22 @@ unsigned Access_Point_Instance_To_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)
|
||||
bool Access_Point_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
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);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Access_Point_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
bool Access_Point_Out_Of_Service(uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
@@ -189,9 +174,7 @@ bool Access_Point_Out_Of_Service(
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Access_Point_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
void Access_Point_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -202,11 +185,10 @@ void Access_Point_Out_Of_Service_Set(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Point_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Access_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -222,9 +204,8 @@ int Access_Point_Read_Property(
|
||||
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);
|
||||
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);
|
||||
@@ -245,69 +226,58 @@ int Access_Point_Read_Property(
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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],
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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]);
|
||||
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 {
|
||||
@@ -319,10 +289,9 @@ int Access_Point_Read_Property(
|
||||
}
|
||||
} 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]);
|
||||
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;
|
||||
@@ -348,17 +317,15 @@ int Access_Point_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Point_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Access_Point_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -404,17 +371,14 @@ bool Access_Point_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -424,10 +388,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessPoint(
|
||||
Test * pTest)
|
||||
void testAccessPoint(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -454,8 +417,7 @@ void testAccessPoint(
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_POINT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -467,7 +429,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+97
-122
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* 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 */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_rights.h"
|
||||
#include "handlers.h"
|
||||
@@ -42,31 +42,23 @@ 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_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_Optional[] = {-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Access_Rights_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Access_Rights_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -78,8 +70,7 @@ void Access_Rights_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Rights_Init(
|
||||
void)
|
||||
void Access_Rights_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -87,7 +78,8 @@ void Access_Rights_Init(
|
||||
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].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;
|
||||
@@ -102,8 +94,7 @@ void Access_Rights_Init(
|
||||
/* 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)
|
||||
bool Access_Rights_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_RIGHTSS)
|
||||
return true;
|
||||
@@ -113,8 +104,7 @@ bool Access_Rights_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Rights_Count(
|
||||
void)
|
||||
unsigned Access_Rights_Count(void)
|
||||
{
|
||||
return MAX_ACCESS_RIGHTSS;
|
||||
}
|
||||
@@ -122,8 +112,7 @@ unsigned Access_Rights_Count(
|
||||
/* 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)
|
||||
uint32_t Access_Rights_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -131,8 +120,7 @@ uint32_t Access_Rights_Index_To_Instance(
|
||||
/* 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 Access_Rights_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_RIGHTSS;
|
||||
|
||||
@@ -143,16 +131,15 @@ unsigned Access_Rights_Instance_To_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)
|
||||
bool Access_Rights_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
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);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -160,11 +147,10 @@ bool Access_Rights_Object_Name(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Rights_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Access_Rights_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -179,9 +165,8 @@ int Access_Rights_Read_Property(
|
||||
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);
|
||||
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);
|
||||
@@ -193,9 +178,8 @@ int Access_Rights_Read_Property(
|
||||
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);
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0], ar_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
@@ -206,26 +190,24 @@ int Access_Rights_Read_Property(
|
||||
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);
|
||||
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);
|
||||
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],
|
||||
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],
|
||||
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;
|
||||
@@ -239,10 +221,10 @@ int Access_Rights_Read_Property(
|
||||
} 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]);
|
||||
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;
|
||||
@@ -252,15 +234,15 @@ int Access_Rights_Read_Property(
|
||||
break;
|
||||
case PROP_POSITIVE_ACCESS_RULES:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[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],
|
||||
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;
|
||||
@@ -274,10 +256,10 @@ int Access_Rights_Read_Property(
|
||||
} 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]);
|
||||
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;
|
||||
@@ -293,9 +275,9 @@ int Access_Rights_Read_Property(
|
||||
}
|
||||
/* 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->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;
|
||||
@@ -305,18 +287,16 @@ int Access_Rights_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Rights_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Access_Rights_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -325,9 +305,9 @@ bool Access_Rights_Write_Property(
|
||||
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)) {
|
||||
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;
|
||||
@@ -337,7 +317,7 @@ bool Access_Rights_Write_Property(
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
ar_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
@@ -363,17 +343,14 @@ bool Access_Rights_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -383,10 +360,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessRights(
|
||||
Test * pTest)
|
||||
void testAccessRights(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -413,8 +389,7 @@ void testAccessRights(
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_RIGHTS
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -426,7 +401,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+66
-98
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* 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 */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_user.h"
|
||||
#include "handlers.h"
|
||||
@@ -43,29 +43,16 @@ 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
|
||||
};
|
||||
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_Optional[] = {-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Access_User_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Access_User_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -77,8 +64,7 @@ void Access_User_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_User_Init(
|
||||
void)
|
||||
void Access_User_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -86,7 +72,8 @@ void Access_User_Init(
|
||||
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].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;
|
||||
@@ -100,8 +87,7 @@ void Access_User_Init(
|
||||
/* 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)
|
||||
bool Access_User_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_USERS)
|
||||
return true;
|
||||
@@ -111,8 +97,7 @@ bool Access_User_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_User_Count(
|
||||
void)
|
||||
unsigned Access_User_Count(void)
|
||||
{
|
||||
return MAX_ACCESS_USERS;
|
||||
}
|
||||
@@ -120,8 +105,7 @@ unsigned Access_User_Count(
|
||||
/* 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)
|
||||
uint32_t Access_User_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -129,8 +113,7 @@ uint32_t Access_User_Index_To_Instance(
|
||||
/* 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 Access_User_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_USERS;
|
||||
|
||||
@@ -141,16 +124,14 @@ unsigned Access_User_Instance_To_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)
|
||||
bool Access_User_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
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);
|
||||
sprintf(text_string, "ACCESS USER %lu", (unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -158,11 +139,10 @@ bool Access_User_Object_Name(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_User_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Access_User_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -177,9 +157,8 @@ int Access_User_Read_Property(
|
||||
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);
|
||||
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);
|
||||
@@ -191,9 +170,8 @@ int Access_User_Read_Property(
|
||||
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);
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0], au_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
@@ -204,20 +182,17 @@ int Access_User_Read_Property(
|
||||
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);
|
||||
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);
|
||||
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]);
|
||||
len = bacapp_encode_device_obj_ref(
|
||||
&apdu[0], &au_descr[object_index].credentials[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
@@ -245,18 +220,16 @@ int Access_User_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_User_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Access_User_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -275,7 +248,7 @@ bool Access_User_Write_Property(
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
au_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
@@ -301,17 +274,14 @@ bool Access_User_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -321,10 +291,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessUser(
|
||||
Test * pTest)
|
||||
void testAccessUser(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -351,8 +320,7 @@ void testAccessUser(
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_USER
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -364,7 +332,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+76
-116
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* 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 */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_zone.h"
|
||||
#include "handlers.h"
|
||||
@@ -43,32 +43,17 @@ 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
|
||||
};
|
||||
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_Optional[] = {-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Access_Zone_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Access_Zone_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -80,8 +65,7 @@ void Access_Zone_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Zone_Init(
|
||||
void)
|
||||
void Access_Zone_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -89,7 +73,8 @@ void Access_Zone_Init(
|
||||
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].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;
|
||||
@@ -106,8 +91,7 @@ void Access_Zone_Init(
|
||||
/* 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)
|
||||
bool Access_Zone_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_ZONES)
|
||||
return true;
|
||||
@@ -117,8 +101,7 @@ bool Access_Zone_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Zone_Count(
|
||||
void)
|
||||
unsigned Access_Zone_Count(void)
|
||||
{
|
||||
return MAX_ACCESS_ZONES;
|
||||
}
|
||||
@@ -126,8 +109,7 @@ unsigned Access_Zone_Count(
|
||||
/* 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)
|
||||
uint32_t Access_Zone_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -135,8 +117,7 @@ uint32_t Access_Zone_Index_To_Instance(
|
||||
/* 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 Access_Zone_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_ZONES;
|
||||
|
||||
@@ -147,24 +128,21 @@ unsigned Access_Zone_Instance_To_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)
|
||||
bool Access_Zone_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
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);
|
||||
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)
|
||||
bool Access_Zone_Out_Of_Service(uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
@@ -177,9 +155,7 @@ bool Access_Zone_Out_Of_Service(
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Access_Zone_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
void Access_Zone_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -190,11 +166,10 @@ void Access_Zone_Out_Of_Service_Set(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Zone_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Access_Zone_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -210,9 +185,8 @@ int Access_Zone_Read_Property(
|
||||
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);
|
||||
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);
|
||||
@@ -224,14 +198,12 @@ int Access_Zone_Read_Property(
|
||||
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);
|
||||
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);
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], az_descr[object_index].occupancy_state);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
@@ -243,14 +215,12 @@ int Access_Zone_Read_Property(
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
@@ -258,9 +228,8 @@ int Access_Zone_Read_Property(
|
||||
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]);
|
||||
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 {
|
||||
@@ -273,9 +242,8 @@ int Access_Zone_Read_Property(
|
||||
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]);
|
||||
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 {
|
||||
@@ -303,18 +271,16 @@ int Access_Zone_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Zone_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Access_Zone_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -333,7 +299,7 @@ bool Access_Zone_Write_Property(
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
az_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
@@ -341,10 +307,9 @@ bool Access_Zone_Write_Property(
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@@ -374,17 +339,14 @@ bool Access_Zone_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -394,10 +356,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessZone(
|
||||
Test * pTest)
|
||||
void testAccessZone(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -424,8 +385,7 @@ void testAccessZone(
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_ZONE
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -437,7 +397,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+316
-357
File diff suppressed because it is too large
Load Diff
+105
-137
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Output Objects - customize for your use */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "ao.h"
|
||||
#include "handlers.h"
|
||||
@@ -60,32 +60,24 @@ static bool Out_Of_Service[MAX_ANALOG_OUTPUTS];
|
||||
static bool Analog_Output_Initialized = false;
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_UNITS,
|
||||
PROP_PRIORITY_ARRAY,
|
||||
PROP_RELINQUISH_DEFAULT,
|
||||
-1
|
||||
};
|
||||
static const int Properties_Required[] = {PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_UNITS,
|
||||
PROP_PRIORITY_ARRAY,
|
||||
PROP_RELINQUISH_DEFAULT,
|
||||
-1};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Optional[] = {-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Analog_Output_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Analog_Output_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -97,8 +89,7 @@ void Analog_Output_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Analog_Output_Init(
|
||||
void)
|
||||
void Analog_Output_Init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
@@ -119,8 +110,7 @@ void Analog_Output_Init(
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Output_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Analog_Output_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_OUTPUTS)
|
||||
return true;
|
||||
@@ -130,8 +120,7 @@ bool Analog_Output_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Output_Count(
|
||||
void)
|
||||
unsigned Analog_Output_Count(void)
|
||||
{
|
||||
return MAX_ANALOG_OUTPUTS;
|
||||
}
|
||||
@@ -139,8 +128,7 @@ unsigned Analog_Output_Count(
|
||||
/* 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 Analog_Output_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Analog_Output_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -148,8 +136,7 @@ uint32_t Analog_Output_Index_To_Instance(
|
||||
/* 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 Analog_Output_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Analog_Output_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ANALOG_OUTPUTS;
|
||||
|
||||
@@ -159,8 +146,7 @@ unsigned Analog_Output_Instance_To_Index(
|
||||
return index;
|
||||
}
|
||||
|
||||
float Analog_Output_Present_Value(
|
||||
uint32_t object_instance)
|
||||
float Analog_Output_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
float value = AO_RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
@@ -179,12 +165,11 @@ float Analog_Output_Present_Value(
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned Analog_Output_Present_Value_Priority(
|
||||
uint32_t object_instance)
|
||||
unsigned Analog_Output_Present_Value_Priority(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0; /* instance to index conversion */
|
||||
unsigned i = 0; /* loop counter */
|
||||
unsigned priority = 0; /* return value */
|
||||
unsigned index = 0; /* instance to index conversion */
|
||||
unsigned i = 0; /* loop counter */
|
||||
unsigned priority = 0; /* return value */
|
||||
|
||||
index = Analog_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ANALOG_OUTPUTS) {
|
||||
@@ -199,10 +184,8 @@ unsigned Analog_Output_Present_Value_Priority(
|
||||
return priority;
|
||||
}
|
||||
|
||||
bool Analog_Output_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value,
|
||||
unsigned priority)
|
||||
bool Analog_Output_Present_Value_Set(uint32_t object_instance, float value,
|
||||
unsigned priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -210,9 +193,9 @@ bool Analog_Output_Present_Value_Set(
|
||||
index = Analog_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ANALOG_OUTPUTS) {
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value >= 0.0) && (value <= 100.0)) {
|
||||
Analog_Output_Level[index][priority - 1] = (uint8_t) value;
|
||||
(priority != 6 /* reserved */) && (value >= 0.0) &&
|
||||
(value <= 100.0)) {
|
||||
Analog_Output_Level[index][priority - 1] = (uint8_t)value;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
@@ -226,9 +209,8 @@ bool Analog_Output_Present_Value_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Analog_Output_Present_Value_Relinquish(
|
||||
uint32_t object_instance,
|
||||
unsigned priority)
|
||||
bool Analog_Output_Present_Value_Relinquish(uint32_t object_instance,
|
||||
unsigned priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -236,7 +218,7 @@ bool Analog_Output_Present_Value_Relinquish(
|
||||
index = Analog_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ANALOG_OUTPUTS) {
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ )) {
|
||||
(priority != 6 /* reserved */)) {
|
||||
Analog_Output_Level[index][priority - 1] = AO_LEVEL_NULL;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
@@ -252,24 +234,22 @@ bool Analog_Output_Present_Value_Relinquish(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Analog_Output_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Analog_Output_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ANALOG_OUTPUTS) {
|
||||
sprintf(text_string, "ANALOG OUTPUT %lu",
|
||||
(unsigned long) object_instance);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Analog_Output_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
bool Analog_Output_Out_Of_Service(uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
@@ -282,9 +262,7 @@ bool Analog_Output_Out_Of_Service(
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Analog_Output_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
void Analog_Output_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -295,14 +273,13 @@ void Analog_Output_Out_Of_Service_Set(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Analog_Output_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Analog_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float real_value = (float) 1.414;
|
||||
float real_value = (float)1.414;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
@@ -315,9 +292,8 @@ int Analog_Output_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_OUTPUT,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_ANALOG_OUTPUT, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Analog_Output_Object_Name(rpdata->object_instance, &char_string);
|
||||
@@ -368,9 +344,8 @@ int Analog_Output_Read_Property(
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Analog_Output_Level[object_index][i];
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
len = encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
@@ -387,11 +362,12 @@ int Analog_Output_Read_Property(
|
||||
Analog_Output_Instance_To_Index(rpdata->object_instance);
|
||||
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Analog_Output_Level[object_index][rpdata->array_index -
|
||||
1] == AO_LEVEL_NULL)
|
||||
1] == AO_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value = Analog_Output_Level[object_index]
|
||||
[rpdata->array_index - 1];
|
||||
real_value =
|
||||
Analog_Output_Level[object_index]
|
||||
[rpdata->array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], real_value);
|
||||
}
|
||||
@@ -424,17 +400,15 @@ int Analog_Output_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Output_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -455,9 +429,9 @@ bool Analog_Output_Write_Property(
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
status =
|
||||
Analog_Output_Present_Value_Set(wp_data->object_instance,
|
||||
value.type.Real, wp_data->priority);
|
||||
status = Analog_Output_Present_Value_Set(
|
||||
wp_data->object_instance, value.type.Real,
|
||||
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
|
||||
@@ -469,13 +443,12 @@ bool Analog_Output_Write_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);
|
||||
status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
status =
|
||||
Analog_Output_Present_Value_Relinquish
|
||||
(wp_data->object_instance, wp_data->priority);
|
||||
status = Analog_Output_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;
|
||||
@@ -486,10 +459,10 @@ bool Analog_Output_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Analog_Output_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -512,38 +485,34 @@ bool Analog_Output_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
bool bResult;
|
||||
bool bResult;
|
||||
|
||||
/*
|
||||
* start out assuming success and only set up error
|
||||
* response if validation fails.
|
||||
*/
|
||||
bResult = true;
|
||||
if (pValue->tag != ucExpectedTag) {
|
||||
bResult = false;
|
||||
/*
|
||||
* start out assuming success and only set up error
|
||||
* response if validation fails.
|
||||
*/
|
||||
bResult = true;
|
||||
if (pValue->tag != ucExpectedTag) {
|
||||
bResult = false;
|
||||
*pErrorClass = ERROR_CLASS_PROPERTY;
|
||||
*pErrorCode = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
return (bResult);
|
||||
return (bResult);
|
||||
}
|
||||
|
||||
void testAnalogOutput(
|
||||
Test * pTest)
|
||||
void testAnalogOutput(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -570,8 +539,7 @@ void testAnalogOutput(
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_OUTPUT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -583,7 +551,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+295
-326
File diff suppressed because it is too large
Load Diff
+114
-145
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -57,36 +57,27 @@ static BACNET_FILE_LISTING BACnet_File_Listing[] = {
|
||||
{0, "temp_0.txt"},
|
||||
{1, "temp_1.txt"},
|
||||
{2, "temp_2.txt"},
|
||||
{0, NULL} /* last file indication */
|
||||
{0, NULL} /* last file indication */
|
||||
};
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int bacfile_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_FILE_TYPE,
|
||||
PROP_FILE_SIZE,
|
||||
PROP_MODIFICATION_DATE,
|
||||
PROP_ARCHIVE,
|
||||
PROP_READ_ONLY,
|
||||
PROP_FILE_ACCESS_METHOD,
|
||||
-1
|
||||
};
|
||||
static const int bacfile_Properties_Required[] = {PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_FILE_TYPE,
|
||||
PROP_FILE_SIZE,
|
||||
PROP_MODIFICATION_DATE,
|
||||
PROP_ARCHIVE,
|
||||
PROP_READ_ONLY,
|
||||
PROP_FILE_ACCESS_METHOD,
|
||||
-1};
|
||||
|
||||
static const int bacfile_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
static const int bacfile_Properties_Optional[] = {PROP_DESCRIPTION, -1};
|
||||
|
||||
static const int bacfile_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int bacfile_Properties_Proprietary[] = {-1};
|
||||
|
||||
void BACfile_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void BACfile_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = bacfile_Properties_Required;
|
||||
@@ -98,8 +89,7 @@ void BACfile_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
static char *bacfile_name(
|
||||
uint32_t instance)
|
||||
static char *bacfile_name(uint32_t instance)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
char *filename = NULL;
|
||||
@@ -116,9 +106,8 @@ static char *bacfile_name(
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool bacfile_object_name(
|
||||
uint32_t instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool bacfile_object_name(uint32_t instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
bool status = false;
|
||||
char *filename = NULL;
|
||||
@@ -131,14 +120,12 @@ bool bacfile_object_name(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool bacfile_valid_instance(
|
||||
uint32_t object_instance)
|
||||
bool bacfile_valid_instance(uint32_t object_instance)
|
||||
{
|
||||
return bacfile_name(object_instance) ? true : false;
|
||||
}
|
||||
|
||||
uint32_t bacfile_count(
|
||||
void)
|
||||
uint32_t bacfile_count(void)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
|
||||
@@ -150,8 +137,7 @@ uint32_t bacfile_count(
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t bacfile_index_to_instance(
|
||||
unsigned find_index)
|
||||
uint32_t bacfile_index_to_instance(unsigned find_index)
|
||||
{
|
||||
uint32_t instance = BACNET_MAX_INSTANCE + 1;
|
||||
uint32_t index = 0;
|
||||
@@ -168,8 +154,7 @@ uint32_t bacfile_index_to_instance(
|
||||
return instance;
|
||||
}
|
||||
|
||||
static long fsize(
|
||||
FILE * pFile)
|
||||
static long fsize(FILE *pFile)
|
||||
{
|
||||
long size = 0;
|
||||
long origin = 0;
|
||||
@@ -183,8 +168,7 @@ static long fsize(
|
||||
return (size);
|
||||
}
|
||||
|
||||
unsigned bacfile_file_size(
|
||||
uint32_t object_instance)
|
||||
unsigned bacfile_file_size(uint32_t object_instance)
|
||||
{
|
||||
char *pFilename = NULL;
|
||||
FILE *pFile = NULL;
|
||||
@@ -203,11 +187,10 @@ unsigned bacfile_file_size(
|
||||
}
|
||||
|
||||
/* return the number of bytes used, or -1 on error */
|
||||
int bacfile_read_property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int bacfile_read_property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
char text_string[32] = { "" };
|
||||
int apdu_len = 0; /* return value */
|
||||
char text_string[32] = {""};
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_DATE bdate;
|
||||
BACNET_TIME btime;
|
||||
@@ -220,13 +203,12 @@ int bacfile_read_property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_FILE,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_FILE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
sprintf(text_string, "FILE %lu",
|
||||
(unsigned long) rpdata->object_instance);
|
||||
(unsigned long)rpdata->object_instance);
|
||||
characterstring_init_ansi(&char_string, text_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
@@ -236,7 +218,7 @@ int bacfile_read_property(
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
bacfile_name(rpdata->object_instance));
|
||||
bacfile_name(rpdata->object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
@@ -246,16 +228,15 @@ int bacfile_read_property(
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FILE_SIZE:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
bacfile_file_size(rpdata->object_instance));
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0], bacfile_file_size(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_MODIFICATION_DATE:
|
||||
/* FIXME: get the actual value instead of April Fool's Day */
|
||||
bdate.year = 2006; /* AD */
|
||||
bdate.month = 4; /* 1=Jan */
|
||||
bdate.day = 1; /* 1..31 */
|
||||
bdate.wday = 6; /* 1=Monday */
|
||||
bdate.year = 2006; /* AD */
|
||||
bdate.month = 4; /* 1=Jan */
|
||||
bdate.day = 1; /* 1..31 */
|
||||
bdate.wday = 6; /* 1=Monday */
|
||||
apdu_len = encode_application_date(&apdu[0], &bdate);
|
||||
/* FIXME: get the actual value */
|
||||
btime.hour = 7;
|
||||
@@ -280,9 +261,8 @@ int bacfile_read_property(
|
||||
apdu_len = encode_application_boolean(&apdu[0], true);
|
||||
break;
|
||||
case PROP_FILE_ACCESS_METHOD:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
FILE_RECORD_AND_STREAM_ACCESS);
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], FILE_RECORD_AND_STREAM_ACCESS);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -295,10 +275,9 @@ int bacfile_read_property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool bacfile_write_property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool bacfile_write_property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
@@ -314,9 +293,8 @@ bool bacfile_write_property(
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
len = bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -334,7 +312,7 @@ bool bacfile_write_property(
|
||||
Access Services since the last time the object was archived. */
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
if (value.type.Boolean) {
|
||||
/* FIXME: do something to wp_data->object_instance */
|
||||
@@ -349,7 +327,7 @@ bool bacfile_write_property(
|
||||
shall be writable. */
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
/* FIXME: do something with value.type.Unsigned
|
||||
to wp_data->object_instance */
|
||||
@@ -375,8 +353,7 @@ bool bacfile_write_property(
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32_t bacfile_instance(
|
||||
char *filename)
|
||||
uint32_t bacfile_instance(char *filename)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
uint32_t instance = BACNET_MAX_INSTANCE + 1;
|
||||
@@ -399,36 +376,33 @@ uint32_t bacfile_instance(
|
||||
/* Another way would be to store the */
|
||||
/* invokeID and file instance in a list or table */
|
||||
/* when the request was sent */
|
||||
uint32_t bacfile_instance_from_tsm(
|
||||
uint8_t invokeID)
|
||||
uint32_t bacfile_instance_from_tsm(uint8_t invokeID)
|
||||
{
|
||||
BACNET_NPDU_DATA npdu_data = { 0 }; /* dummy for getting npdu length */
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
BACNET_NPDU_DATA npdu_data = {0}; /* dummy for getting npdu length */
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = {0};
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
BACNET_ADDRESS dest; /* where the original packet was destined */
|
||||
uint8_t apdu[MAX_PDU] = { 0 }; /* original APDU packet */
|
||||
uint16_t apdu_len = 0; /* original APDU packet length */
|
||||
int len = 0; /* apdu header length */
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = { 0 };
|
||||
BACNET_ADDRESS dest; /* where the original packet was destined */
|
||||
uint8_t apdu[MAX_PDU] = {0}; /* original APDU packet */
|
||||
uint16_t apdu_len = 0; /* original APDU packet length */
|
||||
int len = 0; /* apdu header length */
|
||||
BACNET_ATOMIC_READ_FILE_DATA data = {0};
|
||||
uint32_t object_instance = BACNET_MAX_INSTANCE + 1; /* return value */
|
||||
bool found = false;
|
||||
|
||||
found =
|
||||
tsm_get_transaction_pdu(invokeID, &dest, &npdu_data, &apdu[0],
|
||||
&apdu_len);
|
||||
found = tsm_get_transaction_pdu(invokeID, &dest, &npdu_data, &apdu[0],
|
||||
&apdu_len);
|
||||
if (found) {
|
||||
if (!npdu_data.network_layer_message && npdu_data.data_expecting_reply
|
||||
&& (apdu[0] == PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) {
|
||||
len =
|
||||
apdu_decode_confirmed_service_request(&apdu[0], apdu_len,
|
||||
&service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (!npdu_data.network_layer_message &&
|
||||
npdu_data.data_expecting_reply &&
|
||||
(apdu[0] == PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) {
|
||||
len = apdu_decode_confirmed_service_request(
|
||||
&apdu[0], apdu_len, &service_data, &service_choice,
|
||||
&service_request, &service_request_len);
|
||||
if (service_choice == SERVICE_CONFIRMED_ATOMIC_READ_FILE) {
|
||||
len =
|
||||
arf_decode_service_request(service_request,
|
||||
service_request_len, &data);
|
||||
len = arf_decode_service_request(service_request,
|
||||
service_request_len, &data);
|
||||
if (len > 0) {
|
||||
if (data.object_type == OBJECT_FILE)
|
||||
object_instance = data.object_instance;
|
||||
@@ -441,8 +415,7 @@ uint32_t bacfile_instance_from_tsm(
|
||||
}
|
||||
#endif
|
||||
|
||||
bool bacfile_read_stream_data(
|
||||
BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
bool bacfile_read_stream_data(BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
{
|
||||
char *pFilename = NULL;
|
||||
bool found = false;
|
||||
@@ -454,10 +427,9 @@ bool bacfile_read_stream_data(
|
||||
found = true;
|
||||
pFile = fopen(pFilename, "rb");
|
||||
if (pFile) {
|
||||
(void) fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET);
|
||||
len =
|
||||
fread(octetstring_value(&data->fileData[0]), 1,
|
||||
data->type.stream.requestedOctetCount, pFile);
|
||||
(void)fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET);
|
||||
len = fread(octetstring_value(&data->fileData[0]), 1,
|
||||
data->type.stream.requestedOctetCount, pFile);
|
||||
if (len < data->type.stream.requestedOctetCount)
|
||||
data->endOfFile = true;
|
||||
else
|
||||
@@ -476,8 +448,7 @@ bool bacfile_read_stream_data(
|
||||
return found;
|
||||
}
|
||||
|
||||
bool bacfile_write_stream_data(
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
bool bacfile_write_stream_data(BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
{
|
||||
char *pFilename = NULL;
|
||||
bool found = false;
|
||||
@@ -500,11 +471,11 @@ bool bacfile_write_stream_data(
|
||||
}
|
||||
if (pFile) {
|
||||
if (data->type.stream.fileStartPosition != -1) {
|
||||
(void) fseek(pFile, data->type.stream.fileStartPosition,
|
||||
SEEK_SET);
|
||||
(void)fseek(pFile, data->type.stream.fileStartPosition,
|
||||
SEEK_SET);
|
||||
}
|
||||
if (fwrite(octetstring_value(&data->fileData[0]),
|
||||
octetstring_length(&data->fileData[0]), 1, pFile) != 1) {
|
||||
octetstring_length(&data->fileData[0]), 1, pFile) != 1) {
|
||||
/* do something if it fails? */
|
||||
}
|
||||
fclose(pFile);
|
||||
@@ -514,8 +485,7 @@ bool bacfile_write_stream_data(
|
||||
return found;
|
||||
}
|
||||
|
||||
bool bacfile_write_record_data(
|
||||
BACNET_ATOMIC_WRITE_FILE_DATA * data)
|
||||
bool bacfile_write_record_data(BACNET_ATOMIC_WRITE_FILE_DATA *data)
|
||||
{
|
||||
char *pFilename = NULL;
|
||||
bool found = false;
|
||||
@@ -542,7 +512,8 @@ bool bacfile_write_record_data(
|
||||
if (pFile) {
|
||||
if ((data->type.record.fileStartRecord != -1) &&
|
||||
(data->type.record.fileStartRecord > 0)) {
|
||||
for (i = 0; i < (uint32_t)data->type.record.fileStartRecord; i++) {
|
||||
for (i = 0; i < (uint32_t)data->type.record.fileStartRecord;
|
||||
i++) {
|
||||
pData = fgets(&dummy_data[0], sizeof(dummy_data), pFile);
|
||||
if ((pData == NULL) || feof(pFile)) {
|
||||
break;
|
||||
@@ -551,8 +522,8 @@ bool bacfile_write_record_data(
|
||||
}
|
||||
for (i = 0; i < data->type.record.returnedRecordCount; i++) {
|
||||
if (fwrite(octetstring_value(&data->fileData[i]),
|
||||
octetstring_length(&data->fileData[i]), 1,
|
||||
pFile) != 1) {
|
||||
octetstring_length(&data->fileData[i]), 1,
|
||||
pFile) != 1) {
|
||||
/* do something if it fails? */
|
||||
}
|
||||
}
|
||||
@@ -563,9 +534,8 @@ bool bacfile_write_record_data(
|
||||
return found;
|
||||
}
|
||||
|
||||
bool bacfile_read_ack_stream_data(
|
||||
uint32_t instance,
|
||||
BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
bool bacfile_read_ack_stream_data(uint32_t instance,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
{
|
||||
bool found = false;
|
||||
FILE *pFile = NULL;
|
||||
@@ -576,12 +546,12 @@ bool bacfile_read_ack_stream_data(
|
||||
found = true;
|
||||
pFile = fopen(pFilename, "rb");
|
||||
if (pFile) {
|
||||
(void) fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET);
|
||||
(void)fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET);
|
||||
if (fwrite(octetstring_value(&data->fileData[0]),
|
||||
octetstring_length(&data->fileData[0]), 1, pFile) != 1) {
|
||||
octetstring_length(&data->fileData[0]), 1, pFile) != 1) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to write to %s (%lu)!\n", pFilename,
|
||||
(unsigned long) instance);
|
||||
(unsigned long)instance);
|
||||
#endif
|
||||
}
|
||||
fclose(pFile);
|
||||
@@ -591,15 +561,14 @@ bool bacfile_read_ack_stream_data(
|
||||
return found;
|
||||
}
|
||||
|
||||
bool bacfile_read_ack_record_data(
|
||||
uint32_t instance,
|
||||
BACNET_ATOMIC_READ_FILE_DATA * data)
|
||||
bool bacfile_read_ack_record_data(uint32_t instance,
|
||||
BACNET_ATOMIC_READ_FILE_DATA *data)
|
||||
{
|
||||
bool found = false;
|
||||
FILE *pFile = NULL;
|
||||
char *pFilename = NULL;
|
||||
uint32_t i = 0;
|
||||
char dummy_data[MAX_OCTET_STRING_BYTES] = { 0 };
|
||||
char dummy_data[MAX_OCTET_STRING_BYTES] = {0};
|
||||
char *pData = NULL;
|
||||
|
||||
pFilename = bacfile_name(instance);
|
||||
@@ -608,7 +577,8 @@ bool bacfile_read_ack_record_data(
|
||||
pFile = fopen(pFilename, "rb");
|
||||
if (pFile) {
|
||||
if (data->type.record.fileStartRecord > 0) {
|
||||
for (i = 0; i < (uint32_t)data->type.record.fileStartRecord; i++) {
|
||||
for (i = 0; i < (uint32_t)data->type.record.fileStartRecord;
|
||||
i++) {
|
||||
pData = fgets(&dummy_data[0], sizeof(dummy_data), pFile);
|
||||
if ((pData == NULL) || feof(pFile)) {
|
||||
break;
|
||||
@@ -617,11 +587,11 @@ bool bacfile_read_ack_record_data(
|
||||
}
|
||||
for (i = 0; i < data->type.record.RecordCount; i++) {
|
||||
if (fwrite(octetstring_value(&data->fileData[i]),
|
||||
octetstring_length(&data->fileData[i]), 1,
|
||||
pFile) != 1) {
|
||||
octetstring_length(&data->fileData[i]), 1,
|
||||
pFile) != 1) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Failed to write to %s (%lu)!\n",
|
||||
pFilename, (unsigned long) instance);
|
||||
fprintf(stderr, "Failed to write to %s (%lu)!\n", pFilename,
|
||||
(unsigned long)instance);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -632,7 +602,6 @@ bool bacfile_read_ack_record_data(
|
||||
return found;
|
||||
}
|
||||
|
||||
void bacfile_init(
|
||||
void)
|
||||
void bacfile_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
+87
-125
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Input Objects customize for your use */
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "cov.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "bi.h"
|
||||
#include "handlers.h"
|
||||
|
||||
@@ -54,30 +54,16 @@ static BACNET_POLARITY Polarity[MAX_BINARY_INPUTS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Binary_Input_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_POLARITY,
|
||||
-1
|
||||
};
|
||||
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE, PROP_POLARITY, -1};
|
||||
|
||||
static const int Binary_Input_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
static const int Binary_Input_Properties_Optional[] = {PROP_DESCRIPTION, -1};
|
||||
|
||||
static const int Binary_Input_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Binary_Input_Properties_Proprietary[] = {-1};
|
||||
|
||||
void Binary_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Binary_Input_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired) {
|
||||
*pRequired = Binary_Input_Properties_Required;
|
||||
@@ -95,8 +81,7 @@ void Binary_Input_Property_Lists(
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Binary_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Input_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_INPUTS) {
|
||||
return true;
|
||||
@@ -107,8 +92,7 @@ bool Binary_Input_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Binary_Input_Count(
|
||||
void)
|
||||
unsigned Binary_Input_Count(void)
|
||||
{
|
||||
return MAX_BINARY_INPUTS;
|
||||
}
|
||||
@@ -116,14 +100,12 @@ unsigned Binary_Input_Count(
|
||||
/* 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 Binary_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Binary_Input_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
void Binary_Input_Init(
|
||||
void)
|
||||
void Binary_Input_Init(void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
@@ -143,8 +125,7 @@ void Binary_Input_Init(
|
||||
/* 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 Binary_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Binary_Input_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_INPUTS;
|
||||
|
||||
@@ -155,8 +136,7 @@ unsigned Binary_Input_Instance_To_Index(
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
BACNET_BINARY_PV Binary_Input_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
unsigned index = 0;
|
||||
@@ -176,8 +156,7 @@ BACNET_BINARY_PV Binary_Input_Present_Value(
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Binary_Input_Out_Of_Service(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Input_Out_Of_Service(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned index = 0;
|
||||
@@ -190,8 +169,7 @@ bool Binary_Input_Out_Of_Service(
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Binary_Input_Change_Of_Value(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Input_Change_Of_Value(uint32_t object_instance)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index;
|
||||
@@ -204,8 +182,7 @@ bool Binary_Input_Change_Of_Value(
|
||||
return status;
|
||||
}
|
||||
|
||||
void Binary_Input_Change_Of_Value_Clear(
|
||||
uint32_t object_instance)
|
||||
void Binary_Input_Change_Of_Value_Clear(uint32_t object_instance)
|
||||
{
|
||||
unsigned index;
|
||||
|
||||
@@ -225,9 +202,8 @@ void Binary_Input_Change_Of_Value_Clear(
|
||||
*
|
||||
* @return true if the value list is encoded
|
||||
*/
|
||||
bool Binary_Input_Encode_Value_List(
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list)
|
||||
bool Binary_Input_Encode_Value_List(uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE *value_list)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
@@ -250,17 +226,17 @@ bool Binary_Input_Encode_Value_List(
|
||||
value_list->value.next = NULL;
|
||||
bitstring_init(&value_list->value.type.Bit_String);
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_IN_ALARM, false);
|
||||
STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String, STATUS_FLAG_FAULT,
|
||||
false);
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_OVERRIDDEN, false);
|
||||
STATUS_FLAG_OVERRIDDEN, false);
|
||||
if (Binary_Input_Out_Of_Service(object_instance)) {
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_OUT_OF_SERVICE, true);
|
||||
STATUS_FLAG_OUT_OF_SERVICE, true);
|
||||
} else {
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
}
|
||||
value_list->priority = BACNET_NO_PRIORITY;
|
||||
value_list->next = NULL;
|
||||
@@ -270,9 +246,8 @@ bool Binary_Input_Encode_Value_List(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Binary_Input_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_BINARY_PV value)
|
||||
bool Binary_Input_Present_Value_Set(uint32_t object_instance,
|
||||
BACNET_BINARY_PV value)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -296,9 +271,7 @@ bool Binary_Input_Present_Value_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
void Binary_Input_Out_Of_Service_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
void Binary_Input_Out_Of_Service_Set(uint32_t object_instance, bool value)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -313,26 +286,24 @@ void Binary_Input_Out_Of_Service_Set(
|
||||
return;
|
||||
}
|
||||
|
||||
bool Binary_Input_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Binary_Input_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
|
||||
index = Binary_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_BINARY_INPUTS) {
|
||||
sprintf(text_string, "BINARY INPUT %lu",
|
||||
(unsigned long) object_instance);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BACNET_POLARITY Binary_Input_Polarity(
|
||||
uint32_t object_instance)
|
||||
BACNET_POLARITY Binary_Input_Polarity(uint32_t object_instance)
|
||||
{
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
unsigned index = 0;
|
||||
@@ -345,9 +316,8 @@ BACNET_POLARITY Binary_Input_Polarity(
|
||||
return polarity;
|
||||
}
|
||||
|
||||
bool Binary_Input_Polarity_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_POLARITY polarity)
|
||||
bool Binary_Input_Polarity_Set(uint32_t object_instance,
|
||||
BACNET_POLARITY polarity)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
@@ -362,10 +332,9 @@ bool Binary_Input_Polarity_Set(
|
||||
|
||||
/* return apdu length, or BACNET_STATUS_ERROR on error */
|
||||
/* assumption - object already exists, and has been bounds checked */
|
||||
int Binary_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Binary_Input_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
@@ -378,9 +347,8 @@ int Binary_Input_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_BINARY_INPUT, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
@@ -395,9 +363,8 @@ int Binary_Input_Read_Property(
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
/* note: you need to look up the actual value */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
Binary_Input_Present_Value(rpdata->object_instance));
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], Binary_Input_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
@@ -419,9 +386,8 @@ int Binary_Input_Read_Property(
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
Binary_Input_Polarity(rpdata->object_instance));
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], Binary_Input_Polarity(rpdata->object_instance));
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -440,17 +406,15 @@ int Binary_Input_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Binary_Input_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -468,11 +432,12 @@ bool Binary_Input_Write_Property(
|
||||
case PROP_PRESENT_VALUE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
if (value.type.Enumerated <= MAX_BINARY_PV) {
|
||||
Binary_Input_Present_Value_Set(wp_data->object_instance,
|
||||
(BACNET_BINARY_PV) value.type.Enumerated);
|
||||
Binary_Input_Present_Value_Set(
|
||||
wp_data->object_instance,
|
||||
(BACNET_BINARY_PV)value.type.Enumerated);
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -483,20 +448,21 @@ bool Binary_Input_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Binary_Input_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
if (value.type.Enumerated < MAX_POLARITY) {
|
||||
Binary_Input_Polarity_Set(wp_data->object_instance,
|
||||
(BACNET_POLARITY) value.type.Enumerated);
|
||||
Binary_Input_Polarity_Set(
|
||||
wp_data->object_instance,
|
||||
(BACNET_POLARITY)value.type.Enumerated);
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -527,11 +493,9 @@ bool Binary_Input_Write_Property(
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -541,11 +505,10 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testBinaryInput(
|
||||
Test * pTest)
|
||||
void testBinaryInput(Test *pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -571,8 +534,7 @@ void testBinaryInput(
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_INPUT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -584,7 +546,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+95
-124
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Output Objects - customize for your use */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "bo.h"
|
||||
@@ -46,42 +46,32 @@
|
||||
/* the Relinquish Default value */
|
||||
#define RELINQUISH_DEFAULT BINARY_INACTIVE
|
||||
/* Here is our Priority Array.*/
|
||||
static BACNET_BINARY_PV
|
||||
Binary_Output_Level[MAX_BINARY_OUTPUTS][BACNET_MAX_PRIORITY];
|
||||
static BACNET_BINARY_PV Binary_Output_Level[MAX_BINARY_OUTPUTS]
|
||||
[BACNET_MAX_PRIORITY];
|
||||
/* Writable out-of-service allows others to play with our Present Value */
|
||||
/* without changing the physical output */
|
||||
static bool Out_Of_Service[MAX_BINARY_OUTPUTS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Binary_Output_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_POLARITY,
|
||||
PROP_PRIORITY_ARRAY,
|
||||
PROP_RELINQUISH_DEFAULT,
|
||||
-1
|
||||
};
|
||||
static const int Binary_Output_Properties_Required[] = {PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_POLARITY,
|
||||
PROP_PRIORITY_ARRAY,
|
||||
PROP_RELINQUISH_DEFAULT,
|
||||
-1};
|
||||
|
||||
static const int Binary_Output_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
PROP_ACTIVE_TEXT,
|
||||
PROP_INACTIVE_TEXT,
|
||||
-1
|
||||
};
|
||||
PROP_DESCRIPTION, PROP_ACTIVE_TEXT, PROP_INACTIVE_TEXT, -1};
|
||||
|
||||
static const int Binary_Output_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Binary_Output_Properties_Proprietary[] = {-1};
|
||||
|
||||
void Binary_Output_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Binary_Output_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Binary_Output_Properties_Required;
|
||||
@@ -93,8 +83,7 @@ void Binary_Output_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Binary_Output_Init(
|
||||
void)
|
||||
void Binary_Output_Init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
static bool initialized = false;
|
||||
@@ -116,8 +105,7 @@ void Binary_Output_Init(
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Binary_Output_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Output_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_OUTPUTS)
|
||||
return true;
|
||||
@@ -127,8 +115,7 @@ bool Binary_Output_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Binary_Output_Count(
|
||||
void)
|
||||
unsigned Binary_Output_Count(void)
|
||||
{
|
||||
return MAX_BINARY_OUTPUTS;
|
||||
}
|
||||
@@ -136,8 +123,7 @@ unsigned Binary_Output_Count(
|
||||
/* 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 Binary_Output_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Binary_Output_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -145,8 +131,7 @@ uint32_t Binary_Output_Index_To_Instance(
|
||||
/* 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 Binary_Output_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Binary_Output_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_OUTPUTS;
|
||||
|
||||
@@ -156,8 +141,7 @@ unsigned Binary_Output_Instance_To_Index(
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Output_Present_Value(
|
||||
uint32_t object_instance)
|
||||
BACNET_BINARY_PV Binary_Output_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
@@ -176,8 +160,7 @@ BACNET_BINARY_PV Binary_Output_Present_Value(
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Binary_Output_Out_Of_Service(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Output_Out_Of_Service(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned index = 0;
|
||||
@@ -191,16 +174,15 @@ bool Binary_Output_Out_Of_Service(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Binary_Output_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Binary_Output_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_BINARY_OUTPUTS) {
|
||||
sprintf(text_string, "BINARY OUTPUT %lu",
|
||||
(unsigned long) object_instance);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -208,11 +190,10 @@ bool Binary_Output_Object_Name(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Binary_Output_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Binary_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
@@ -229,9 +210,8 @@ int Binary_Output_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_OUTPUT,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_BINARY_OUTPUT, rpdata->object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
@@ -289,9 +269,8 @@ int Binary_Output_Read_Property(
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
present_value = Binary_Output_Level[object_index][i];
|
||||
len =
|
||||
encode_application_enumerated(&apdu[apdu_len],
|
||||
present_value);
|
||||
len = encode_application_enumerated(&apdu[apdu_len],
|
||||
present_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
@@ -308,14 +287,14 @@ int Binary_Output_Read_Property(
|
||||
Binary_Output_Instance_To_Index(rpdata->object_instance);
|
||||
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Binary_Output_Level[object_index][rpdata->array_index -
|
||||
1] == BINARY_NULL)
|
||||
1] == BINARY_NULL)
|
||||
apdu_len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
present_value = Binary_Output_Level[object_index]
|
||||
[rpdata->array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[apdu_len],
|
||||
present_value);
|
||||
present_value =
|
||||
Binary_Output_Level[object_index]
|
||||
[rpdata->array_index - 1];
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[apdu_len], present_value);
|
||||
}
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -357,10 +336,9 @@ int Binary_Output_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Output_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Binary_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
BACNET_BINARY_PV level = BINARY_NULL;
|
||||
@@ -368,9 +346,8 @@ bool Binary_Output_Write_Property(
|
||||
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);
|
||||
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 */
|
||||
@@ -393,19 +370,19 @@ bool Binary_Output_Write_Property(
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(priority != 6 /* reserved */) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = (BACNET_BINARY_PV) value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Output_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
level = (BACNET_BINARY_PV)value.type.Enumerated;
|
||||
object_index = Binary_Output_Instance_To_Index(
|
||||
wp_data->object_instance);
|
||||
priority--;
|
||||
Binary_Output_Level[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
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) */
|
||||
main loop (i.e. check out of service before changing
|
||||
output) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
@@ -418,24 +395,24 @@ bool Binary_Output_Write_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);
|
||||
status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
level = BINARY_NULL;
|
||||
object_index =
|
||||
Binary_Output_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
object_index = Binary_Output_Instance_To_Index(
|
||||
wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Binary_Output_Level[object_index][priority] = level;
|
||||
/* 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) */
|
||||
/* 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) */
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -447,12 +424,11 @@ bool Binary_Output_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
object_index =
|
||||
Binary_Output_Instance_To_Index(wp_data->object_instance);
|
||||
Out_Of_Service[object_index] =
|
||||
value.type.Boolean;
|
||||
Out_Of_Service[object_index] = value.type.Boolean;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -478,17 +454,14 @@ bool Binary_Output_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -498,10 +471,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testBinaryOutput(
|
||||
Test * pTest)
|
||||
void testBinaryOutput(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -528,8 +500,7 @@ void testBinaryOutput(
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_OUTPUT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -541,7 +512,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+89
-124
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Output Objects - customize for your use */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bv.h"
|
||||
@@ -46,39 +46,26 @@
|
||||
/* the Relinquish Default value */
|
||||
#define RELINQUISH_DEFAULT BINARY_INACTIVE
|
||||
/* Here is our Priority Array.*/
|
||||
static BACNET_BINARY_PV
|
||||
Binary_Value_Level[MAX_BINARY_VALUES][BACNET_MAX_PRIORITY];
|
||||
static BACNET_BINARY_PV Binary_Value_Level[MAX_BINARY_VALUES]
|
||||
[BACNET_MAX_PRIORITY];
|
||||
/* Writable out-of-service allows others to play with our Present Value */
|
||||
/* without changing the physical output */
|
||||
static bool Out_Of_Service[MAX_BINARY_VALUES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Binary_Value_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
-1
|
||||
};
|
||||
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE, PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS, PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE, -1};
|
||||
|
||||
static const int Binary_Value_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
PROP_PRIORITY_ARRAY,
|
||||
PROP_RELINQUISH_DEFAULT,
|
||||
-1
|
||||
};
|
||||
PROP_DESCRIPTION, PROP_PRIORITY_ARRAY, PROP_RELINQUISH_DEFAULT, -1};
|
||||
|
||||
static const int Binary_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Binary_Value_Properties_Proprietary[] = {-1};
|
||||
|
||||
void Binary_Value_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Binary_Value_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Binary_Value_Properties_Required;
|
||||
@@ -90,8 +77,7 @@ void Binary_Value_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Binary_Value_Init(
|
||||
void)
|
||||
void Binary_Value_Init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
static bool initialized = false;
|
||||
@@ -113,8 +99,7 @@ void Binary_Value_Init(
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
@@ -124,8 +109,7 @@ bool Binary_Value_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Binary_Value_Count(
|
||||
void)
|
||||
unsigned Binary_Value_Count(void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
@@ -133,8 +117,7 @@ unsigned Binary_Value_Count(
|
||||
/* 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 Binary_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Binary_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -142,8 +125,7 @@ uint32_t Binary_Value_Index_To_Instance(
|
||||
/* 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 Binary_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Binary_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
@@ -153,8 +135,7 @@ unsigned Binary_Value_Instance_To_Index(
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
@@ -174,24 +155,22 @@ BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Binary_Value_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Binary_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
sprintf(text_string, "BINARY VALUE %lu",
|
||||
(unsigned long) object_instance);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Binary_Value_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
bool Binary_Value_Out_Of_Service(uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
@@ -204,9 +183,7 @@ bool Binary_Value_Out_Of_Service(
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Binary_Value_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
void Binary_Value_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -217,11 +194,10 @@ void Binary_Value_Out_Of_Service_Set(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Binary_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Binary_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
@@ -237,9 +213,8 @@ int Binary_Value_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_BINARY_VALUE, rpdata->object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
@@ -254,8 +229,7 @@ int Binary_Value_Read_Property(
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
Binary_Value_Present_Value(rpdata->object_instance);
|
||||
present_value = Binary_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
@@ -293,9 +267,8 @@ int Binary_Value_Read_Property(
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
present_value = Binary_Value_Level[object_index][i];
|
||||
len =
|
||||
encode_application_enumerated(&apdu[apdu_len],
|
||||
present_value);
|
||||
len = encode_application_enumerated(&apdu[apdu_len],
|
||||
present_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
@@ -311,15 +284,14 @@ int Binary_Value_Read_Property(
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(rpdata->object_instance);
|
||||
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Binary_Value_Level[object_index][rpdata->array_index]
|
||||
== BINARY_NULL)
|
||||
if (Binary_Value_Level[object_index][rpdata->array_index] ==
|
||||
BINARY_NULL)
|
||||
apdu_len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
present_value = Binary_Value_Level[object_index]
|
||||
[rpdata->array_index];
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[apdu_len],
|
||||
present_value);
|
||||
[rpdata->array_index];
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[apdu_len], present_value);
|
||||
}
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -350,10 +322,9 @@ int Binary_Value_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
BACNET_BINARY_PV level = BINARY_NULL;
|
||||
@@ -361,9 +332,8 @@ bool Binary_Value_Write_Property(
|
||||
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);
|
||||
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 */
|
||||
@@ -386,19 +356,19 @@ bool Binary_Value_Write_Property(
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(priority != 6 /* reserved */) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = (BACNET_BINARY_PV) value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
level = (BACNET_BINARY_PV)value.type.Enumerated;
|
||||
object_index = Binary_Value_Instance_To_Index(
|
||||
wp_data->object_instance);
|
||||
priority--;
|
||||
Binary_Value_Level[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
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) */
|
||||
main loop (i.e. check out of service before changing
|
||||
output) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
@@ -411,24 +381,24 @@ bool Binary_Value_Write_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);
|
||||
status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
level = BINARY_NULL;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
object_index = Binary_Value_Instance_To_Index(
|
||||
wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Binary_Value_Level[object_index][priority] = level;
|
||||
/* 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) */
|
||||
/* 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) */
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -440,10 +410,10 @@ bool Binary_Value_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Binary_Value_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -466,17 +436,14 @@ bool Binary_Value_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -486,10 +453,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testBinary_Value(
|
||||
Test * pTest)
|
||||
void testBinary_Value(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -516,8 +482,7 @@ void testBinary_Value(
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_VALUE
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -529,7 +494,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+251
-308
File diff suppressed because it is too large
Load Diff
+153
-223
@@ -47,87 +47,78 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "proplist.h"
|
||||
#include "timestamp.h"
|
||||
#include "command.h"
|
||||
|
||||
/*BACnetActionCommand ::= SEQUENCE {
|
||||
deviceIdentifier [0] BACnetObjectIdentifier OPTIONAL,
|
||||
objectIdentifier [1] BACnetObjectIdentifier,
|
||||
propertyIdentifier [2] BACnetPropertyIdentifier,
|
||||
propertyArrayIndex [3] Unsigned OPTIONAL, --used only with array datatype
|
||||
propertyValue [4] ABSTRACT-SYNTAX.&Type,
|
||||
priority [5] Unsigned (1..16) OPTIONAL, --used only when property is commandable
|
||||
postDelay [6] Unsigned OPTIONAL,
|
||||
quitOnFailure [7] BOOLEAN,
|
||||
writeSuccessful [8] BOOLEAN
|
||||
}*/
|
||||
/*BACnetActionCommand ::= SEQUENCE {
|
||||
deviceIdentifier [0] BACnetObjectIdentifier OPTIONAL,
|
||||
objectIdentifier [1] BACnetObjectIdentifier,
|
||||
propertyIdentifier [2] BACnetPropertyIdentifier,
|
||||
propertyArrayIndex [3] Unsigned OPTIONAL, --used only with array datatype
|
||||
propertyValue [4] ABSTRACT-SYNTAX.&Type,
|
||||
priority [5] Unsigned (1..16) OPTIONAL, --used only when property is commandable
|
||||
postDelay [6] Unsigned OPTIONAL,
|
||||
quitOnFailure [7] BOOLEAN,
|
||||
writeSuccessful [8] BOOLEAN
|
||||
}*/
|
||||
|
||||
|
||||
int cl_encode_apdu(
|
||||
uint8_t * apdu,
|
||||
BACNET_ACTION_LIST * bcl)
|
||||
int cl_encode_apdu(uint8_t *apdu, BACNET_ACTION_LIST *bcl)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
|
||||
if (bcl->Device_Id.instance >= 0 &&
|
||||
bcl->Device_Id.instance <= BACNET_MAX_INSTANCE) {
|
||||
len =
|
||||
encode_context_object_id(&apdu[apdu_len], 0, bcl->Device_Id.type,
|
||||
bcl->Device_Id.instance);
|
||||
len = encode_context_object_id(&apdu[apdu_len], 0, bcl->Device_Id.type,
|
||||
bcl->Device_Id.instance);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
}
|
||||
/* TODO: Check for object type and instance limits */
|
||||
len =
|
||||
encode_context_object_id(&apdu[apdu_len], 1, bcl->Object_Id.type,
|
||||
bcl->Object_Id.instance);
|
||||
len = encode_context_object_id(&apdu[apdu_len], 1, bcl->Object_Id.type,
|
||||
bcl->Object_Id.instance);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
len =
|
||||
encode_context_enumerated(&apdu[apdu_len], 2,
|
||||
bcl->Property_Identifier);
|
||||
encode_context_enumerated(&apdu[apdu_len], 2, bcl->Property_Identifier);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
if (bcl->Property_Array_Index != BACNET_ARRAY_ALL) {
|
||||
len =
|
||||
encode_context_unsigned(&apdu[apdu_len], 3,
|
||||
bcl->Property_Array_Index);
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 3,
|
||||
bcl->Property_Array_Index);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
/* BACnet Testing Observed Incident oi00108
|
||||
Command Action not correctly formatted
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00031
|
||||
BC 135.1: 9.20.1.7
|
||||
BC 135.1: 9.20.1.9
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes have been reviewed
|
||||
by all interested parties. Say 6 months -> September 2016 */
|
||||
|
||||
len = encode_opening_tag(&apdu[apdu_len], 4);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
len = bacapp_encode_application_data(&apdu[apdu_len], &bcl->Value);
|
||||
/* BACnet Testing Observed Incident oi00108
|
||||
Command Action not correctly formatted
|
||||
Revealed by BACnet Test Client v1.8.16 (
|
||||
www.bac-test.com/bacnet-test-client-download ) BITS: BIT00031 BC
|
||||
135.1: 9.20.1.7 BC 135.1: 9.20.1.9 Any discussions can be directed to
|
||||
edward@bac-test.com Please feel free to remove this comment when my
|
||||
changes have been reviewed by all interested parties. Say 6 months ->
|
||||
September 2016 */
|
||||
|
||||
len = encode_opening_tag(&apdu[apdu_len], 4);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
len = bacapp_encode_application_data(&apdu[apdu_len], &bcl->Value);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
len = encode_closing_tag(&apdu[apdu_len], 4);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
len = encode_closing_tag(&apdu[apdu_len], 4);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
apdu_len += len;
|
||||
|
||||
|
||||
if (bcl->Priority != BACNET_NO_PRIORITY) {
|
||||
len = encode_context_unsigned(&apdu[apdu_len], 5, bcl->Priority);
|
||||
@@ -153,11 +144,8 @@ int cl_encode_apdu(
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
int cl_decode_apdu(
|
||||
uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
BACNET_APPLICATION_TAG tag,
|
||||
BACNET_ACTION_LIST * bcl)
|
||||
int cl_decode_apdu(uint8_t *apdu, unsigned apdu_len, BACNET_APPLICATION_TAG tag,
|
||||
BACNET_ACTION_LIST *bcl)
|
||||
{
|
||||
int len = 0;
|
||||
int dec_len = 0;
|
||||
@@ -167,43 +155,37 @@ int cl_decode_apdu(
|
||||
if (decode_is_context_tag(&apdu[dec_len], 0)) {
|
||||
/* Tag 0: Device ID */
|
||||
dec_len++;
|
||||
len =
|
||||
decode_object_id(&apdu[dec_len], &bcl->Device_Id.type,
|
||||
&bcl->Device_Id.instance);
|
||||
len = decode_object_id(&apdu[dec_len], &bcl->Device_Id.type,
|
||||
&bcl->Device_Id.instance);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
dec_len += len;
|
||||
}
|
||||
if (!decode_is_context_tag(&apdu[dec_len++], 1))
|
||||
return BACNET_STATUS_REJECT;
|
||||
len =
|
||||
decode_object_id(&apdu[dec_len], &bcl->Object_Id.type,
|
||||
&bcl->Object_Id.instance);
|
||||
len = decode_object_id(&apdu[dec_len], &bcl->Object_Id.type,
|
||||
&bcl->Object_Id.instance);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
dec_len += len;
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[dec_len], &tag_number,
|
||||
&len_value_type);
|
||||
len = decode_tag_number_and_value(&apdu[dec_len], &tag_number,
|
||||
&len_value_type);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
dec_len += len;
|
||||
if (tag_number != 2)
|
||||
return BACNET_STATUS_REJECT;
|
||||
len =
|
||||
decode_enumerated(&apdu[dec_len], len_value_type,
|
||||
&bcl->Property_Identifier);
|
||||
len = decode_enumerated(&apdu[dec_len], len_value_type,
|
||||
&bcl->Property_Identifier);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
dec_len += len;
|
||||
if (decode_is_context_tag(&apdu[dec_len], 3)) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[dec_len], &tag_number,
|
||||
&len_value_type);
|
||||
len = decode_tag_number_and_value(&apdu[dec_len], &tag_number,
|
||||
&len_value_type);
|
||||
dec_len += len;
|
||||
len =
|
||||
decode_unsigned(&apdu[dec_len], len_value_type,
|
||||
&bcl->Property_Array_Index);
|
||||
len = decode_unsigned(&apdu[dec_len], len_value_type,
|
||||
&bcl->Property_Array_Index);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
dec_len += len;
|
||||
@@ -220,68 +202,55 @@ int cl_decode_apdu(
|
||||
len = 1;
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_BOOLEAN:
|
||||
len =
|
||||
decode_context_boolean2(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Boolean);
|
||||
len = decode_context_boolean2(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Boolean);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
|
||||
len =
|
||||
decode_context_unsigned(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Unsigned_Int);
|
||||
len = decode_context_unsigned(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Unsigned_Int);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_SIGNED_INT:
|
||||
len =
|
||||
decode_context_signed(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Signed_Int);
|
||||
len = decode_context_signed(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Signed_Int);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_REAL:
|
||||
len =
|
||||
decode_context_real(&apdu[dec_len], 4, &bcl->Value.type.Real);
|
||||
len = decode_context_real(&apdu[dec_len], 4, &bcl->Value.type.Real);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_DOUBLE:
|
||||
len =
|
||||
decode_context_double(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Double);
|
||||
len = decode_context_double(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Double);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_OCTET_STRING:
|
||||
len =
|
||||
decode_context_octet_string(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Octet_String);
|
||||
len = decode_context_octet_string(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Octet_String);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
|
||||
len =
|
||||
decode_context_character_string(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Character_String);
|
||||
len = decode_context_character_string(
|
||||
&apdu[dec_len], 4, &bcl->Value.type.Character_String);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_BIT_STRING:
|
||||
len =
|
||||
decode_context_bitstring(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Bit_String);
|
||||
len = decode_context_bitstring(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Bit_String);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_ENUMERATED:
|
||||
len =
|
||||
decode_context_enumerated(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Enumerated);
|
||||
len = decode_context_enumerated(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Enumerated);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_DATE:
|
||||
len =
|
||||
decode_context_date(&apdu[dec_len], 4, &bcl->Value.type.Date);
|
||||
len = decode_context_date(&apdu[dec_len], 4, &bcl->Value.type.Date);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_TIME:
|
||||
len =
|
||||
decode_context_bacnet_time(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Time);
|
||||
len = decode_context_bacnet_time(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Time);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_OBJECT_ID:
|
||||
len =
|
||||
decode_context_object_id(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Object_Id.type,
|
||||
&bcl->Value.type.Object_Id.instance);
|
||||
len = decode_context_object_id(&apdu[dec_len], 4,
|
||||
&bcl->Value.type.Object_Id.type,
|
||||
&bcl->Value.type.Object_Id.instance);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_LIGHTING_COMMAND:
|
||||
len =
|
||||
lighting_command_decode(&apdu[dec_len], apdu_len - dec_len,
|
||||
&bcl->Value.type.Lighting_Command);
|
||||
len = lighting_command_decode(&apdu[dec_len], apdu_len - dec_len,
|
||||
&bcl->Value.type.Lighting_Command);
|
||||
break;
|
||||
default:
|
||||
return BACNET_STATUS_REJECT;
|
||||
@@ -291,25 +260,22 @@ int cl_decode_apdu(
|
||||
dec_len += len;
|
||||
if (decode_is_context_tag(&apdu[dec_len], 5)) {
|
||||
uint32_t priority_dec;
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[dec_len], &tag_number,
|
||||
&len_value_type);
|
||||
len = decode_tag_number_and_value(&apdu[dec_len], &tag_number,
|
||||
&len_value_type);
|
||||
dec_len += len;
|
||||
len = decode_unsigned(&apdu[dec_len], len_value_type, &priority_dec);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
bcl->Priority = (uint8_t) priority_dec;
|
||||
bcl->Priority = (uint8_t)priority_dec;
|
||||
dec_len += len;
|
||||
} else {
|
||||
bcl->Priority = BACNET_NO_PRIORITY;
|
||||
}
|
||||
if (decode_is_context_tag(&apdu[dec_len], 6)) {
|
||||
len =
|
||||
decode_tag_number_and_value(&apdu[dec_len], &tag_number,
|
||||
&len_value_type);
|
||||
len = decode_tag_number_and_value(&apdu[dec_len], &tag_number,
|
||||
&len_value_type);
|
||||
dec_len += len;
|
||||
len =
|
||||
decode_unsigned(&apdu[dec_len], len_value_type, &bcl->Post_Delay);
|
||||
len = decode_unsigned(&apdu[dec_len], len_value_type, &bcl->Post_Delay);
|
||||
if (len < 0)
|
||||
return BACNET_STATUS_REJECT;
|
||||
dec_len += len;
|
||||
@@ -340,25 +306,18 @@ int cl_decode_apdu(
|
||||
COMMAND_DESCR Command_Descr[MAX_COMMANDS];
|
||||
|
||||
/* These arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Command_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_IN_PROCESS,
|
||||
PROP_ALL_WRITES_SUCCESSFUL,
|
||||
PROP_ACTION,
|
||||
-1
|
||||
};
|
||||
static const int Command_Properties_Required[] = {PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_IN_PROCESS,
|
||||
PROP_ALL_WRITES_SUCCESSFUL,
|
||||
PROP_ACTION,
|
||||
-1};
|
||||
|
||||
static const int Command_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
static const int Command_Properties_Optional[] = {PROP_DESCRIPTION, -1};
|
||||
|
||||
static const int Command_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Command_Properties_Proprietary[] = {-1};
|
||||
|
||||
/**
|
||||
* Returns the list of required, optional, and proprietary properties.
|
||||
@@ -371,10 +330,8 @@ static const int Command_Properties_Proprietary[] = {
|
||||
* @param pProprietary - pointer to list of int terminated by -1, of
|
||||
* BACnet proprietary properties for this object.
|
||||
*/
|
||||
void Command_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Command_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Command_Properties_Required;
|
||||
@@ -386,18 +343,16 @@ void Command_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the Command object data
|
||||
*/
|
||||
void Command_Init(
|
||||
void)
|
||||
void Command_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < MAX_COMMANDS; i++) {
|
||||
Command_Descr[i].Present_Value = 0;
|
||||
Command_Descr[i].In_Process = false;
|
||||
Command_Descr[i].All_Writes_Successful = true; /* Optimistic default */
|
||||
Command_Descr[i].All_Writes_Successful = true; /* Optimistic default */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,8 +363,7 @@ void Command_Init(
|
||||
*
|
||||
* @return true if the instance is valid, and false if not
|
||||
*/
|
||||
bool Command_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Command_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
@@ -425,8 +379,7 @@ bool Command_Valid_Instance(
|
||||
*
|
||||
* @return Number of objects
|
||||
*/
|
||||
unsigned Command_Count(
|
||||
void)
|
||||
unsigned Command_Count(void)
|
||||
{
|
||||
return MAX_COMMANDS;
|
||||
}
|
||||
@@ -439,8 +392,7 @@ unsigned Command_Count(
|
||||
*
|
||||
* @return object instance-number for the given index
|
||||
*/
|
||||
uint32_t Command_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Command_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -454,8 +406,7 @@ uint32_t Command_Index_To_Instance(
|
||||
* @return index for the given instance-number, or
|
||||
* the total number of this object instances if not valid.
|
||||
*/
|
||||
unsigned Command_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Command_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_COMMANDS;
|
||||
|
||||
@@ -472,8 +423,7 @@ unsigned Command_Instance_To_Index(
|
||||
*
|
||||
* @return present-value of the object
|
||||
*/
|
||||
uint32_t Command_Present_Value(
|
||||
uint32_t object_instance)
|
||||
uint32_t Command_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
unsigned int index;
|
||||
@@ -494,9 +444,7 @@ uint32_t Command_Present_Value(
|
||||
*
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool Command_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
uint32_t value)
|
||||
bool Command_Present_Value_Set(uint32_t object_instance, uint32_t value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index;
|
||||
@@ -521,8 +469,7 @@ bool Command_Present_Value_Set(
|
||||
*
|
||||
* @return true if this object-instance is in-process.
|
||||
*/
|
||||
bool Command_In_Process(
|
||||
uint32_t object_instance)
|
||||
bool Command_In_Process(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned int index;
|
||||
@@ -543,9 +490,7 @@ bool Command_In_Process(
|
||||
*
|
||||
* @return true if values are within range and in-process flag is set.
|
||||
*/
|
||||
bool Command_In_Process_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
bool Command_In_Process_Set(uint32_t object_instance, bool value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index;
|
||||
@@ -568,8 +513,7 @@ bool Command_In_Process_Set(
|
||||
*
|
||||
* @return true if all writes were successful for this object-instance
|
||||
*/
|
||||
bool Command_All_Writes_Successful(
|
||||
uint32_t object_instance)
|
||||
bool Command_All_Writes_Successful(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned int index;
|
||||
@@ -590,9 +534,7 @@ bool Command_All_Writes_Successful(
|
||||
*
|
||||
* @return true if values are within range and all-writes-succcessful is set.
|
||||
*/
|
||||
bool Command_All_Writes_Successful_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
bool Command_All_Writes_Successful_Set(uint32_t object_instance, bool value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index;
|
||||
@@ -615,17 +557,16 @@ bool Command_All_Writes_Successful_Set(
|
||||
*
|
||||
* @return true if object-name was retrieved
|
||||
*/
|
||||
bool Command_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Command_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
unsigned int index;
|
||||
bool status = false;
|
||||
|
||||
index = Command_Instance_To_Index(object_instance);
|
||||
if (index < MAX_COMMANDS) {
|
||||
sprintf(text_string, "COMMAND %lu", (unsigned long) index);
|
||||
sprintf(text_string, "COMMAND %lu", (unsigned long)index);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -642,10 +583,9 @@ bool Command_Object_Name(
|
||||
* @return number of APDU bytes in the response, or
|
||||
* BACNET_STATUS_ERROR on error.
|
||||
*/
|
||||
int Command_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Command_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -666,11 +606,10 @@ int Command_Read_Property(
|
||||
}
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
switch ((int) rpdata->object_property) {
|
||||
switch ((int)rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_COMMAND,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_COMMAND,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_NAME:
|
||||
@@ -685,24 +624,23 @@ int Command_Read_Property(
|
||||
break;
|
||||
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Command_Present_Value(rpdata->object_instance));
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0], Command_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_IN_PROCESS:
|
||||
apdu_len =
|
||||
encode_application_boolean(&apdu[0],
|
||||
Command_In_Process(rpdata->object_instance));
|
||||
apdu_len = encode_application_boolean(
|
||||
&apdu[0], Command_In_Process(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_ALL_WRITES_SUCCESSFUL:
|
||||
apdu_len =
|
||||
encode_application_boolean(&apdu[0],
|
||||
apdu_len = encode_application_boolean(
|
||||
&apdu[0],
|
||||
Command_All_Writes_Successful(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_ACTION:
|
||||
/* TODO */
|
||||
if (rpdata->array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], MAX_COMMAND_ACTIONS);
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], MAX_COMMAND_ACTIONS);
|
||||
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
int i;
|
||||
for (i = 0; i < MAX_COMMAND_ACTIONS; i++) {
|
||||
@@ -710,12 +648,12 @@ int Command_Read_Property(
|
||||
&CurrentCommand->Action[0];
|
||||
/* another loop, for aditional actions in the list */
|
||||
for (; Curr_CL_Member != NULL;
|
||||
Curr_CL_Member = Curr_CL_Member->next) {
|
||||
len =
|
||||
cl_encode_apdu(&apdu[apdu_len],
|
||||
&CurrentCommand->Action[0]);
|
||||
Curr_CL_Member = Curr_CL_Member->next) {
|
||||
len = cl_encode_apdu(&apdu[apdu_len],
|
||||
&CurrentCommand->Action[0]);
|
||||
apdu_len += len;
|
||||
/* assume the next one is of the same length, which need not be the case */
|
||||
/* assume the next one is of the same length, which need
|
||||
* not be the case */
|
||||
if ((i != MAX_COMMAND_ACTIONS - 1) &&
|
||||
(apdu_len + len) >= apdu_max) {
|
||||
rpdata->error_code =
|
||||
@@ -731,12 +669,12 @@ int Command_Read_Property(
|
||||
&CurrentCommand->Action[rpdata->array_index];
|
||||
/* another loop, for aditional actions in the list */
|
||||
for (; Curr_CL_Member != NULL;
|
||||
Curr_CL_Member = Curr_CL_Member->next) {
|
||||
len =
|
||||
cl_encode_apdu(&apdu[apdu_len],
|
||||
&CurrentCommand->Action[0]);
|
||||
Curr_CL_Member = Curr_CL_Member->next) {
|
||||
len = cl_encode_apdu(&apdu[apdu_len],
|
||||
&CurrentCommand->Action[0]);
|
||||
apdu_len += len;
|
||||
/* assume the next one is of the same length, which need not be the case */
|
||||
/* assume the next one is of the same length, which need
|
||||
* not be the case */
|
||||
if ((apdu_len + len) >= apdu_max) {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
@@ -758,8 +696,8 @@ int Command_Read_Property(
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_ACTION)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_ACTION) &&
|
||||
(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;
|
||||
@@ -777,17 +715,15 @@ int Command_Read_Property(
|
||||
*
|
||||
* @return false if an error is loaded, true if no errors
|
||||
*/
|
||||
bool Command_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Command_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
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);
|
||||
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 */
|
||||
@@ -807,11 +743,11 @@ bool Command_Write_Property(
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ((int) wp_data->object_property) {
|
||||
switch ((int)wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
if (value.type.Unsigned_Int >= MAX_COMMAND_ACTIONS) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -819,7 +755,7 @@ bool Command_Write_Property(
|
||||
return false;
|
||||
}
|
||||
Command_Present_Value_Set(wp_data->object_instance,
|
||||
value.type.Unsigned_Int);
|
||||
value.type.Unsigned_Int);
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
@@ -846,8 +782,7 @@ bool Command_Write_Property(
|
||||
return status;
|
||||
}
|
||||
|
||||
void Command_Intrinsic_Reporting(
|
||||
uint32_t object_instance)
|
||||
void Command_Intrinsic_Reporting(uint32_t object_instance)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -856,11 +791,9 @@ void Command_Intrinsic_Reporting(
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
bool bResult;
|
||||
|
||||
@@ -878,10 +811,9 @@ bool WPValidateArgType(
|
||||
return (bResult);
|
||||
}
|
||||
|
||||
void testCommand(
|
||||
Test * pTest)
|
||||
void testCommand(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -926,10 +858,9 @@ void testCommand(
|
||||
ct_test(pTest, clist.Device_Id.instance == clist_test.Device_Id.instance);
|
||||
ct_test(pTest, clist.Object_Id.type == clist_test.Object_Id.type);
|
||||
ct_test(pTest, clist.Object_Id.instance == clist_test.Object_Id.instance);
|
||||
ct_test(pTest, clist.Property_Identifier == clist_test.Property_Identifier);
|
||||
ct_test(pTest,
|
||||
clist.Property_Identifier == clist_test.Property_Identifier);
|
||||
ct_test(pTest,
|
||||
clist.Property_Array_Index == clist_test.Property_Array_Index);
|
||||
clist.Property_Array_Index == clist_test.Property_Array_Index);
|
||||
ct_test(pTest, clist.Value.tag == clist_test.Value.tag);
|
||||
ct_test(pTest, clist.Value.type.Real == clist_test.Value.type.Real);
|
||||
ct_test(pTest, clist.Priority == clist_test.Priority);
|
||||
@@ -940,8 +871,7 @@ void testCommand(
|
||||
}
|
||||
|
||||
#ifdef TEST_COMMAND
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -953,7 +883,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* 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 */
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "credential_data_input.h"
|
||||
#include "handlers.h"
|
||||
@@ -44,30 +44,19 @@ 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
|
||||
};
|
||||
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_Optional[] = {-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Credential_Data_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Credential_Data_Input_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -79,8 +68,7 @@ void Credential_Data_Input_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Credential_Data_Input_Init(
|
||||
void)
|
||||
void Credential_Data_Input_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -107,8 +95,7 @@ void Credential_Data_Input_Init(
|
||||
/* 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)
|
||||
bool Credential_Data_Input_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
|
||||
return true;
|
||||
@@ -118,8 +105,7 @@ bool Credential_Data_Input_Valid_Instance(
|
||||
|
||||
/* 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)
|
||||
unsigned Credential_Data_Input_Count(void)
|
||||
{
|
||||
return MAX_CREDENTIAL_DATA_INPUTS;
|
||||
}
|
||||
@@ -127,8 +113,7 @@ unsigned Credential_Data_Input_Count(
|
||||
/* 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)
|
||||
uint32_t Credential_Data_Input_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -136,8 +121,7 @@ uint32_t Credential_Data_Input_Index_To_Instance(
|
||||
/* 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 Credential_Data_Input_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_CREDENTIAL_DATA_INPUTS;
|
||||
|
||||
@@ -148,24 +132,22 @@ unsigned Credential_Data_Input_Instance_To_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)
|
||||
bool Credential_Data_Input_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
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);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Credential_Data_Input_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
bool Credential_Data_Input_Out_Of_Service(uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
@@ -178,9 +160,7 @@ bool Credential_Data_Input_Out_Of_Service(
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Credential_Data_Input_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
void Credential_Data_Input_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -191,11 +171,10 @@ void Credential_Data_Input_Out_Of_Service_Set(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Credential_Data_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Credential_Data_Input_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -212,25 +191,23 @@ int Credential_Data_Input_Read_Property(
|
||||
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);
|
||||
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);
|
||||
&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);
|
||||
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);
|
||||
apdu_len = bacapp_encode_authentication_factor(
|
||||
&apdu[apdu_len], &cdi_descr[object_index].present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
@@ -243,9 +220,8 @@ int Credential_Data_Input_Read_Property(
|
||||
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);
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], cdi_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state =
|
||||
@@ -254,14 +230,13 @@ int Credential_Data_Input_Read_Property(
|
||||
break;
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
cdi_descr[object_index].supported_formats_count);
|
||||
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],
|
||||
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;
|
||||
@@ -275,10 +250,10 @@ int Credential_Data_Input_Read_Property(
|
||||
} 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]);
|
||||
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;
|
||||
@@ -288,9 +263,8 @@ int Credential_Data_Input_Read_Property(
|
||||
|
||||
break;
|
||||
case PROP_UPDATE_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_timestamp(&apdu[0],
|
||||
&cdi_descr[object_index].timestamp);
|
||||
apdu_len = bacapp_encode_timestamp(
|
||||
&apdu[0], &cdi_descr[object_index].timestamp);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -299,8 +273,9 @@ int Credential_Data_Input_Read_Property(
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_SUPPORTED_FORMATS)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
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;
|
||||
@@ -310,18 +285,16 @@ int Credential_Data_Input_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Credential_Data_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Credential_Data_Input_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -336,17 +309,18 @@ bool Credential_Data_Input_Write_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);
|
||||
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)) {
|
||||
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);
|
||||
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));
|
||||
sizeof(BACNET_AUTHENTICATION_FACTOR));
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
@@ -357,14 +331,13 @@ bool Credential_Data_Input_Write_Property(
|
||||
}
|
||||
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 (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;
|
||||
cdi_descr[object_index].reliability = value.type.Enumerated;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -390,17 +363,14 @@ bool Credential_Data_Input_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -410,10 +380,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testCredentialDataInput(
|
||||
Test * pTest)
|
||||
void testCredentialDataInput(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -440,8 +409,7 @@ void testCredentialDataInput(
|
||||
}
|
||||
|
||||
#ifdef TEST_CREDENTIAL_DATA_INPUT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -453,7 +421,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+91
-128
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* CharacterString Value Objects */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "csv.h"
|
||||
@@ -52,29 +52,17 @@ static char Object_Description[MAX_CHARACTERSTRING_VALUES][64];
|
||||
|
||||
/* 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,
|
||||
-1
|
||||
};
|
||||
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, -1};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
static const int Properties_Optional[] = {PROP_EVENT_STATE, PROP_OUT_OF_SERVICE,
|
||||
PROP_DESCRIPTION, -1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void CharacterString_Value_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void CharacterString_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -86,17 +74,16 @@ void CharacterString_Value_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void CharacterString_Value_Init(
|
||||
void)
|
||||
void CharacterString_Value_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/* initialize all Present Values */
|
||||
for (i = 0; i < MAX_CHARACTERSTRING_VALUES; i++) {
|
||||
snprintf(&Object_Name[i][0], sizeof(Object_Name[i]),
|
||||
"CHARACTER STRING VALUE %u", i+1);
|
||||
"CHARACTER STRING VALUE %u", i + 1);
|
||||
snprintf(&Object_Description[i][0], sizeof(Object_Description[i]),
|
||||
"A Character String Value Example");
|
||||
"A Character String Value Example");
|
||||
characterstring_init_ansi(&Present_Value[i], "");
|
||||
}
|
||||
|
||||
@@ -106,8 +93,7 @@ void CharacterString_Value_Init(
|
||||
/* 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 CharacterString_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned CharacterString_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_CHARACTERSTRING_VALUES;
|
||||
|
||||
@@ -121,22 +107,19 @@ unsigned CharacterString_Value_Instance_To_Index(
|
||||
/* 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 CharacterString_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t CharacterString_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned CharacterString_Value_Count(
|
||||
void)
|
||||
unsigned CharacterString_Value_Count(void)
|
||||
{
|
||||
return MAX_CHARACTERSTRING_VALUES;
|
||||
}
|
||||
|
||||
bool CharacterString_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool CharacterString_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
|
||||
@@ -148,9 +131,8 @@ bool CharacterString_Value_Valid_Instance(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CharacterString_Value_Present_Value(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool CharacterString_Value_Present_Value(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
@@ -164,8 +146,7 @@ bool CharacterString_Value_Present_Value(
|
||||
}
|
||||
|
||||
bool CharacterString_Value_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
@@ -178,8 +159,7 @@ bool CharacterString_Value_Present_Value_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool CharacterString_Value_Out_Of_Service(
|
||||
uint32_t object_instance)
|
||||
bool CharacterString_Value_Out_Of_Service(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned index = 0;
|
||||
@@ -192,9 +172,8 @@ bool CharacterString_Value_Out_Of_Service(
|
||||
return value;
|
||||
}
|
||||
|
||||
static void CharacterString_Value_Out_Of_Service_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
static void CharacterString_Value_Out_Of_Service_Set(uint32_t object_instance,
|
||||
bool value)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -206,8 +185,7 @@ static void CharacterString_Value_Out_Of_Service_Set(
|
||||
return;
|
||||
}
|
||||
|
||||
static char *CharacterString_Value_Description(
|
||||
uint32_t object_instance)
|
||||
static char *CharacterString_Value_Description(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
char *pName = NULL; /* return value */
|
||||
@@ -220,13 +198,12 @@ static char *CharacterString_Value_Description(
|
||||
return pName;
|
||||
}
|
||||
|
||||
bool CharacterString_Value_Description_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name)
|
||||
bool CharacterString_Value_Description_Set(uint32_t object_instance,
|
||||
char *new_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = CharacterString_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_CHARACTERSTRING_VALUES) {
|
||||
@@ -248,9 +225,8 @@ bool CharacterString_Value_Description_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool CharacterString_Value_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool CharacterString_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
bool status = false;
|
||||
@@ -264,13 +240,11 @@ bool CharacterString_Value_Object_Name(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool CharacterString_Value_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name)
|
||||
bool CharacterString_Value_Name_Set(uint32_t object_instance, char *new_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = CharacterString_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_CHARACTERSTRING_VALUES) {
|
||||
@@ -294,10 +268,9 @@ bool CharacterString_Value_Name_Set(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int CharacterString_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int CharacterString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -311,32 +284,32 @@ int CharacterString_Value_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_CHARACTERSTRING_VALUE, rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_CHARACTERSTRING_VALUE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
CharacterString_Value_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
characterstring_init_ansi(
|
||||
&char_string,
|
||||
CharacterString_Value_Description(rpdata->object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_CHARACTERSTRING_VALUE);
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], OBJECT_CHARACTERSTRING_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
CharacterString_Value_Present_Value(rpdata->object_instance,
|
||||
&char_string);
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
@@ -348,10 +321,10 @@ int CharacterString_Value_Read_Property(
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
if (CharacterString_Value_Out_Of_Service(rpdata->object_instance)) {
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
true);
|
||||
true);
|
||||
} else {
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
false);
|
||||
false);
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
@@ -361,9 +334,8 @@ int CharacterString_Value_Read_Property(
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
object_index =
|
||||
CharacterString_Value_Instance_To_Index
|
||||
(rpdata->object_instance);
|
||||
object_index = CharacterString_Value_Instance_To_Index(
|
||||
rpdata->object_instance);
|
||||
state = Out_Of_Service[object_index];
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
@@ -385,17 +357,15 @@ int CharacterString_Value_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool CharacterString_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool CharacterString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -405,14 +375,12 @@ bool CharacterString_Value_Write_Property(
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
status =
|
||||
WPValidateArgType(&value,
|
||||
BACNET_APPLICATION_TAG_CHARACTER_STRING, &wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
status = WPValidateArgType(
|
||||
&value, BACNET_APPLICATION_TAG_CHARACTER_STRING,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
status =
|
||||
CharacterString_Value_Present_Value_Set
|
||||
(wp_data->object_instance, &value.type.Character_String);
|
||||
status = CharacterString_Value_Present_Value_Set(
|
||||
wp_data->object_instance, &value.type.Character_String);
|
||||
if (!status) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
@@ -422,10 +390,10 @@ bool CharacterString_Value_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
CharacterString_Value_Out_Of_Service_Set
|
||||
(wp_data->object_instance, value.type.Boolean);
|
||||
CharacterString_Value_Out_Of_Service_Set(
|
||||
wp_data->object_instance, value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -446,17 +414,14 @@ bool CharacterString_Value_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -466,10 +431,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testCharacterStringValue(
|
||||
Test * pTest)
|
||||
void testCharacterStringValue(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -496,8 +460,7 @@ void testCharacterStringValue(
|
||||
}
|
||||
|
||||
#ifdef TEST_CHARACTERSTRING_VALUE
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -509,7 +472,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+153
-230
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/** @file device-client.c Lightweight base "class" for handling all
|
||||
* BACnet objects belonging to a BACnet device, as well as
|
||||
@@ -30,8 +30,8 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memmove */
|
||||
#include <time.h> /* for timezone, localtime */
|
||||
#include <string.h> /* for memmove */
|
||||
#include <time.h> /* for timezone, localtime */
|
||||
/* OS specific include*/
|
||||
#include "net.h"
|
||||
#include "timer.h"
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "apdu.h"
|
||||
#include "rp.h" /* ReadProperty handling */
|
||||
#include "version.h"
|
||||
@@ -51,7 +51,7 @@
|
||||
#include "netport.h"
|
||||
#endif
|
||||
/* include the device object */
|
||||
#include "device.h" /* me */
|
||||
#include "device.h" /* me */
|
||||
|
||||
#if defined(__BORLANDC__) || defined(_WIN32)
|
||||
/* seems to not be defined in time.h as specified by The Open Group */
|
||||
@@ -82,14 +82,14 @@ static char *Description = "command line client";
|
||||
/* static uint8_t Max_Segments_Accepted = 0; */
|
||||
/* VT_Classes_Supported */
|
||||
/* Active_VT_Sessions */
|
||||
static BACNET_TIME Local_Time; /* rely on OS, if there is one */
|
||||
static BACNET_DATE Local_Date; /* rely on OS, if there is one */
|
||||
static BACNET_TIME Local_Time; /* rely on OS, if there is one */
|
||||
static BACNET_DATE Local_Date; /* rely on OS, if there is one */
|
||||
/* NOTE: BACnet UTC Offset is inverse of common practice.
|
||||
If your UTC offset is -5hours of GMT,
|
||||
then BACnet UTC offset is +5hours.
|
||||
BACnet UTC offset is expressed in minutes. */
|
||||
static int32_t UTC_Offset = 5 * 60;
|
||||
static bool Daylight_Savings_Status = false; /* rely on OS */
|
||||
static bool Daylight_Savings_Status = false; /* rely on OS */
|
||||
#if defined(BACNET_TIME_MASTER)
|
||||
static bool Align_Intervals;
|
||||
static uint32_t Interval_Minutes;
|
||||
@@ -112,68 +112,40 @@ static uint32_t Database_Revision = 0;
|
||||
/* Profile_Name */
|
||||
|
||||
/* local forward (semi-private) and external prototypes */
|
||||
int Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
extern int Routed_Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata);
|
||||
extern int Routed_Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata);
|
||||
extern bool Routed_Device_Write_Property_Local(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
BACNET_WRITE_PROPERTY_DATA *wp_data);
|
||||
|
||||
/* All included BACnet objects */
|
||||
static object_functions_t Object_Table[] = {
|
||||
{OBJECT_DEVICE,
|
||||
NULL /* Init - don't init Device or it will recourse! */ ,
|
||||
Device_Count,
|
||||
Device_Index_To_Instance,
|
||||
Device_Valid_Object_Instance_Number,
|
||||
Device_Object_Name,
|
||||
Device_Read_Property_Local,
|
||||
NULL /* Write_Property */ ,
|
||||
NULL /* Property_Lists */ ,
|
||||
NULL /* ReadRangeInfo */ ,
|
||||
NULL /* Iterator */ ,
|
||||
NULL /* Value_Lists */ ,
|
||||
NULL /* COV */ ,
|
||||
NULL /* COV Clear */ ,
|
||||
NULL /* Intrinsic Reporting */ },
|
||||
{OBJECT_DEVICE, NULL /* Init - don't init Device or it will recourse! */,
|
||||
Device_Count, Device_Index_To_Instance,
|
||||
Device_Valid_Object_Instance_Number, Device_Object_Name,
|
||||
Device_Read_Property_Local, NULL /* Write_Property */,
|
||||
NULL /* Property_Lists */, NULL /* ReadRangeInfo */, NULL /* Iterator */,
|
||||
NULL /* Value_Lists */, NULL /* COV */, NULL /* COV Clear */,
|
||||
NULL /* Intrinsic Reporting */},
|
||||
#if (BACNET_PROTOCOL_REVISION >= 17)
|
||||
{OBJECT_NETWORK_PORT,
|
||||
Network_Port_Init,
|
||||
Network_Port_Count,
|
||||
Network_Port_Index_To_Instance,
|
||||
Network_Port_Valid_Instance,
|
||||
Network_Port_Object_Name,
|
||||
Network_Port_Read_Property,
|
||||
Network_Port_Write_Property,
|
||||
Network_Port_Property_Lists,
|
||||
NULL /* ReadRangeInfo */ ,
|
||||
NULL /* Iterator */ ,
|
||||
NULL /* Value_Lists */ ,
|
||||
NULL /* COV */ ,
|
||||
NULL /* COV Clear */ ,
|
||||
NULL /* Intrinsic Reporting */ },
|
||||
{OBJECT_NETWORK_PORT, Network_Port_Init, Network_Port_Count,
|
||||
Network_Port_Index_To_Instance, Network_Port_Valid_Instance,
|
||||
Network_Port_Object_Name, Network_Port_Read_Property,
|
||||
Network_Port_Write_Property, Network_Port_Property_Lists,
|
||||
NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */,
|
||||
NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */},
|
||||
#endif
|
||||
{MAX_BACNET_OBJECT_TYPE,
|
||||
NULL /* Init */ ,
|
||||
NULL /* Count */ ,
|
||||
NULL /* Index_To_Instance */ ,
|
||||
NULL /* Valid_Instance */ ,
|
||||
NULL /* Object_Name */ ,
|
||||
NULL /* Read_Property */ ,
|
||||
NULL /* Write_Property */ ,
|
||||
NULL /* Property_Lists */ ,
|
||||
NULL /* ReadRangeInfo */ ,
|
||||
NULL /* Iterator */ ,
|
||||
NULL /* Value_Lists */ ,
|
||||
NULL /* COV */ ,
|
||||
NULL /* COV Clear */ ,
|
||||
NULL /* Intrinsic Reporting */ }
|
||||
};
|
||||
{MAX_BACNET_OBJECT_TYPE, NULL /* Init */, NULL /* Count */,
|
||||
NULL /* Index_To_Instance */, NULL /* Valid_Instance */,
|
||||
NULL /* Object_Name */, NULL /* Read_Property */,
|
||||
NULL /* Write_Property */, NULL /* Property_Lists */,
|
||||
NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */,
|
||||
NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */}};
|
||||
|
||||
/** Glue function to let the Device object, when called by a handler,
|
||||
* lookup which Object type needs to be invoked.
|
||||
* @ingroup ObjHelpers
|
||||
* @param Object_Type [in] The type of BACnet Object the handler wants to access.
|
||||
* @param Object_Type [in] The type of BACnet Object the handler wants to
|
||||
* access.
|
||||
* @return Pointer to the group of object helper functions that implement this
|
||||
* type of Object.
|
||||
*/
|
||||
@@ -195,14 +167,12 @@ static struct object_functions *Device_Objects_Find_Functions(
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
unsigned Device_Count(
|
||||
void)
|
||||
unsigned Device_Count(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t Device_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Device_Index_To_Instance(unsigned index)
|
||||
{
|
||||
index = index;
|
||||
return Object_Instance_Number;
|
||||
@@ -216,8 +186,7 @@ uint32_t Device_Index_To_Instance(
|
||||
* @ingroup ObjIntf
|
||||
* @return The Instance number used in the BACNET_OBJECT_ID for the Device.
|
||||
*/
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void)
|
||||
uint32_t Device_Object_Instance_Number(void)
|
||||
{
|
||||
#ifdef BAC_ROUTING
|
||||
return Routed_Device_Object_Instance_Number();
|
||||
@@ -226,8 +195,7 @@ uint32_t Device_Object_Instance_Number(
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
bool Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
{
|
||||
bool status = true; /* return value */
|
||||
|
||||
@@ -241,15 +209,13 @@ bool Device_Set_Object_Instance_Number(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||
{
|
||||
return (Object_Instance_Number == object_id);
|
||||
}
|
||||
|
||||
bool Device_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Device_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
@@ -260,10 +226,9 @@ bool Device_Object_Name(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Name(
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Device_Set_Object_Name(BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
bool status = false; /*return value */
|
||||
|
||||
if (!characterstring_same(&My_Object_Name, object_name)) {
|
||||
/* Make the change and update the database revision */
|
||||
@@ -274,17 +239,14 @@ bool Device_Set_Object_Name(
|
||||
return status;
|
||||
}
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(
|
||||
void)
|
||||
BACNET_DEVICE_STATUS Device_System_Status(void)
|
||||
{
|
||||
return System_Status;
|
||||
}
|
||||
|
||||
int Device_Set_System_Status(
|
||||
BACNET_DEVICE_STATUS status,
|
||||
bool local)
|
||||
int Device_Set_System_Status(BACNET_DEVICE_STATUS status, bool local)
|
||||
{
|
||||
int result = 0; /*return value - 0 = ok, -1 = bad value, -2 = not allowed */
|
||||
int result = 0; /*return value - 0 = ok, -1 = bad value, -2 = not allowed */
|
||||
|
||||
/* We limit the options available depending on whether the source is
|
||||
* internal or external. */
|
||||
@@ -345,39 +307,34 @@ int Device_Set_System_Status(
|
||||
return (result);
|
||||
}
|
||||
|
||||
const char *Device_Vendor_Name(
|
||||
void)
|
||||
const char *Device_Vendor_Name(void)
|
||||
{
|
||||
return Vendor_Name;
|
||||
}
|
||||
|
||||
/** Returns the Vendor ID for this Device.
|
||||
* See the assignments at http://www.bacnet.org/VendorID/BACnet%20Vendor%20IDs.htm
|
||||
* See the assignments at
|
||||
* http://www.bacnet.org/VendorID/BACnet%20Vendor%20IDs.htm
|
||||
* @return The Vendor ID of this Device.
|
||||
*/
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void)
|
||||
uint16_t Device_Vendor_Identifier(void)
|
||||
{
|
||||
return Vendor_Identifier;
|
||||
}
|
||||
|
||||
void Device_Set_Vendor_Identifier(
|
||||
uint16_t vendor_id)
|
||||
void Device_Set_Vendor_Identifier(uint16_t vendor_id)
|
||||
{
|
||||
Vendor_Identifier = vendor_id;
|
||||
}
|
||||
|
||||
const char *Device_Model_Name(
|
||||
void)
|
||||
const char *Device_Model_Name(void)
|
||||
{
|
||||
return Model_Name;
|
||||
}
|
||||
|
||||
bool Device_Set_Model_Name(
|
||||
const char *name,
|
||||
size_t length)
|
||||
bool Device_Set_Model_Name(const char *name, size_t length)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
bool status = false; /*return value */
|
||||
|
||||
if (length < sizeof(Model_Name)) {
|
||||
memmove(Model_Name, name, length);
|
||||
@@ -388,23 +345,19 @@ bool Device_Set_Model_Name(
|
||||
return status;
|
||||
}
|
||||
|
||||
const char *Device_Firmware_Revision(
|
||||
void)
|
||||
const char *Device_Firmware_Revision(void)
|
||||
{
|
||||
return BACnet_Version;
|
||||
}
|
||||
|
||||
const char *Device_Application_Software_Version(
|
||||
void)
|
||||
const char *Device_Application_Software_Version(void)
|
||||
{
|
||||
return Application_Software_Version;
|
||||
}
|
||||
|
||||
bool Device_Set_Application_Software_Version(
|
||||
const char *name,
|
||||
size_t length)
|
||||
bool Device_Set_Application_Software_Version(const char *name, size_t length)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
bool status = false; /*return value */
|
||||
|
||||
if (length < sizeof(Application_Software_Version)) {
|
||||
memmove(Application_Software_Version, name, length);
|
||||
@@ -415,17 +368,14 @@ bool Device_Set_Application_Software_Version(
|
||||
return status;
|
||||
}
|
||||
|
||||
const char *Device_Description(
|
||||
void)
|
||||
const char *Device_Description(void)
|
||||
{
|
||||
return Description;
|
||||
}
|
||||
|
||||
bool Device_Set_Description(
|
||||
const char *name,
|
||||
size_t length)
|
||||
bool Device_Set_Description(const char *name, size_t length)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
bool status = false; /*return value */
|
||||
|
||||
if (length < sizeof(Description)) {
|
||||
memmove(Description, name, length);
|
||||
@@ -436,17 +386,14 @@ bool Device_Set_Description(
|
||||
return status;
|
||||
}
|
||||
|
||||
const char *Device_Location(
|
||||
void)
|
||||
const char *Device_Location(void)
|
||||
{
|
||||
return Location;
|
||||
}
|
||||
|
||||
bool Device_Set_Location(
|
||||
const char *name,
|
||||
size_t length)
|
||||
bool Device_Set_Location(const char *name, size_t length)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
bool status = false; /*return value */
|
||||
|
||||
if (length < sizeof(Location)) {
|
||||
memmove(Location, name, length);
|
||||
@@ -457,32 +404,27 @@ bool Device_Set_Location(
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Version(
|
||||
void)
|
||||
uint8_t Device_Protocol_Version(void)
|
||||
{
|
||||
return BACNET_PROTOCOL_VERSION;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Revision(
|
||||
void)
|
||||
uint8_t Device_Protocol_Revision(void)
|
||||
{
|
||||
return BACNET_PROTOCOL_REVISION;
|
||||
}
|
||||
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||
void)
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void)
|
||||
{
|
||||
return SEGMENTATION_NONE;
|
||||
}
|
||||
|
||||
uint32_t Device_Database_Revision(
|
||||
void)
|
||||
uint32_t Device_Database_Revision(void)
|
||||
{
|
||||
return Database_Revision;
|
||||
}
|
||||
|
||||
void Device_Set_Database_Revision(
|
||||
uint32_t revision)
|
||||
void Device_Set_Database_Revision(uint32_t revision)
|
||||
{
|
||||
Database_Revision = revision;
|
||||
}
|
||||
@@ -492,8 +434,7 @@ void Device_Set_Database_Revision(
|
||||
* the most common operation if changing object names and ids is
|
||||
* implemented.
|
||||
*/
|
||||
void Device_Inc_Database_Revision(
|
||||
void)
|
||||
void Device_Inc_Database_Revision(void)
|
||||
{
|
||||
Database_Revision++;
|
||||
}
|
||||
@@ -503,8 +444,7 @@ void Device_Inc_Database_Revision(
|
||||
* for discovery, it must be consistent!
|
||||
* @return The count of objects, for all supported Object types.
|
||||
*/
|
||||
unsigned Device_Object_List_Count(
|
||||
void)
|
||||
unsigned Device_Object_List_Count(void)
|
||||
{
|
||||
unsigned count = 0; /* number of objects */
|
||||
struct object_functions *pObject = NULL;
|
||||
@@ -531,10 +471,8 @@ unsigned Device_Object_List_Count(
|
||||
* @param instance [out] The object's instance number, if found.
|
||||
* @return True if found, else false.
|
||||
*/
|
||||
bool Device_Object_List_Identifier(
|
||||
uint32_t array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance)
|
||||
bool Device_Object_List_Identifier(uint32_t array_index, int *object_type,
|
||||
uint32_t *instance)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned count = 0;
|
||||
@@ -558,19 +496,19 @@ bool Device_Object_List_Identifier(
|
||||
* look for the index to instance to get the ID */
|
||||
if (pObject->Object_Iterator) {
|
||||
/* First find the first object */
|
||||
temp_index = pObject->Object_Iterator(~(unsigned) 0);
|
||||
temp_index = pObject->Object_Iterator(~(unsigned)0);
|
||||
/* Then step through the objects to find the nth */
|
||||
while (object_index != 0) {
|
||||
temp_index = pObject->Object_Iterator(temp_index);
|
||||
object_index--;
|
||||
}
|
||||
/* set the object_index up before falling through to next bit */
|
||||
/* set the object_index up before falling through to next
|
||||
* bit */
|
||||
object_index = temp_index;
|
||||
}
|
||||
if (pObject->Object_Index_To_Instance) {
|
||||
*object_type = pObject->Object_Type;
|
||||
*instance =
|
||||
pObject->Object_Index_To_Instance(object_index);
|
||||
*instance = pObject->Object_Index_To_Instance(object_index);
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
@@ -587,13 +525,12 @@ bool Device_Object_List_Identifier(
|
||||
* and the lookup succeeds, they will be given the resulting values.
|
||||
* @param object_name [in] The desired Object Name to look for.
|
||||
* @param object_type [out] The BACNET_OBJECT_TYPE of the matching Object.
|
||||
* @param object_instance [out] The object instance number of the matching Object.
|
||||
* @param object_instance [out] The object instance number of the matching
|
||||
* Object.
|
||||
* @return True on success or else False if not found.
|
||||
*/
|
||||
bool Device_Valid_Object_Name(
|
||||
BACNET_CHARACTER_STRING * object_name1,
|
||||
int *object_type,
|
||||
uint32_t * object_instance)
|
||||
bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name1,
|
||||
int *object_type, uint32_t *object_instance)
|
||||
{
|
||||
bool found = false;
|
||||
int type = 0;
|
||||
@@ -610,7 +547,7 @@ bool Device_Valid_Object_Name(
|
||||
pObject = Device_Objects_Find_Functions(type);
|
||||
if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
|
||||
(pObject->Object_Name(instance, &object_name2) &&
|
||||
characterstring_same(object_name1, &object_name2))) {
|
||||
characterstring_same(object_name1, &object_name2))) {
|
||||
found = true;
|
||||
if (object_type) {
|
||||
*object_type = type;
|
||||
@@ -631,11 +568,9 @@ bool Device_Valid_Object_Name(
|
||||
* @param object_instance [in] The object instance number to be looked up.
|
||||
* @return True if found, else False if no such Object in this device.
|
||||
*/
|
||||
bool Device_Valid_Object_Id(
|
||||
int object_type,
|
||||
uint32_t object_instance)
|
||||
bool Device_Valid_Object_Id(int object_type, uint32_t object_instance)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
struct object_functions *pObject = NULL;
|
||||
|
||||
pObject = Device_Objects_Find_Functions(object_type);
|
||||
@@ -652,10 +587,9 @@ bool Device_Valid_Object_Id(
|
||||
* @param object_name [out] The Object Name found for this child Object.
|
||||
* @return True on success or else False if not found.
|
||||
*/
|
||||
bool Device_Object_Name_Copy(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Device_Object_Name_Copy(BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
struct object_functions *pObject = NULL;
|
||||
bool found = false;
|
||||
@@ -668,8 +602,7 @@ bool Device_Object_Name_Copy(
|
||||
return found;
|
||||
}
|
||||
|
||||
static void Update_Current_Time(
|
||||
void)
|
||||
static void Update_Current_Time(void)
|
||||
{
|
||||
struct tm *tblock = NULL;
|
||||
#if defined(_MSC_VER)
|
||||
@@ -700,15 +633,16 @@ int tm_isdst Daylight Savings flag.
|
||||
#endif
|
||||
|
||||
if (tblock) {
|
||||
datetime_set_date(&Local_Date, (uint16_t) tblock->tm_year + 1900,
|
||||
(uint8_t) tblock->tm_mon + 1, (uint8_t) tblock->tm_mday);
|
||||
datetime_set_date(&Local_Date, (uint16_t)tblock->tm_year + 1900,
|
||||
(uint8_t)tblock->tm_mon + 1,
|
||||
(uint8_t)tblock->tm_mday);
|
||||
#if !defined(_MSC_VER)
|
||||
datetime_set_time(&Local_Time, (uint8_t) tblock->tm_hour,
|
||||
(uint8_t) tblock->tm_min, (uint8_t) tblock->tm_sec,
|
||||
(uint8_t) (tv.tv_usec / 10000));
|
||||
datetime_set_time(&Local_Time, (uint8_t)tblock->tm_hour,
|
||||
(uint8_t)tblock->tm_min, (uint8_t)tblock->tm_sec,
|
||||
(uint8_t)(tv.tv_usec / 10000));
|
||||
#else
|
||||
datetime_set_time(&Local_Time, (uint8_t) tblock->tm_hour,
|
||||
(uint8_t) tblock->tm_min, (uint8_t) tblock->tm_sec, 0);
|
||||
datetime_set_time(&Local_Time, (uint8_t)tblock->tm_hour,
|
||||
(uint8_t)tblock->tm_min, (uint8_t)tblock->tm_sec, 0);
|
||||
#endif
|
||||
if (tblock->tm_isdst) {
|
||||
Daylight_Savings_Status = true;
|
||||
@@ -724,8 +658,7 @@ int tm_isdst Daylight Savings flag.
|
||||
}
|
||||
}
|
||||
|
||||
void Device_getCurrentDateTime(
|
||||
BACNET_DATE_TIME * DateTime)
|
||||
void Device_getCurrentDateTime(BACNET_DATE_TIME *DateTime)
|
||||
{
|
||||
Update_Current_Time();
|
||||
|
||||
@@ -821,11 +754,10 @@ uint32_t Device_Interval_Offset(void)
|
||||
|
||||
/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error or
|
||||
BACNET_STATUS_ABORT for abort message */
|
||||
int Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint32_t i = 0;
|
||||
@@ -843,9 +775,8 @@ int Device_Read_Property_Local(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
apdu_len =
|
||||
@@ -868,8 +799,7 @@ int Device_Read_Property_Local(
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Vendor_Identifier);
|
||||
apdu_len = encode_application_unsigned(&apdu[0], Vendor_Identifier);
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
characterstring_init_ansi(&char_string, Model_Name);
|
||||
@@ -883,7 +813,7 @@ int Device_Read_Property_Local(
|
||||
break;
|
||||
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Application_Software_Version);
|
||||
Application_Software_Version);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
@@ -893,22 +823,21 @@ int Device_Read_Property_Local(
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_VERSION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Version());
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Version());
|
||||
break;
|
||||
case PROP_PROTOCOL_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Revision());
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Revision());
|
||||
break;
|
||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||
/* Note: list of services that are executed, not initiated. */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||
/* automatic lookup based on handlers set */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||
apdu_service_supported((BACNET_SERVICES_SUPPORTED) i));
|
||||
bitstring_set_bit(
|
||||
&bit_string, (uint8_t)i,
|
||||
apdu_service_supported((BACNET_SERVICES_SUPPORTED)i));
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
@@ -918,7 +847,7 @@ int Device_Read_Property_Local(
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||
/* initialize all the object types to not-supported */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||
bitstring_set_bit(&bit_string, (uint8_t)i, false);
|
||||
}
|
||||
/* set the object types with objects to supported */
|
||||
|
||||
@@ -942,16 +871,15 @@ int Device_Read_Property_Local(
|
||||
/* your maximum APDU size. */
|
||||
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
found =
|
||||
Device_Object_List_Identifier(i, &object_type,
|
||||
&instance);
|
||||
found = Device_Object_List_Identifier(i, &object_type,
|
||||
&instance);
|
||||
if (found) {
|
||||
len =
|
||||
encode_application_object_id(&apdu[apdu_len],
|
||||
object_type, instance);
|
||||
len = encode_application_object_id(
|
||||
&apdu[apdu_len], object_type, instance);
|
||||
apdu_len += len;
|
||||
/* assume next one is the same size as this one */
|
||||
/* can we all fit into the APDU? Don't check for last entry */
|
||||
/* can we all fit into the APDU? Don't check for last
|
||||
* entry */
|
||||
if ((i != count) && (apdu_len + len) >= MAX_APDU) {
|
||||
/* Abort response */
|
||||
rpdata->error_code =
|
||||
@@ -968,13 +896,11 @@ int Device_Read_Property_Local(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
found =
|
||||
Device_Object_List_Identifier(rpdata->array_index,
|
||||
&object_type, &instance);
|
||||
found = Device_Object_List_Identifier(rpdata->array_index,
|
||||
&object_type, &instance);
|
||||
if (found) {
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], object_type, instance);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
@@ -986,9 +912,8 @@ int Device_Read_Property_Local(
|
||||
apdu_len = encode_application_unsigned(&apdu[0], MAX_APDU);
|
||||
break;
|
||||
case PROP_SEGMENTATION_SUPPORTED:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
Device_Segmentation_Supported());
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], Device_Segmentation_Supported());
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], apdu_timeout());
|
||||
@@ -997,18 +922,17 @@ int Device_Read_Property_Local(
|
||||
apdu_len = encode_application_unsigned(&apdu[0], apdu_retries());
|
||||
break;
|
||||
case PROP_DEVICE_ADDRESS_BINDING:
|
||||
/* FIXME: the real max apdu remaining should be passed into function */
|
||||
/* FIXME: the real max apdu remaining should be passed into function
|
||||
*/
|
||||
apdu_len = address_list_encode(&apdu[0], MAX_APDU);
|
||||
break;
|
||||
case PROP_DATABASE_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], Database_Revision);
|
||||
apdu_len = encode_application_unsigned(&apdu[0], Database_Revision);
|
||||
break;
|
||||
#if defined(BACDL_MSTP)
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
dlmstp_max_info_frames());
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_info_frames());
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
apdu_len =
|
||||
@@ -1034,7 +958,8 @@ int Device_Read_Property_Local(
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/** Looks up the requested Object and Property, and encodes its Value in an APDU.
|
||||
/** Looks up the requested Object and Property, and encodes its Value in an
|
||||
* APDU.
|
||||
* @ingroup ObjIntf
|
||||
* If the Object or Property can't be found, sets the error class and code.
|
||||
*
|
||||
@@ -1042,8 +967,7 @@ int Device_Read_Property_Local(
|
||||
* on entry, and APDU message on return.
|
||||
* @return The length of the APDU on success, else BACNET_STATUS_ERROR
|
||||
*/
|
||||
int Device_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = BACNET_STATUS_ERROR;
|
||||
struct object_functions *pObject = NULL;
|
||||
@@ -1078,14 +1002,13 @@ int Device_Read_Property(
|
||||
* Each Child Object must provide some implementation of each of these
|
||||
* functions in order to properly support the default handlers.
|
||||
*/
|
||||
void Device_Init(
|
||||
object_functions_t * object_table)
|
||||
void Device_Init(object_functions_t *object_table)
|
||||
{
|
||||
struct object_functions *pObject = NULL;
|
||||
|
||||
characterstring_init_ansi(&My_Object_Name, "SimpleClient");
|
||||
/* we don't use the object table passed in */
|
||||
(void) object_table;
|
||||
(void)object_table;
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
if (pObject->Object_Init) {
|
||||
|
||||
+393
-700
File diff suppressed because it is too large
Load Diff
+115
-154
@@ -1,44 +1,45 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005,2010 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2005,2010 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/** @file gw_device.c Functions that extend the Device object to support routing. */
|
||||
/** @file gw_device.c Functions that extend the Device object to support
|
||||
* routing. */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memmove */
|
||||
#include <time.h> /* for timezone, localtime */
|
||||
#include <string.h> /* for memmove */
|
||||
#include <time.h> /* for timezone, localtime */
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "apdu.h"
|
||||
#include "wp.h" /* write property handling */
|
||||
#include "rp.h" /* read property handling */
|
||||
#include "version.h"
|
||||
#include "device.h" /* me */
|
||||
#include "device.h" /* me */
|
||||
#include "handlers.h"
|
||||
#include "datalink.h"
|
||||
#include "address.h"
|
||||
@@ -56,7 +57,7 @@
|
||||
#include "ms-input.h"
|
||||
#include "trendlog.h"
|
||||
#if defined(BACFILE)
|
||||
#include "bacfile.h" /* object list dependency */
|
||||
#include "bacfile.h" /* object list dependency */
|
||||
#endif
|
||||
/* os specfic includes */
|
||||
#include "timer.h"
|
||||
@@ -68,19 +69,15 @@ long int timezone;
|
||||
#endif
|
||||
|
||||
/* local forward and external prototypes */
|
||||
extern int Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
extern bool Device_Write_Property_Local(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
int Routed_Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Routed_Device_Write_Property_Local(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
extern int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata);
|
||||
extern bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data);
|
||||
int Routed_Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata);
|
||||
bool Routed_Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data);
|
||||
|
||||
#if !defined(BAC_ROUTING)
|
||||
#ifdef _MSC_VER
|
||||
#pragma message This file should not be included in the build unless BAC_ROUTING is enabled.
|
||||
#pragma message This file should not be included in the build unless \
|
||||
BAC_ROUTING is enabled.
|
||||
#else
|
||||
#warning This file should not be included in the build unless BAC_ROUTING is enabled.
|
||||
#endif
|
||||
@@ -118,10 +115,9 @@ uint16_t iCurrent_Device_Idx = 0;
|
||||
* @return The index of this instance in the Devices[] array,
|
||||
* or -1 if there isn't enough room to add this Device.
|
||||
*/
|
||||
uint16_t Add_Routed_Device(
|
||||
uint32_t Object_Instance,
|
||||
BACNET_CHARACTER_STRING * sObject_Name,
|
||||
const char *sDescription)
|
||||
uint16_t Add_Routed_Device(uint32_t Object_Instance,
|
||||
BACNET_CHARACTER_STRING *sObject_Name,
|
||||
const char *sDescription)
|
||||
{
|
||||
int i = Num_Managed_Devices;
|
||||
if (i < MAX_NUM_DEVICES) {
|
||||
@@ -132,21 +128,21 @@ uint16_t Add_Routed_Device(
|
||||
pDev->bacObj.Object_Instance_Number = Object_Instance;
|
||||
if (sObject_Name != NULL)
|
||||
Routed_Device_Set_Object_Name(sObject_Name->encoding,
|
||||
sObject_Name->value, sObject_Name->length);
|
||||
sObject_Name->value,
|
||||
sObject_Name->length);
|
||||
else
|
||||
Routed_Device_Set_Object_Name(CHARACTER_UTF8, "No Name",
|
||||
strlen("No Name"));
|
||||
strlen("No Name"));
|
||||
if (sDescription != NULL)
|
||||
Routed_Device_Set_Description(sDescription, strlen(sDescription));
|
||||
else
|
||||
Routed_Device_Set_Description("No Descr", strlen("No Descr"));
|
||||
pDev->Database_Revision = 0; /* Reset/Initialize now */
|
||||
pDev->Database_Revision = 0; /* Reset/Initialize now */
|
||||
return i;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/** Return the Device Object descriptive data for the indicated entry.
|
||||
* @param idx [in] Index into Devices[] array being requested.
|
||||
* 0 is for the main, gateway Device entry.
|
||||
@@ -156,8 +152,7 @@ uint16_t Add_Routed_Device(
|
||||
* @return Pointer to the requested Device Object data, or NULL if the idx
|
||||
* is for an invalid row entry (eg, after the last good Device).
|
||||
*/
|
||||
DEVICE_OBJECT_DATA *Get_Routed_Device_Object(
|
||||
int idx)
|
||||
DEVICE_OBJECT_DATA *Get_Routed_Device_Object(int idx)
|
||||
{
|
||||
if (idx == -1)
|
||||
return &Devices[iCurrent_Device_Idx];
|
||||
@@ -174,11 +169,10 @@ DEVICE_OBJECT_DATA *Get_Routed_Device_Object(
|
||||
* -1 is a special case meaning "whichever iCurrent_Device_Idx
|
||||
* is currently set to"
|
||||
* If valid idx, will set iCurrent_Device_Idx with the idx
|
||||
* @return Pointer to the requested Device Object BACnet address, or NULL if the idx
|
||||
* is for an invalid row entry (eg, after the last good Device).
|
||||
* @return Pointer to the requested Device Object BACnet address, or NULL if the
|
||||
* idx is for an invalid row entry (eg, after the last good Device).
|
||||
*/
|
||||
BACNET_ADDRESS *Get_Routed_Device_Address(
|
||||
int idx)
|
||||
BACNET_ADDRESS *Get_Routed_Device_Address(int idx)
|
||||
{
|
||||
if (idx == -1)
|
||||
return &Devices[iCurrent_Device_Idx].bacDevAddr;
|
||||
@@ -189,8 +183,6 @@ BACNET_ADDRESS *Get_Routed_Device_Address(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Get the currently active BACnet address.
|
||||
* This is an implementation of the datalink_get_my_address() template for
|
||||
* devices with routing.
|
||||
@@ -198,16 +190,14 @@ BACNET_ADDRESS *Get_Routed_Device_Address(
|
||||
* @param my_address [out] Points to the currently active Device Object's
|
||||
* BACnet address.
|
||||
*/
|
||||
void routed_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
void routed_get_my_address(BACNET_ADDRESS *my_address)
|
||||
{
|
||||
if (my_address) {
|
||||
memcpy(my_address, &Devices[iCurrent_Device_Idx].bacDevAddr,
|
||||
sizeof(BACNET_ADDRESS));
|
||||
sizeof(BACNET_ADDRESS));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** See if the Gateway or Routed Device at the given idx matches
|
||||
* the given MAC address.
|
||||
* Has the desirable side-effect of setting iCurrent_Device_Idx to the
|
||||
@@ -225,10 +215,8 @@ void routed_get_my_address(
|
||||
* meaning MAC broadcast, so it's an automatic match).
|
||||
* Else False if no match or invalid idx is given.
|
||||
*/
|
||||
bool Routed_Device_Address_Lookup(
|
||||
int idx,
|
||||
uint8_t address_len,
|
||||
uint8_t * mac_adress)
|
||||
bool Routed_Device_Address_Lookup(int idx, uint8_t address_len,
|
||||
uint8_t *mac_adress)
|
||||
{
|
||||
bool result = false;
|
||||
DEVICE_OBJECT_DATA *pDev = &Devices[idx];
|
||||
@@ -244,7 +232,7 @@ bool Routed_Device_Address_Lookup(
|
||||
if (pDev->bacDevAddr.mac[i] != mac_adress[i])
|
||||
break;
|
||||
}
|
||||
if (i == address_len) { /* Success! */
|
||||
if (i == address_len) { /* Success! */
|
||||
iCurrent_Device_Idx = idx;
|
||||
result = true;
|
||||
}
|
||||
@@ -253,7 +241,6 @@ bool Routed_Device_Address_Lookup(
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Find the next Gateway or Routed Device at the given MAC address,
|
||||
* starting the search at the "cursor".
|
||||
* Has the desirable side-effect of setting internal iCurrent_Device_Idx
|
||||
@@ -261,31 +248,27 @@ bool Routed_Device_Address_Lookup(
|
||||
* functions.
|
||||
*
|
||||
* @param dest [in] The BACNET_ADDRESS of the message's destination.
|
||||
* If the Length of the mac_adress[] field is 0, then this is a MAC
|
||||
* broadcast. Otherwise, size is determined
|
||||
* by the DLL type (eg, 6 for BIP and 2 for MSTP).
|
||||
* @param DNET_list [in] List of our reachable downstream BACnet Network numbers.
|
||||
* Normally just one valid entry; terminated with a -1 value.
|
||||
* If the Length of the mac_adress[] field is 0, then this is a
|
||||
* MAC broadcast. Otherwise, size is determined by the DLL type (eg, 6 for BIP
|
||||
* and 2 for MSTP).
|
||||
* @param DNET_list [in] List of our reachable downstream BACnet Network
|
||||
* numbers. Normally just one valid entry; terminated with a -1 value.
|
||||
* @param cursor [in,out] The concept of the cursor is that it is a starting
|
||||
* "hint" for the search; on return, it is updated to provide the
|
||||
* cursor value to use with a subsequent GetNext call, or it
|
||||
* equals -1 if there are no further matches.
|
||||
* Set it to 0 on entry to access the main, gateway Device entry, or
|
||||
* to start looping through the routed devices.
|
||||
* "hint" for the search; on return, it is updated to provide
|
||||
* the cursor value to use with a subsequent GetNext call, or it equals -1 if
|
||||
* there are no further matches. Set it to 0 on entry to access the main,
|
||||
* gateway Device entry, or to start looping through the routed devices.
|
||||
* Otherwise, its returned value is implementation-dependent and the
|
||||
* calling function should not alter or interpret it.
|
||||
*
|
||||
* @return True if the MAC addresses match (or if BACNET_BROADCAST_NETWORK and
|
||||
* the dest->len is 0, meaning MAC bcast, so it's an automatic match).
|
||||
* Else False if no match or invalid idx is given; the cursor will
|
||||
* be returned as -1 in these cases.
|
||||
* the dest->len is 0, meaning MAC bcast, so it's an automatic
|
||||
* match). Else False if no match or invalid idx is given; the cursor will be
|
||||
* returned as -1 in these cases.
|
||||
*/
|
||||
bool Routed_Device_GetNext(
|
||||
BACNET_ADDRESS * dest,
|
||||
int *DNET_list,
|
||||
int *cursor)
|
||||
bool Routed_Device_GetNext(BACNET_ADDRESS *dest, int *DNET_list, int *cursor)
|
||||
{
|
||||
int dnet = DNET_list[0]; /* Get the DNET of our virtual network */
|
||||
int dnet = DNET_list[0]; /* Get the DNET of our virtual network */
|
||||
int idx = *cursor;
|
||||
bool bSuccess = false;
|
||||
|
||||
@@ -319,44 +302,40 @@ bool Routed_Device_GetNext(
|
||||
* For broadcasts, all Devices get a chance at it.
|
||||
*/
|
||||
else if (dest->net == dnet) {
|
||||
if (idx == 0) /* Step over this case (starting point) */
|
||||
if (idx == 0) /* Step over this case (starting point) */
|
||||
idx = 1;
|
||||
while (idx < MAX_NUM_DEVICES) {
|
||||
bSuccess =
|
||||
Routed_Device_Address_Lookup(idx++, dest->len, dest->adr);
|
||||
if (bSuccess)
|
||||
break; /* We don't need to keep looking */
|
||||
break; /* We don't need to keep looking */
|
||||
}
|
||||
}
|
||||
|
||||
if (!bSuccess)
|
||||
*cursor = -1;
|
||||
else if (idx == MAX_NUM_DEVICES) /* No more to GetNext */
|
||||
else if (idx == MAX_NUM_DEVICES) /* No more to GetNext */
|
||||
*cursor = -1;
|
||||
else
|
||||
*cursor = idx;
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
|
||||
/** Check if the destination network is reachable - is it our virtual network,
|
||||
* or local or else broadcast.
|
||||
*
|
||||
* @param dest_net [in] The BACnet network number of a message's destination.
|
||||
* Success if it is our virtual network number, or 0 (local for the
|
||||
* gateway, or 0xFFFF for a broadcast network number.
|
||||
* @param DNET_list [in] List of our reachable downstream BACnet Network numbers.
|
||||
* Normally just one valid entry; terminated with a -1 value.
|
||||
* Success if it is our virtual network number, or 0 (local for
|
||||
* the gateway, or 0xFFFF for a broadcast network number.
|
||||
* @param DNET_list [in] List of our reachable downstream BACnet Network
|
||||
* numbers. Normally just one valid entry; terminated with a -1 value.
|
||||
* @return True if matches our virtual network, or is for the local network
|
||||
* Device (the gateway), or is BACNET_BROADCAST_NETWORK, which is
|
||||
* an automatic match.
|
||||
* Else False if not a reachable network.
|
||||
* Device (the gateway), or is BACNET_BROADCAST_NETWORK,
|
||||
* which is an automatic match. Else False if not a reachable network.
|
||||
*/
|
||||
bool Routed_Device_Is_Valid_Network(
|
||||
uint16_t dest_net,
|
||||
int *DNET_list)
|
||||
bool Routed_Device_Is_Valid_Network(uint16_t dest_net, int *DNET_list)
|
||||
{
|
||||
int dnet = DNET_list[0]; /* Get the DNET of our virtual network */
|
||||
int dnet = DNET_list[0]; /* Get the DNET of our virtual network */
|
||||
bool bSuccess = false;
|
||||
|
||||
/* First, see if it's a BACnet broadcast (automatic pass). */
|
||||
@@ -374,11 +353,9 @@ bool Routed_Device_Is_Valid_Network(
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
|
||||
/* methods to override the normal Device objection functions */
|
||||
|
||||
uint32_t Routed_Device_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Routed_Device_Index_To_Instance(unsigned index)
|
||||
{
|
||||
index = index;
|
||||
return Devices[iCurrent_Device_Idx].bacObj.Object_Instance_Number;
|
||||
@@ -389,11 +366,11 @@ uint32_t Routed_Device_Index_To_Instance(
|
||||
* iCurrent_Device_Idx must have been set to point to this Device Object
|
||||
* before this function is called.
|
||||
* @param object_id [in] Object ID of the desired Device object.
|
||||
* If the wildcard value (BACNET_MAX_INSTANCE), always matches.
|
||||
* If the wildcard value (BACNET_MAX_INSTANCE), always
|
||||
* matches.
|
||||
* @return True if Object ID matches the present Device, else False.
|
||||
*/
|
||||
bool Routed_Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
bool Routed_Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||
{
|
||||
bool bResult = false;
|
||||
DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx];
|
||||
@@ -404,14 +381,12 @@ bool Routed_Device_Valid_Object_Instance_Number(
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool Routed_Device_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Routed_Device_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx];
|
||||
if (object_instance == pDev->bacObj.Object_Instance_Number) {
|
||||
return characterstring_init_ansi(object_name,
|
||||
pDev->bacObj.Object_Name);
|
||||
return characterstring_init_ansi(object_name, pDev->bacObj.Object_Name);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -423,10 +398,9 @@ bool Routed_Device_Name(
|
||||
* @return The length of the apdu encoded, or BACNET_STATUS_ERROR for error or
|
||||
* BACNET_STATUS_ABORT for abort message.
|
||||
*/
|
||||
int Routed_Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Routed_Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx];
|
||||
@@ -438,9 +412,8 @@ int Routed_Device_Read_Property_Local(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
pDev->bacObj.Object_Instance_Number);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_DEVICE, pDev->bacObj.Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string, pDev->bacObj.Object_Name);
|
||||
@@ -464,17 +437,15 @@ int Routed_Device_Read_Property_Local(
|
||||
return (apdu_len);
|
||||
}
|
||||
|
||||
bool Routed_Device_Write_Property_Local(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Routed_Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
len = bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -493,12 +464,13 @@ bool Routed_Device_Write_Property_Local(
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_OBJECT_ID,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Routed_Device_Set_Object_Instance_Number(value.type.
|
||||
Object_Id.instance))) {
|
||||
/* FIXME: we could send an I-Am broadcast to let the world know */
|
||||
(Routed_Device_Set_Object_Instance_Number(
|
||||
value.type.Object_Id.instance))) {
|
||||
/* FIXME: we could send an I-Am broadcast to let the world
|
||||
* know */
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -509,10 +481,10 @@ bool Routed_Device_Write_Property_Local(
|
||||
case PROP_OBJECT_NAME:
|
||||
status =
|
||||
WPValidateString(&value, MAX_DEV_NAME_LEN, false,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Routed_Device_Set_Object_Name(characterstring_encoding(&value.
|
||||
type.Character_String),
|
||||
Routed_Device_Set_Object_Name(
|
||||
characterstring_encoding(&value.type.Character_String),
|
||||
characterstring_value(&value.type.Character_String),
|
||||
characterstring_length(&value.type.Character_String));
|
||||
}
|
||||
@@ -532,14 +504,12 @@ bool Routed_Device_Write_Property_Local(
|
||||
*
|
||||
* @return The Instance number of the currently active Device.
|
||||
*/
|
||||
uint32_t Routed_Device_Object_Instance_Number(
|
||||
void)
|
||||
uint32_t Routed_Device_Object_Instance_Number(void)
|
||||
{
|
||||
return Devices[iCurrent_Device_Idx].bacObj.Object_Instance_Number;
|
||||
}
|
||||
|
||||
bool Routed_Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
bool Routed_Device_Set_Object_Instance_Number(uint32_t object_id)
|
||||
{
|
||||
bool status = true; /* return value */
|
||||
|
||||
@@ -559,12 +529,10 @@ bool Routed_Device_Set_Object_Instance_Number(
|
||||
* @param object_name [in] Character String for the new Object Name.
|
||||
* @return True if succeed in updating Object Name, else False.
|
||||
*/
|
||||
bool Routed_Device_Set_Object_Name(
|
||||
uint8_t encoding,
|
||||
const char *value,
|
||||
size_t length)
|
||||
bool Routed_Device_Set_Object_Name(uint8_t encoding, const char *value,
|
||||
size_t length)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
bool status = false; /*return value */
|
||||
DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx];
|
||||
|
||||
if ((encoding == CHARACTER_UTF8) && (length < MAX_DEV_NAME_LEN)) {
|
||||
@@ -578,11 +546,9 @@ bool Routed_Device_Set_Object_Name(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Routed_Device_Set_Description(
|
||||
const char *name,
|
||||
size_t length)
|
||||
bool Routed_Device_Set_Description(const char *name, size_t length)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
bool status = false; /*return value */
|
||||
DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx];
|
||||
|
||||
if (length < MAX_DEV_DESC_LEN) {
|
||||
@@ -594,20 +560,17 @@ bool Routed_Device_Set_Description(
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shortcut for incrementing database revision as this is potentially
|
||||
* the most common operation if changing object names and ids is
|
||||
* implemented.
|
||||
*/
|
||||
void Routed_Device_Inc_Database_Revision(
|
||||
void)
|
||||
void Routed_Device_Inc_Database_Revision(void)
|
||||
{
|
||||
DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx];
|
||||
pDev->Database_Revision++;
|
||||
}
|
||||
|
||||
|
||||
/** Check to see if the current Device supports this service.
|
||||
* Presently checks for RD and DCC and only allows them if the current
|
||||
* device is the gateway device.
|
||||
@@ -621,11 +584,9 @@ void Routed_Device_Inc_Database_Revision(
|
||||
* just 1 if no apdu_buff was supplied and service is not supported,
|
||||
* else 0 if service is approved for the current device.
|
||||
*/
|
||||
int Routed_Device_Service_Approval(
|
||||
BACNET_CONFIRMED_SERVICE service,
|
||||
int service_argument,
|
||||
uint8_t * apdu_buff,
|
||||
uint8_t invoke_id)
|
||||
int Routed_Device_Service_Approval(BACNET_CONFIRMED_SERVICE service,
|
||||
int service_argument, uint8_t *apdu_buff,
|
||||
uint8_t invoke_id)
|
||||
{
|
||||
int len = 0;
|
||||
switch (service) {
|
||||
@@ -635,9 +596,9 @@ int Routed_Device_Service_Approval(
|
||||
if (apdu_buff != NULL)
|
||||
len =
|
||||
reject_encode_apdu(apdu_buff, invoke_id,
|
||||
REJECT_REASON_UNRECOGNIZED_SERVICE);
|
||||
REJECT_REASON_UNRECOGNIZED_SERVICE);
|
||||
else
|
||||
len = 1; /* Non-zero return */
|
||||
len = 1; /* Non-zero return */
|
||||
}
|
||||
break;
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
@@ -646,9 +607,9 @@ int Routed_Device_Service_Approval(
|
||||
if (apdu_buff != NULL)
|
||||
len =
|
||||
reject_encode_apdu(apdu_buff, invoke_id,
|
||||
REJECT_REASON_UNRECOGNIZED_SERVICE);
|
||||
REJECT_REASON_UNRECOGNIZED_SERVICE);
|
||||
else
|
||||
len = 1; /* Non-zero return */
|
||||
len = 1; /* Non-zero return */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
+49
-74
@@ -41,7 +41,7 @@
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
/* me! */
|
||||
@@ -52,31 +52,25 @@
|
||||
#endif
|
||||
|
||||
struct integer_object {
|
||||
bool Out_Of_Service:1;
|
||||
bool Out_Of_Service : 1;
|
||||
int32_t Present_Value;
|
||||
uint16_t Units;
|
||||
};
|
||||
struct integer_object Integer_Value[MAX_INTEGER_VALUES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Integer_Value_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_UNITS,
|
||||
-1
|
||||
};
|
||||
static const int Integer_Value_Properties_Required[] = {PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_UNITS,
|
||||
-1};
|
||||
|
||||
static const int Integer_Value_Properties_Optional[] = {
|
||||
PROP_OUT_OF_SERVICE,
|
||||
-1
|
||||
};
|
||||
static const int Integer_Value_Properties_Optional[] = {PROP_OUT_OF_SERVICE,
|
||||
-1};
|
||||
|
||||
static const int Integer_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Integer_Value_Properties_Proprietary[] = {-1};
|
||||
|
||||
/**
|
||||
* Returns the list of required, optional, and proprietary properties.
|
||||
@@ -89,10 +83,8 @@ static const int Integer_Value_Properties_Proprietary[] = {
|
||||
* @param pProprietary - pointer to list of int terminated by -1, of
|
||||
* BACnet proprietary properties for this object.
|
||||
*/
|
||||
void Integer_Value_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Integer_Value_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Integer_Value_Properties_Required;
|
||||
@@ -111,8 +103,7 @@ void Integer_Value_Property_Lists(
|
||||
*
|
||||
* @return true if the instance is valid, and false if not
|
||||
*/
|
||||
bool Integer_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Integer_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
@@ -129,8 +120,7 @@ bool Integer_Value_Valid_Instance(
|
||||
*
|
||||
* @return Number of Analog Value objects
|
||||
*/
|
||||
unsigned Integer_Value_Count(
|
||||
void)
|
||||
unsigned Integer_Value_Count(void)
|
||||
{
|
||||
return MAX_INTEGER_VALUES;
|
||||
}
|
||||
@@ -143,8 +133,7 @@ unsigned Integer_Value_Count(
|
||||
*
|
||||
* @return object instance-number for the given index
|
||||
*/
|
||||
uint32_t Integer_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Integer_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
uint32_t instance = 1;
|
||||
|
||||
@@ -162,8 +151,7 @@ uint32_t Integer_Value_Index_To_Instance(
|
||||
* @return index for the given instance-number, or MAX_INTEGER_VALUES
|
||||
* if not valid.
|
||||
*/
|
||||
unsigned Integer_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Integer_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_INTEGER_VALUES;
|
||||
|
||||
@@ -184,8 +172,7 @@ unsigned Integer_Value_Instance_To_Index(
|
||||
*
|
||||
* @return present-value of the object
|
||||
*/
|
||||
int32_t Integer_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
int32_t Integer_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
int32_t value = 0;
|
||||
unsigned int index;
|
||||
@@ -206,10 +193,8 @@ int32_t Integer_Value_Present_Value(
|
||||
*
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool Integer_Value_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
int32_t value,
|
||||
uint8_t priority)
|
||||
bool Integer_Value_Present_Value_Set(uint32_t object_instance, int32_t value,
|
||||
uint8_t priority)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index;
|
||||
@@ -234,9 +219,8 @@ bool Integer_Value_Present_Value_Set(
|
||||
*
|
||||
* @return true if object-name was retrieved
|
||||
*/
|
||||
bool Integer_Value_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Integer_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
char text_string[32] = "";
|
||||
unsigned int index;
|
||||
@@ -244,7 +228,8 @@ bool Integer_Value_Object_Name(
|
||||
|
||||
index = Integer_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_INTEGER_VALUES) {
|
||||
sprintf(text_string, "ANALOG VALUE %lu", (unsigned long) object_instance);
|
||||
sprintf(text_string, "ANALOG VALUE %lu",
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -258,8 +243,7 @@ bool Integer_Value_Object_Name(
|
||||
*
|
||||
* @return units property value
|
||||
*/
|
||||
uint16_t Integer_Value_Units(
|
||||
uint32_t instance)
|
||||
uint16_t Integer_Value_Units(uint32_t instance)
|
||||
{
|
||||
unsigned int index;
|
||||
uint16_t units = UNITS_NO_UNITS;
|
||||
@@ -280,9 +264,7 @@ uint16_t Integer_Value_Units(
|
||||
*
|
||||
* @return true if the units property value was set
|
||||
*/
|
||||
bool Integer_Value_Units_Set(
|
||||
uint32_t instance,
|
||||
uint16_t units)
|
||||
bool Integer_Value_Units_Set(uint32_t instance, uint16_t units)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
bool status = false;
|
||||
@@ -304,15 +286,14 @@ bool Integer_Value_Units_Set(
|
||||
*
|
||||
* @return out-of-service property value
|
||||
*/
|
||||
bool Integer_Value_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
bool Integer_Value_Out_Of_Service(uint32_t instance)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
bool value = false;
|
||||
|
||||
index = Integer_Value_Instance_To_Index(instance);
|
||||
if (index < MAX_INTEGER_VALUES) {
|
||||
value= Integer_Value[index].Out_Of_Service;
|
||||
value = Integer_Value[index].Out_Of_Service;
|
||||
}
|
||||
|
||||
return value;
|
||||
@@ -326,9 +307,7 @@ bool Integer_Value_Out_Of_Service(
|
||||
*
|
||||
* @return true if the out-of-service property value was set
|
||||
*/
|
||||
void Integer_Value_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool value)
|
||||
void Integer_Value_Out_Of_Service_Set(uint32_t instance, bool value)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
|
||||
@@ -348,10 +327,9 @@ void Integer_Value_Out_Of_Service_Set(
|
||||
* @return number of APDU bytes in the response, or
|
||||
* BACNET_STATUS_ERROR on error.
|
||||
*/
|
||||
int Integer_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Integer_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
@@ -367,9 +345,8 @@ int Integer_Value_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_INTEGER_VALUE,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_INTEGER_VALUE, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Integer_Value_Object_Name(rpdata->object_instance, &char_string);
|
||||
@@ -381,7 +358,8 @@ int Integer_Value_Read_Property(
|
||||
encode_application_enumerated(&apdu[0], OBJECT_INTEGER_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
integer_value = Integer_Value_Present_Value(rpdata->object_instance);
|
||||
integer_value =
|
||||
Integer_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_signed(&apdu[0], integer_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
@@ -428,17 +406,15 @@ int Integer_Value_Read_Property(
|
||||
*
|
||||
* @return false if an error is loaded, true if no errors
|
||||
*/
|
||||
bool Integer_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Integer_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -456,22 +432,22 @@ bool Integer_Value_Write_Property(
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
status =
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_SIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Integer_Value_Present_Value_Set(wp_data->object_instance,
|
||||
value.type.Signed_Int, wp_data->priority);
|
||||
value.type.Signed_Int,
|
||||
wp_data->priority);
|
||||
}
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Integer_Value_Out_Of_Service_Set(
|
||||
wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
Integer_Value_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -494,8 +470,7 @@ bool Integer_Value_Write_Property(
|
||||
/**
|
||||
* Initializes the Integer Value object data
|
||||
*/
|
||||
void Integer_Value_Init(
|
||||
void)
|
||||
void Integer_Value_Init(void)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
|
||||
+202
-260
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Load Control Objects - customize for your use */
|
||||
/* from 135-2004-Addendum e */
|
||||
@@ -29,13 +29,13 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h> /* for memcpy */
|
||||
#include <string.h> /* for memcpy */
|
||||
#include <time.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "datetime.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "lc.h"
|
||||
#include "ao.h"
|
||||
#include "wp.h"
|
||||
@@ -51,9 +51,9 @@ static BACNET_SHED_STATE Present_Value[MAX_LOAD_CONTROLS];
|
||||
|
||||
/* load control objects are required to support LEVEL */
|
||||
typedef enum BACnetShedLevelType {
|
||||
BACNET_SHED_TYPE_PERCENT, /* Unsigned */
|
||||
BACNET_SHED_TYPE_LEVEL, /* Unsigned */
|
||||
BACNET_SHED_TYPE_AMOUNT /* REAL */
|
||||
BACNET_SHED_TYPE_PERCENT, /* Unsigned */
|
||||
BACNET_SHED_TYPE_LEVEL, /* Unsigned */
|
||||
BACNET_SHED_TYPE_AMOUNT /* REAL */
|
||||
} BACNET_SHED_LEVEL_TYPE;
|
||||
|
||||
#define DEFAULT_VALUE_PERCENT 100
|
||||
@@ -126,17 +126,9 @@ static unsigned Shed_Levels[MAX_LOAD_CONTROLS][MAX_SHED_LEVELS];
|
||||
Load Control object can take on. It is the same for
|
||||
all the load control objects in this example device. */
|
||||
static char *Shed_Level_Descriptions[MAX_SHED_LEVELS] = {
|
||||
"dim lights 10%",
|
||||
"dim lights 20%",
|
||||
"dim lights 30%"
|
||||
};
|
||||
|
||||
static float Shed_Level_Values[MAX_SHED_LEVELS] = {
|
||||
90.0,
|
||||
80.0,
|
||||
70.0
|
||||
};
|
||||
"dim lights 10%", "dim lights 20%", "dim lights 30%"};
|
||||
|
||||
static float Shed_Level_Values[MAX_SHED_LEVELS] = {90.0, 80.0, 70.0};
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Load_Control_Properties_Required[] = {
|
||||
@@ -155,23 +147,15 @@ static const int Load_Control_Properties_Required[] = {
|
||||
PROP_ACTUAL_SHED_LEVEL,
|
||||
PROP_SHED_LEVELS,
|
||||
PROP_SHED_LEVEL_DESCRIPTIONS,
|
||||
-1
|
||||
};
|
||||
-1};
|
||||
|
||||
static const int Load_Control_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
PROP_FULL_DUTY_BASELINE,
|
||||
-1
|
||||
};
|
||||
PROP_DESCRIPTION, PROP_FULL_DUTY_BASELINE, -1};
|
||||
|
||||
static const int Load_Control_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Load_Control_Properties_Proprietary[] = {-1};
|
||||
|
||||
void Load_Control_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Load_Control_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Load_Control_Properties_Required;
|
||||
@@ -183,8 +167,7 @@ void Load_Control_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Load_Control_Init(
|
||||
void)
|
||||
void Load_Control_Init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
@@ -199,7 +182,7 @@ void Load_Control_Init(
|
||||
Shed_Duration[i] = 0;
|
||||
Duty_Window[i] = 0;
|
||||
Load_Control_Enable[i] = true;
|
||||
Full_Duty_Baseline[i] = 1.500; /* kilowatts */
|
||||
Full_Duty_Baseline[i] = 1.500; /* kilowatts */
|
||||
Expected_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
|
||||
Expected_Shed_Level[i].value.level = 0;
|
||||
Actual_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL;
|
||||
@@ -217,8 +200,7 @@ void Load_Control_Init(
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Load_Control_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Load_Control_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_LOAD_CONTROLS)
|
||||
return true;
|
||||
@@ -228,8 +210,7 @@ bool Load_Control_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Load_Control_Count(
|
||||
void)
|
||||
unsigned Load_Control_Count(void)
|
||||
{
|
||||
return MAX_LOAD_CONTROLS;
|
||||
}
|
||||
@@ -237,8 +218,7 @@ unsigned Load_Control_Count(
|
||||
/* 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 Load_Control_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Load_Control_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -246,8 +226,7 @@ uint32_t Load_Control_Index_To_Instance(
|
||||
/* 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 Load_Control_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Load_Control_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_LOAD_CONTROLS;
|
||||
|
||||
@@ -257,8 +236,7 @@ unsigned Load_Control_Instance_To_Index(
|
||||
return index;
|
||||
}
|
||||
|
||||
static BACNET_SHED_STATE Load_Control_Present_Value(
|
||||
uint32_t object_instance)
|
||||
static BACNET_SHED_STATE Load_Control_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
BACNET_SHED_STATE value = BACNET_SHED_INACTIVE;
|
||||
unsigned index = 0;
|
||||
@@ -272,11 +250,10 @@ static BACNET_SHED_STATE Load_Control_Present_Value(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Load_Control_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Load_Control_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_LOAD_CONTROLS) {
|
||||
@@ -287,37 +264,35 @@ bool Load_Control_Object_Name(
|
||||
return status;
|
||||
}
|
||||
|
||||
static void Update_Current_Time(
|
||||
BACNET_DATE_TIME * bdatetime)
|
||||
static void Update_Current_Time(BACNET_DATE_TIME *bdatetime)
|
||||
{
|
||||
time_t timer;
|
||||
struct tm *tblock;
|
||||
|
||||
/*
|
||||
struct tm {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
};
|
||||
*/
|
||||
/*
|
||||
struct tm {
|
||||
int tm_sec;
|
||||
int tm_min;
|
||||
int tm_hour;
|
||||
int tm_mday;
|
||||
int tm_mon;
|
||||
int tm_year;
|
||||
int tm_wday;
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
};
|
||||
*/
|
||||
|
||||
timer = time(NULL);
|
||||
tblock = localtime(&timer);
|
||||
datetime_set_values(bdatetime, (uint16_t) tblock->tm_year,
|
||||
(uint8_t) tblock->tm_mon, (uint8_t) tblock->tm_mday,
|
||||
(uint8_t) tblock->tm_hour, (uint8_t) tblock->tm_min,
|
||||
(uint8_t) tblock->tm_sec, 0);
|
||||
datetime_set_values(bdatetime, (uint16_t)tblock->tm_year,
|
||||
(uint8_t)tblock->tm_mon, (uint8_t)tblock->tm_mday,
|
||||
(uint8_t)tblock->tm_hour, (uint8_t)tblock->tm_min,
|
||||
(uint8_t)tblock->tm_sec, 0);
|
||||
}
|
||||
|
||||
/* convert the shed level request into an Analog Output Present_Value */
|
||||
static float Requested_Shed_Level_Value(
|
||||
int object_index)
|
||||
static float Requested_Shed_Level_Value(int object_index)
|
||||
{
|
||||
unsigned shed_level_index = 0;
|
||||
unsigned i = 0;
|
||||
@@ -326,13 +301,12 @@ static float Requested_Shed_Level_Value(
|
||||
switch (Requested_Shed_Level[object_index].type) {
|
||||
case BACNET_SHED_TYPE_PERCENT:
|
||||
requested_level =
|
||||
(float) Requested_Shed_Level[object_index].value.percent;
|
||||
(float)Requested_Shed_Level[object_index].value.percent;
|
||||
break;
|
||||
case BACNET_SHED_TYPE_AMOUNT:
|
||||
/* Assumptions: wattage is linear with analog output level */
|
||||
requested_level =
|
||||
Full_Duty_Baseline[object_index] -
|
||||
Requested_Shed_Level[object_index].value.amount;
|
||||
requested_level = Full_Duty_Baseline[object_index] -
|
||||
Requested_Shed_Level[object_index].value.amount;
|
||||
requested_level /= Full_Duty_Baseline[object_index];
|
||||
requested_level *= 100.0;
|
||||
break;
|
||||
@@ -350,9 +324,7 @@ static float Requested_Shed_Level_Value(
|
||||
return requested_level;
|
||||
}
|
||||
|
||||
static void Shed_Level_Copy(
|
||||
BACNET_SHED_LEVEL * dest,
|
||||
BACNET_SHED_LEVEL * src)
|
||||
static void Shed_Level_Copy(BACNET_SHED_LEVEL *dest, BACNET_SHED_LEVEL *src)
|
||||
{
|
||||
if (dest && src) {
|
||||
dest->type = src->type;
|
||||
@@ -371,9 +343,8 @@ static void Shed_Level_Copy(
|
||||
}
|
||||
}
|
||||
|
||||
static void Shed_Level_Default_Set(
|
||||
BACNET_SHED_LEVEL * dest,
|
||||
BACNET_SHED_LEVEL_TYPE type)
|
||||
static void Shed_Level_Default_Set(BACNET_SHED_LEVEL *dest,
|
||||
BACNET_SHED_LEVEL_TYPE type)
|
||||
{
|
||||
if (dest) {
|
||||
dest->type = type;
|
||||
@@ -392,8 +363,7 @@ static void Shed_Level_Default_Set(
|
||||
}
|
||||
}
|
||||
|
||||
static bool Able_To_Meet_Shed_Request(
|
||||
int object_index)
|
||||
static bool Able_To_Meet_Shed_Request(int object_index)
|
||||
{
|
||||
float level = 0.0;
|
||||
float requested_level = 0.0;
|
||||
@@ -428,30 +398,25 @@ static LOAD_CONTROL_STATE Load_Control_State[MAX_LOAD_CONTROLS];
|
||||
static LOAD_CONTROL_STATE Load_Control_State_Previously[MAX_LOAD_CONTROLS];
|
||||
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
static void Print_Load_Control_State(
|
||||
int object_index)
|
||||
static void Print_Load_Control_State(int object_index)
|
||||
{
|
||||
char *Load_Control_State_Text[MAX_LOAD_CONTROLS] = {
|
||||
"SHED_INACTIVE",
|
||||
"SHED_REQUEST_PENDING",
|
||||
"SHED_NON_COMPLIANT",
|
||||
"SHED_COMPLIANT"
|
||||
};
|
||||
"SHED_INACTIVE", "SHED_REQUEST_PENDING", "SHED_NON_COMPLIANT",
|
||||
"SHED_COMPLIANT"};
|
||||
|
||||
if (object_index < MAX_LOAD_CONTROLS) {
|
||||
if (Load_Control_State[object_index] < MAX_LOAD_CONTROL_STATE) {
|
||||
printf("Load Control[%d]=%s\n", object_index,
|
||||
Load_Control_State_Text[Load_Control_State[object_index]]);
|
||||
Load_Control_State_Text[Load_Control_State[object_index]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Load_Control_State_Machine(
|
||||
int object_index)
|
||||
void Load_Control_State_Machine(int object_index)
|
||||
{
|
||||
unsigned i = 0; /* loop counter */
|
||||
int diff = 0; /* used for datetime comparison */
|
||||
unsigned i = 0; /* loop counter */
|
||||
int diff = 0; /* used for datetime comparison */
|
||||
|
||||
/* is the state machine enabled? */
|
||||
if (!Load_Control_Enable[object_index]) {
|
||||
@@ -485,7 +450,7 @@ void Load_Control_State_Machine(
|
||||
if (Load_Control_State[object_index] == SHED_INACTIVE) {
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf("Load Control[%d]:Requested Shed Level=Default\n",
|
||||
object_index);
|
||||
object_index);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -498,7 +463,7 @@ void Load_Control_State_Machine(
|
||||
Load_Control_State[object_index] = SHED_INACTIVE;
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf("Load Control[%d]:Start Time=Wildcard\n",
|
||||
object_index);
|
||||
object_index);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -506,14 +471,16 @@ void Load_Control_State_Machine(
|
||||
/* cancel because current time is after start time + duration? */
|
||||
datetime_copy(&End_Time[object_index], &Start_Time[object_index]);
|
||||
datetime_add_minutes(&End_Time[object_index],
|
||||
Shed_Duration[object_index]);
|
||||
Shed_Duration[object_index]);
|
||||
diff = datetime_compare(&End_Time[object_index], &Current_Time);
|
||||
if (diff < 0) {
|
||||
/* CancelShed */
|
||||
/* FIXME: stop shedding! i.e. relinquish */
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf("Load Control[%d]:Current Time"
|
||||
" is after Start Time + Duration\n", object_index);
|
||||
printf(
|
||||
"Load Control[%d]:Current Time"
|
||||
" is after Start Time + Duration\n",
|
||||
object_index);
|
||||
#endif
|
||||
Load_Control_State[object_index] = SHED_INACTIVE;
|
||||
break;
|
||||
@@ -523,29 +490,34 @@ void Load_Control_State_Machine(
|
||||
/* current time prior to start time */
|
||||
/* ReconfigurePending */
|
||||
Shed_Level_Copy(&Expected_Shed_Level[object_index],
|
||||
&Requested_Shed_Level[object_index]);
|
||||
&Requested_Shed_Level[object_index]);
|
||||
Shed_Level_Default_Set(&Actual_Shed_Level[object_index],
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Requested_Shed_Level[object_index].type);
|
||||
} else if (diff > 0) {
|
||||
/* current time after to start time */
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf("Load Control[%d]:Current Time"
|
||||
" is after Start Time\n", object_index);
|
||||
printf(
|
||||
"Load Control[%d]:Current Time"
|
||||
" is after Start Time\n",
|
||||
object_index);
|
||||
#endif
|
||||
/* AbleToMeetShed */
|
||||
if (Able_To_Meet_Shed_Request(object_index)) {
|
||||
Shed_Level_Copy(&Expected_Shed_Level[object_index],
|
||||
&Requested_Shed_Level[object_index]);
|
||||
Analog_Output_Present_Value_Set(object_index,
|
||||
Requested_Shed_Level_Value(object_index), 4);
|
||||
&Requested_Shed_Level[object_index]);
|
||||
Analog_Output_Present_Value_Set(
|
||||
object_index, Requested_Shed_Level_Value(object_index),
|
||||
4);
|
||||
Shed_Level_Copy(&Actual_Shed_Level[object_index],
|
||||
&Requested_Shed_Level[object_index]);
|
||||
&Requested_Shed_Level[object_index]);
|
||||
Load_Control_State[object_index] = SHED_COMPLIANT;
|
||||
} else {
|
||||
/* CannotMeetShed */
|
||||
Shed_Level_Default_Set(&Expected_Shed_Level[object_index],
|
||||
Shed_Level_Default_Set(
|
||||
&Expected_Shed_Level[object_index],
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Shed_Level_Default_Set(&Actual_Shed_Level[object_index],
|
||||
Shed_Level_Default_Set(
|
||||
&Actual_Shed_Level[object_index],
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Load_Control_State[object_index] = SHED_NON_COMPLIANT;
|
||||
}
|
||||
@@ -554,13 +526,14 @@ void Load_Control_State_Machine(
|
||||
case SHED_NON_COMPLIANT:
|
||||
datetime_copy(&End_Time[object_index], &Start_Time[object_index]);
|
||||
datetime_add_minutes(&End_Time[object_index],
|
||||
Shed_Duration[object_index]);
|
||||
Shed_Duration[object_index]);
|
||||
diff = datetime_compare(&End_Time[object_index], &Current_Time);
|
||||
if (diff < 0) {
|
||||
/* FinishedUnsuccessfulShed */
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf
|
||||
("Load Control[%d]:Current Time is after Start Time + Duration\n",
|
||||
printf(
|
||||
"Load Control[%d]:Current Time is after Start Time + "
|
||||
"Duration\n",
|
||||
object_index);
|
||||
#endif
|
||||
Load_Control_State[object_index] = SHED_INACTIVE;
|
||||
@@ -571,7 +544,7 @@ void Load_Control_State_Machine(
|
||||
/* UnsuccessfulShedReconfigured */
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf("Load Control[%d]:Control Property written\n",
|
||||
object_index);
|
||||
object_index);
|
||||
#endif
|
||||
/* The Written flags will cleared in the next state */
|
||||
Load_Control_State[object_index] = SHED_REQUEST_PENDING;
|
||||
@@ -581,27 +554,28 @@ void Load_Control_State_Machine(
|
||||
/* CanNowComplyWithShed */
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf("Load Control[%d]:Able to meet Shed Request\n",
|
||||
object_index);
|
||||
object_index);
|
||||
#endif
|
||||
Shed_Level_Copy(&Expected_Shed_Level[object_index],
|
||||
&Requested_Shed_Level[object_index]);
|
||||
Analog_Output_Present_Value_Set(object_index,
|
||||
Requested_Shed_Level_Value(object_index), 4);
|
||||
&Requested_Shed_Level[object_index]);
|
||||
Analog_Output_Present_Value_Set(
|
||||
object_index, Requested_Shed_Level_Value(object_index), 4);
|
||||
Shed_Level_Copy(&Actual_Shed_Level[object_index],
|
||||
&Requested_Shed_Level[object_index]);
|
||||
&Requested_Shed_Level[object_index]);
|
||||
Load_Control_State[object_index] = SHED_COMPLIANT;
|
||||
}
|
||||
break;
|
||||
case SHED_COMPLIANT:
|
||||
datetime_copy(&End_Time[object_index], &Start_Time[object_index]);
|
||||
datetime_add_minutes(&End_Time[object_index],
|
||||
Shed_Duration[object_index]);
|
||||
Shed_Duration[object_index]);
|
||||
diff = datetime_compare(&End_Time[object_index], &Current_Time);
|
||||
if (diff < 0) {
|
||||
/* FinishedSuccessfulShed */
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf
|
||||
("Load Control[%d]:Current Time is after Start Time + Duration\n",
|
||||
printf(
|
||||
"Load Control[%d]:Current Time is after Start Time + "
|
||||
"Duration\n",
|
||||
object_index);
|
||||
#endif
|
||||
datetime_wildcard_set(&Start_Time[i]);
|
||||
@@ -614,7 +588,7 @@ void Load_Control_State_Machine(
|
||||
/* UnsuccessfulShedReconfigured */
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf("Load Control[%d]:Control Property written\n",
|
||||
object_index);
|
||||
object_index);
|
||||
#endif
|
||||
/* The Written flags will cleared in the next state */
|
||||
Load_Control_State[object_index] = SHED_REQUEST_PENDING;
|
||||
@@ -624,12 +598,12 @@ void Load_Control_State_Machine(
|
||||
/* CanNoLongerComplyWithShed */
|
||||
#if PRINT_ENABLED_DEBUG
|
||||
printf("Load Control[%d]:Not able to meet Shed Request\n",
|
||||
object_index);
|
||||
object_index);
|
||||
#endif
|
||||
Shed_Level_Default_Set(&Expected_Shed_Level[object_index],
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Shed_Level_Default_Set(&Actual_Shed_Level[object_index],
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Load_Control_State[object_index] = SHED_NON_COMPLIANT;
|
||||
}
|
||||
break;
|
||||
@@ -641,9 +615,9 @@ void Load_Control_State_Machine(
|
||||
#endif
|
||||
/* The Written flag will cleared in the next state */
|
||||
Shed_Level_Copy(&Expected_Shed_Level[object_index],
|
||||
&Requested_Shed_Level[object_index]);
|
||||
&Requested_Shed_Level[object_index]);
|
||||
Shed_Level_Default_Set(&Actual_Shed_Level[object_index],
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Requested_Shed_Level[object_index].type);
|
||||
Load_Control_State[object_index] = SHED_REQUEST_PENDING;
|
||||
}
|
||||
break;
|
||||
@@ -653,8 +627,7 @@ void Load_Control_State_Machine(
|
||||
}
|
||||
|
||||
/* call every second or so */
|
||||
void Load_Control_State_Machine_Handler(
|
||||
void)
|
||||
void Load_Control_State_Machine_Handler(void)
|
||||
{
|
||||
unsigned i = 0;
|
||||
static bool initialized = false;
|
||||
@@ -675,17 +648,14 @@ void Load_Control_State_Machine_Handler(
|
||||
#endif
|
||||
Load_Control_State_Previously[i] = Load_Control_State[i];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Load_Control_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Load_Control_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
int enumeration = 0;
|
||||
@@ -702,9 +672,8 @@ int Load_Control_Read_Property(
|
||||
object_index = Load_Control_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_LOAD_CONTROL,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_LOAD_CONTROL, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
@@ -744,68 +713,63 @@ int Load_Control_Read_Property(
|
||||
case PROP_REQUESTED_SHED_LEVEL:
|
||||
switch (Requested_Shed_Level[object_index].type) {
|
||||
case BACNET_SHED_TYPE_PERCENT:
|
||||
apdu_len =
|
||||
encode_context_unsigned(&apdu[0], 0,
|
||||
apdu_len = encode_context_unsigned(
|
||||
&apdu[0], 0,
|
||||
Requested_Shed_Level[object_index].value.percent);
|
||||
break;
|
||||
case BACNET_SHED_TYPE_AMOUNT:
|
||||
apdu_len =
|
||||
encode_context_real(&apdu[0], 2,
|
||||
apdu_len = encode_context_real(
|
||||
&apdu[0], 2,
|
||||
Requested_Shed_Level[object_index].value.amount);
|
||||
break;
|
||||
case BACNET_SHED_TYPE_LEVEL:
|
||||
default:
|
||||
apdu_len =
|
||||
encode_context_unsigned(&apdu[0], 1,
|
||||
apdu_len = encode_context_unsigned(
|
||||
&apdu[0], 1,
|
||||
Requested_Shed_Level[object_index].value.level);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PROP_START_TIME:
|
||||
len =
|
||||
encode_application_date(&apdu[0],
|
||||
&Start_Time[object_index].date);
|
||||
len = encode_application_date(&apdu[0],
|
||||
&Start_Time[object_index].date);
|
||||
apdu_len = len;
|
||||
len =
|
||||
encode_application_time(&apdu[apdu_len],
|
||||
&Start_Time[object_index].time);
|
||||
len = encode_application_time(&apdu[apdu_len],
|
||||
&Start_Time[object_index].time);
|
||||
apdu_len += len;
|
||||
break;
|
||||
case PROP_SHED_DURATION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Shed_Duration[object_index]);
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
Shed_Duration[object_index]);
|
||||
break;
|
||||
case PROP_DUTY_WINDOW:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Duty_Window[object_index]);
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
Duty_Window[object_index]);
|
||||
break;
|
||||
case PROP_ENABLE:
|
||||
state = Load_Control_Enable[object_index];
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_FULL_DUTY_BASELINE: /* optional */
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0],
|
||||
Full_Duty_Baseline[object_index]);
|
||||
case PROP_FULL_DUTY_BASELINE: /* optional */
|
||||
apdu_len = encode_application_real(
|
||||
&apdu[0], Full_Duty_Baseline[object_index]);
|
||||
break;
|
||||
case PROP_EXPECTED_SHED_LEVEL:
|
||||
switch (Expected_Shed_Level[object_index].type) {
|
||||
case BACNET_SHED_TYPE_PERCENT:
|
||||
apdu_len =
|
||||
encode_context_unsigned(&apdu[0], 0,
|
||||
apdu_len = encode_context_unsigned(
|
||||
&apdu[0], 0,
|
||||
Expected_Shed_Level[object_index].value.percent);
|
||||
break;
|
||||
case BACNET_SHED_TYPE_AMOUNT:
|
||||
apdu_len =
|
||||
encode_context_real(&apdu[0], 2,
|
||||
apdu_len = encode_context_real(
|
||||
&apdu[0], 2,
|
||||
Expected_Shed_Level[object_index].value.amount);
|
||||
break;
|
||||
case BACNET_SHED_TYPE_LEVEL:
|
||||
default:
|
||||
apdu_len =
|
||||
encode_context_unsigned(&apdu[0], 1,
|
||||
apdu_len = encode_context_unsigned(
|
||||
&apdu[0], 1,
|
||||
Expected_Shed_Level[object_index].value.level);
|
||||
break;
|
||||
}
|
||||
@@ -813,19 +777,19 @@ int Load_Control_Read_Property(
|
||||
case PROP_ACTUAL_SHED_LEVEL:
|
||||
switch (Actual_Shed_Level[object_index].type) {
|
||||
case BACNET_SHED_TYPE_PERCENT:
|
||||
apdu_len =
|
||||
encode_context_unsigned(&apdu[0], 0,
|
||||
apdu_len = encode_context_unsigned(
|
||||
&apdu[0], 0,
|
||||
Actual_Shed_Level[object_index].value.percent);
|
||||
break;
|
||||
case BACNET_SHED_TYPE_AMOUNT:
|
||||
apdu_len =
|
||||
encode_context_real(&apdu[0], 2,
|
||||
apdu_len = encode_context_real(
|
||||
&apdu[0], 2,
|
||||
Actual_Shed_Level[object_index].value.amount);
|
||||
break;
|
||||
case BACNET_SHED_TYPE_LEVEL:
|
||||
default:
|
||||
apdu_len =
|
||||
encode_context_unsigned(&apdu[0], 1,
|
||||
apdu_len = encode_context_unsigned(
|
||||
&apdu[0], 1,
|
||||
Actual_Shed_Level[object_index].value.level);
|
||||
break;
|
||||
}
|
||||
@@ -841,9 +805,8 @@ int Load_Control_Read_Property(
|
||||
apdu_len = 0;
|
||||
for (i = 0; i < MAX_SHED_LEVELS; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
len =
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
Shed_Levels[object_index][i]);
|
||||
len = encode_application_unsigned(
|
||||
&apdu[apdu_len], Shed_Levels[object_index][i]);
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
@@ -856,8 +819,8 @@ int Load_Control_Read_Property(
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <= MAX_SHED_LEVELS) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0],
|
||||
Shed_Levels[object_index][rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -878,10 +841,9 @@ int Load_Control_Read_Property(
|
||||
for (i = 0; i < MAX_SHED_LEVELS; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
characterstring_init_ansi(&char_string,
|
||||
Shed_Level_Descriptions[i]);
|
||||
len =
|
||||
encode_application_character_string(&apdu[apdu_len],
|
||||
&char_string);
|
||||
Shed_Level_Descriptions[i]);
|
||||
len = encode_application_character_string(&apdu[apdu_len],
|
||||
&char_string);
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
@@ -894,11 +856,11 @@ int Load_Control_Read_Property(
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <= MAX_SHED_LEVELS) {
|
||||
characterstring_init_ansi(&char_string,
|
||||
characterstring_init_ansi(
|
||||
&char_string,
|
||||
Shed_Level_Descriptions[rpdata->array_index - 1]);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0],
|
||||
&char_string);
|
||||
apdu_len = encode_application_character_string(
|
||||
&apdu[0], &char_string);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
@@ -926,19 +888,18 @@ int Load_Control_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Load_Control_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
BACNET_DATE TempDate; /* build here in case of error in time half of datetime */
|
||||
BACNET_DATE
|
||||
TempDate; /* build here in case of error in time half of datetime */
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
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 */
|
||||
@@ -956,10 +917,9 @@ bool Load_Control_Write_Property(
|
||||
object_index = Load_Control_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_REQUESTED_SHED_LEVEL:
|
||||
len =
|
||||
bacapp_decode_context_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value,
|
||||
PROP_REQUESTED_SHED_LEVEL);
|
||||
len = bacapp_decode_context_data(wp_data->application_data,
|
||||
wp_data->application_data_len,
|
||||
&value, PROP_REQUESTED_SHED_LEVEL);
|
||||
if (value.context_tag == 0) {
|
||||
/* percent - Unsigned */
|
||||
Requested_Shed_Level[object_index].type =
|
||||
@@ -994,20 +954,20 @@ bool Load_Control_Write_Property(
|
||||
case PROP_START_TIME:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_DATE,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (!status) {
|
||||
/* don't continue if we don't have a valid date */
|
||||
break;
|
||||
}
|
||||
/* Hold the date until we are sure the time is also there */
|
||||
TempDate = value.type.Date;
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data + len,
|
||||
len = bacapp_decode_application_data(
|
||||
wp_data->application_data + len,
|
||||
wp_data->application_data_len - len, &value);
|
||||
if (len) {
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_TIME,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_TIME,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
/* Write time and date and set written flag */
|
||||
Start_Time[object_index].date = TempDate;
|
||||
@@ -1024,7 +984,7 @@ bool Load_Control_Write_Property(
|
||||
case PROP_SHED_DURATION:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Shed_Duration[object_index] = value.type.Unsigned_Int;
|
||||
Load_Control_Request_Written[object_index] = true;
|
||||
@@ -1034,7 +994,7 @@ bool Load_Control_Write_Property(
|
||||
case PROP_DUTY_WINDOW:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Duty_Window[object_index] = value.type.Unsigned_Int;
|
||||
Load_Control_Request_Written[object_index] = true;
|
||||
@@ -1044,7 +1004,7 @@ bool Load_Control_Write_Property(
|
||||
case PROP_SHED_LEVELS:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
/* re-write the size of the array? */
|
||||
if (wp_data->array_index == 0) {
|
||||
@@ -1069,7 +1029,7 @@ bool Load_Control_Write_Property(
|
||||
case PROP_ENABLE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Load_Control_Enable[object_index] = value.type.Boolean;
|
||||
}
|
||||
@@ -1117,10 +1077,9 @@ static void Load_Control_WriteProperty_Request_Shed_Percent(
|
||||
}
|
||||
#endif
|
||||
|
||||
static void Load_Control_WriteProperty_Request_Shed_Level(
|
||||
Test * pTest,
|
||||
int instance,
|
||||
unsigned level)
|
||||
static void Load_Control_WriteProperty_Request_Shed_Level(Test *pTest,
|
||||
int instance,
|
||||
unsigned level)
|
||||
{
|
||||
bool status = false;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
@@ -1169,10 +1128,8 @@ static void Load_Control_WriteProperty_Request_Shed_Amount(
|
||||
}
|
||||
#endif
|
||||
|
||||
static void Load_Control_WriteProperty_Enable(
|
||||
Test * pTest,
|
||||
int instance,
|
||||
bool enable)
|
||||
static void Load_Control_WriteProperty_Enable(Test *pTest, int instance,
|
||||
bool enable)
|
||||
{
|
||||
bool status = false;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
@@ -1195,10 +1152,8 @@ static void Load_Control_WriteProperty_Enable(
|
||||
ct_test(pTest, status == true);
|
||||
}
|
||||
|
||||
static void Load_Control_WriteProperty_Shed_Duration(
|
||||
Test * pTest,
|
||||
int instance,
|
||||
unsigned duration)
|
||||
static void Load_Control_WriteProperty_Shed_Duration(Test *pTest, int instance,
|
||||
unsigned duration)
|
||||
{
|
||||
bool status = false;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
@@ -1220,10 +1175,8 @@ static void Load_Control_WriteProperty_Shed_Duration(
|
||||
ct_test(pTest, status == true);
|
||||
}
|
||||
|
||||
static void Load_Control_WriteProperty_Duty_Window(
|
||||
Test * pTest,
|
||||
int instance,
|
||||
unsigned duration)
|
||||
static void Load_Control_WriteProperty_Duty_Window(Test *pTest, int instance,
|
||||
unsigned duration)
|
||||
{
|
||||
bool status = false;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
@@ -1245,9 +1198,8 @@ static void Load_Control_WriteProperty_Duty_Window(
|
||||
ct_test(pTest, status == true);
|
||||
}
|
||||
|
||||
static void Load_Control_WriteProperty_Start_Time_Wildcards(
|
||||
Test * pTest,
|
||||
int instance)
|
||||
static void Load_Control_WriteProperty_Start_Time_Wildcards(Test *pTest,
|
||||
int instance)
|
||||
{
|
||||
int len = 0;
|
||||
bool status = false;
|
||||
@@ -1278,15 +1230,8 @@ static void Load_Control_WriteProperty_Start_Time_Wildcards(
|
||||
}
|
||||
|
||||
static void Load_Control_WriteProperty_Start_Time(
|
||||
Test * pTest,
|
||||
int instance,
|
||||
uint16_t year,
|
||||
uint8_t month,
|
||||
uint8_t day,
|
||||
uint8_t hour,
|
||||
uint8_t minute,
|
||||
uint8_t seconds,
|
||||
uint8_t hundredths)
|
||||
Test *pTest, int instance, uint16_t year, uint8_t month, uint8_t day,
|
||||
uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths)
|
||||
{
|
||||
int len = 0;
|
||||
bool status = false;
|
||||
@@ -1316,8 +1261,7 @@ static void Load_Control_WriteProperty_Start_Time(
|
||||
ct_test(pTest, status == true);
|
||||
}
|
||||
|
||||
void testLoadControlStateMachine(
|
||||
Test * pTest)
|
||||
void testLoadControlStateMachine(Test *pTest)
|
||||
{
|
||||
unsigned i = 0, j = 0;
|
||||
uint8_t level = 0;
|
||||
@@ -1456,10 +1400,9 @@ void testLoadControlStateMachine(
|
||||
ct_test(pTest, level == 100);
|
||||
}
|
||||
|
||||
void testLoadControl(
|
||||
Test * pTest)
|
||||
void testLoadControl(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -1487,8 +1430,7 @@ void testLoadControl(
|
||||
}
|
||||
|
||||
#ifdef TEST_LOAD_CONTROL
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -1502,7 +1444,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+168
-242
@@ -1,31 +1,31 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Steve Karg
|
||||
* @date 2013
|
||||
* @brief Lighting Output object
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
* @file
|
||||
* @author Steve Karg
|
||||
* @date 2013
|
||||
* @brief Lighting Output object
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "lighting.h"
|
||||
@@ -53,9 +53,9 @@ struct lighting_output_object {
|
||||
float Physical_Value;
|
||||
BACNET_LIGHTING_COMMAND Lighting_Command;
|
||||
BACNET_LIGHTING_IN_PROGRESS In_Progress;
|
||||
bool Out_Of_Service:1;
|
||||
bool Blink_Warn_Enable:1;
|
||||
bool Egress_Active:1;
|
||||
bool Out_Of_Service : 1;
|
||||
bool Blink_Warn_Enable : 1;
|
||||
bool Egress_Active : 1;
|
||||
uint32_t Egress_Time;
|
||||
uint32_t Default_Fade_Time;
|
||||
float Default_Ramp_Rate;
|
||||
@@ -94,15 +94,10 @@ static const int Lighting_Output_Properties_Required[] = {
|
||||
PROP_PRIORITY_ARRAY,
|
||||
PROP_RELINQUISH_DEFAULT,
|
||||
PROP_LIGHTING_COMMAND_DEFAULT_PRIORITY,
|
||||
-1
|
||||
};
|
||||
static const int Lighting_Output_Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
-1};
|
||||
static const int Lighting_Output_Properties_Optional[] = {-1};
|
||||
|
||||
static const int Lighting_Output_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Lighting_Output_Properties_Proprietary[] = {-1};
|
||||
|
||||
/**
|
||||
* Returns the list of required, optional, and proprietary properties.
|
||||
@@ -115,10 +110,9 @@ static const int Lighting_Output_Properties_Proprietary[] = {
|
||||
* @param pProprietary - pointer to list of int terminated by -1, of
|
||||
* BACnet proprietary properties for this object.
|
||||
*/
|
||||
void Lighting_Output_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Lighting_Output_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Lighting_Output_Properties_Required;
|
||||
@@ -137,8 +131,7 @@ void Lighting_Output_Property_Lists(
|
||||
*
|
||||
* @return true if the instance is valid, and false if not
|
||||
*/
|
||||
bool Lighting_Output_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Lighting_Output_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
@@ -155,8 +148,7 @@ bool Lighting_Output_Valid_Instance(
|
||||
*
|
||||
* @return Number of Lighting Output objects
|
||||
*/
|
||||
unsigned Lighting_Output_Count(
|
||||
void)
|
||||
unsigned Lighting_Output_Count(void)
|
||||
{
|
||||
return MAX_LIGHTING_OUTPUTS;
|
||||
}
|
||||
@@ -169,8 +161,7 @@ unsigned Lighting_Output_Count(
|
||||
*
|
||||
* @return object instance-number for the given index
|
||||
*/
|
||||
uint32_t Lighting_Output_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Lighting_Output_Index_To_Instance(unsigned index)
|
||||
{
|
||||
uint32_t instance = 1;
|
||||
|
||||
@@ -188,8 +179,7 @@ uint32_t Lighting_Output_Index_To_Instance(
|
||||
* @return index for the given instance-number, or MAX_LIGHTING_OUTPUTS
|
||||
* if not valid.
|
||||
*/
|
||||
unsigned Lighting_Output_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Lighting_Output_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_LIGHTING_OUTPUTS;
|
||||
|
||||
@@ -210,8 +200,7 @@ unsigned Lighting_Output_Instance_To_Index(
|
||||
*
|
||||
* @return present-value of the object
|
||||
*/
|
||||
float Lighting_Output_Present_Value(
|
||||
uint32_t object_instance)
|
||||
float Lighting_Output_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
unsigned index = 0;
|
||||
@@ -240,9 +229,8 @@ float Lighting_Output_Present_Value(
|
||||
*
|
||||
* @return priority-value of the object
|
||||
*/
|
||||
static float Lighting_Output_Priority_Value(
|
||||
uint32_t object_instance,
|
||||
unsigned priority)
|
||||
static float Lighting_Output_Priority_Value(uint32_t object_instance,
|
||||
unsigned priority)
|
||||
{
|
||||
float value = 0.0;
|
||||
unsigned index = 0;
|
||||
@@ -267,9 +255,8 @@ static float Lighting_Output_Priority_Value(
|
||||
*
|
||||
* @return true if the priority slot is active
|
||||
*/
|
||||
static bool Lighting_Output_Priority_Active(
|
||||
uint32_t object_instance,
|
||||
unsigned priority)
|
||||
static bool Lighting_Output_Priority_Active(uint32_t object_instance,
|
||||
unsigned priority)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
@@ -278,7 +265,8 @@ static bool Lighting_Output_Priority_Active(
|
||||
if (index < MAX_LIGHTING_OUTPUTS) {
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
if (BIT_CHECK(Lighting_Output[index].Priority_Active_Bits, priority)) {
|
||||
if (BIT_CHECK(Lighting_Output[index].Priority_Active_Bits,
|
||||
priority)) {
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
@@ -294,12 +282,11 @@ static bool Lighting_Output_Priority_Active(
|
||||
*
|
||||
* @return active priority 1..16, or 0 if no priority is active
|
||||
*/
|
||||
unsigned Lighting_Output_Present_Value_Priority(
|
||||
uint32_t object_instance)
|
||||
unsigned Lighting_Output_Present_Value_Priority(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0; /* instance to index conversion */
|
||||
unsigned p = 0; /* loop counter */
|
||||
unsigned priority = 0; /* return value */
|
||||
unsigned index = 0; /* instance to index conversion */
|
||||
unsigned p = 0; /* loop counter */
|
||||
unsigned priority = 0; /* return value */
|
||||
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_LIGHTING_OUTPUTS) {
|
||||
@@ -324,10 +311,8 @@ unsigned Lighting_Output_Present_Value_Priority(
|
||||
*
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool Lighting_Output_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value,
|
||||
unsigned priority)
|
||||
bool Lighting_Output_Present_Value_Set(uint32_t object_instance, float value,
|
||||
unsigned priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -335,7 +320,7 @@ bool Lighting_Output_Present_Value_Set(
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_LIGHTING_OUTPUTS) {
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ )) {
|
||||
(priority != 6 /* reserved */)) {
|
||||
priority--;
|
||||
BIT_SET(Lighting_Output[index].Priority_Active_Bits, priority);
|
||||
Lighting_Output[index].Priority_Array[priority] = value;
|
||||
@@ -355,9 +340,8 @@ bool Lighting_Output_Present_Value_Set(
|
||||
*
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool Lighting_Output_Present_Value_Relinquish(
|
||||
uint32_t object_instance,
|
||||
unsigned priority)
|
||||
bool Lighting_Output_Present_Value_Relinquish(uint32_t object_instance,
|
||||
unsigned priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -365,7 +349,7 @@ bool Lighting_Output_Present_Value_Relinquish(
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_LIGHTING_OUTPUTS) {
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ )) {
|
||||
(priority != 6 /* reserved */)) {
|
||||
priority--;
|
||||
BIT_CLEAR(Lighting_Output[index].Priority_Active_Bits, priority);
|
||||
Lighting_Output[index].Priority_Array[priority] = 0.0;
|
||||
@@ -386,9 +370,8 @@ bool Lighting_Output_Present_Value_Relinquish(
|
||||
*
|
||||
* @return true if object-name was retrieved
|
||||
*/
|
||||
bool Lighting_Output_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Lighting_Output_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
char text_string[32] = "";
|
||||
bool status = false;
|
||||
@@ -397,7 +380,7 @@ bool Lighting_Output_Object_Name(
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_LIGHTING_OUTPUTS) {
|
||||
sprintf(text_string, "LIGHTING OUTPUT %lu",
|
||||
(unsigned long) object_instance);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -412,9 +395,8 @@ bool Lighting_Output_Object_Name(
|
||||
*
|
||||
* @return true if lighting command was set
|
||||
*/
|
||||
bool Lighting_Output_Lighting_Command_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_LIGHTING_COMMAND *value)
|
||||
bool Lighting_Output_Lighting_Command_Set(uint32_t object_instance,
|
||||
BACNET_LIGHTING_COMMAND *value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
@@ -422,9 +404,8 @@ bool Lighting_Output_Lighting_Command_Set(
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_LIGHTING_OUTPUTS) {
|
||||
// FIXME: check lighting command member values
|
||||
status = lighting_command_copy(
|
||||
&Lighting_Output[index].Lighting_Command,
|
||||
value);
|
||||
status = lighting_command_copy(&Lighting_Output[index].Lighting_Command,
|
||||
value);
|
||||
// FIXME: set all the other values, and get the light levels moving
|
||||
}
|
||||
|
||||
@@ -439,17 +420,16 @@ bool Lighting_Output_Lighting_Command_Set(
|
||||
*
|
||||
* @return true if lighting command was retrieved
|
||||
*/
|
||||
bool Lighting_Output_Lighting_Command(
|
||||
uint32_t object_instance,
|
||||
BACNET_LIGHTING_COMMAND *value)
|
||||
bool Lighting_Output_Lighting_Command(uint32_t object_instance,
|
||||
BACNET_LIGHTING_COMMAND *value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_LIGHTING_OUTPUTS) {
|
||||
status = lighting_command_copy(value,
|
||||
&Lighting_Output[index].Lighting_Command);
|
||||
status = lighting_command_copy(
|
||||
value, &Lighting_Output[index].Lighting_Command);
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -485,9 +465,8 @@ BACNET_LIGHTING_IN_PROGRESS Lighting_Output_In_Progress(
|
||||
*
|
||||
* @return true if value was set
|
||||
*/
|
||||
bool Lighting_Output_In_Progress_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_LIGHTING_IN_PROGRESS in_progress)
|
||||
bool Lighting_Output_In_Progress_Set(uint32_t object_instance,
|
||||
BACNET_LIGHTING_IN_PROGRESS in_progress)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
@@ -495,7 +474,6 @@ bool Lighting_Output_In_Progress_Set(
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if (index < MAX_LIGHTING_OUTPUTS) {
|
||||
Lighting_Output[index].In_Progress = in_progress;
|
||||
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -508,8 +486,7 @@ bool Lighting_Output_In_Progress_Set(
|
||||
*
|
||||
* @return the tracking-value of this object instance.
|
||||
*/
|
||||
float Lighting_Output_Tracking_Value(
|
||||
uint32_t object_instance)
|
||||
float Lighting_Output_Tracking_Value(uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
unsigned index = 0;
|
||||
@@ -531,9 +508,7 @@ float Lighting_Output_Tracking_Value(
|
||||
*
|
||||
* @return true if value was set
|
||||
*/
|
||||
bool Lighting_Output_Tracking_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value)
|
||||
bool Lighting_Output_Tracking_Value_Set(uint32_t object_instance, float value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index = 0;
|
||||
@@ -555,8 +530,7 @@ bool Lighting_Output_Tracking_Value_Set(
|
||||
*
|
||||
* @return the blink-warn-enable property value of this object
|
||||
*/
|
||||
bool Lighting_Output_Blink_Warn_Enable(
|
||||
uint32_t object_instance)
|
||||
bool Lighting_Output_Blink_Warn_Enable(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned index = 0;
|
||||
@@ -578,9 +552,8 @@ bool Lighting_Output_Blink_Warn_Enable(
|
||||
*
|
||||
* @return true if value was set
|
||||
*/
|
||||
bool Lighting_Output_Blink_Warn_Enable_Set(
|
||||
uint32_t object_instance,
|
||||
bool enable)
|
||||
bool Lighting_Output_Blink_Warn_Enable_Set(uint32_t object_instance,
|
||||
bool enable)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index = 0;
|
||||
@@ -602,8 +575,7 @@ bool Lighting_Output_Blink_Warn_Enable_Set(
|
||||
*
|
||||
* @return the egress-time property value of this object
|
||||
*/
|
||||
uint32_t Lighting_Output_Egress_Time(
|
||||
uint32_t object_instance)
|
||||
uint32_t Lighting_Output_Egress_Time(uint32_t object_instance)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
unsigned int index = 0;
|
||||
@@ -625,9 +597,7 @@ uint32_t Lighting_Output_Egress_Time(
|
||||
*
|
||||
* @return true if value was set
|
||||
*/
|
||||
bool Lighting_Output_Egress_Time_Set(
|
||||
uint32_t object_instance,
|
||||
uint32_t seconds)
|
||||
bool Lighting_Output_Egress_Time_Set(uint32_t object_instance, uint32_t seconds)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index = 0;
|
||||
@@ -649,8 +619,7 @@ bool Lighting_Output_Egress_Time_Set(
|
||||
*
|
||||
* @return the egress-active property value of this object
|
||||
*/
|
||||
bool Lighting_Output_Egress_Active(
|
||||
uint32_t object_instance)
|
||||
bool Lighting_Output_Egress_Active(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned int index = 0;
|
||||
@@ -671,8 +640,7 @@ bool Lighting_Output_Egress_Active(
|
||||
*
|
||||
* @return the fade-time property value of this object
|
||||
*/
|
||||
uint32_t Lighting_Output_Default_Fade_Time(
|
||||
uint32_t object_instance)
|
||||
uint32_t Lighting_Output_Default_Fade_Time(uint32_t object_instance)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
unsigned int index = 0;
|
||||
@@ -694,16 +662,14 @@ uint32_t Lighting_Output_Default_Fade_Time(
|
||||
*
|
||||
* @return true if value was set
|
||||
*/
|
||||
bool Lighting_Output_Default_Fade_Time_Set(
|
||||
uint32_t object_instance,
|
||||
uint32_t milliseconds)
|
||||
bool Lighting_Output_Default_Fade_Time_Set(uint32_t object_instance,
|
||||
uint32_t milliseconds)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index = 0;
|
||||
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if ((index < MAX_LIGHTING_OUTPUTS) &&
|
||||
(milliseconds >= 100) &&
|
||||
if ((index < MAX_LIGHTING_OUTPUTS) && (milliseconds >= 100) &&
|
||||
(milliseconds <= 86400000)) {
|
||||
Lighting_Output[index].Default_Fade_Time = milliseconds;
|
||||
status = true;
|
||||
@@ -720,8 +686,7 @@ bool Lighting_Output_Default_Fade_Time_Set(
|
||||
*
|
||||
* @return the ramp-rate property value of this object
|
||||
*/
|
||||
float Lighting_Output_Default_Ramp_Rate(
|
||||
uint32_t object_instance)
|
||||
float Lighting_Output_Default_Ramp_Rate(uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
unsigned int index = 0;
|
||||
@@ -743,16 +708,14 @@ float Lighting_Output_Default_Ramp_Rate(
|
||||
*
|
||||
* @return true if value was set
|
||||
*/
|
||||
bool Lighting_Output_Default_Ramp_Rate_Set(
|
||||
uint32_t object_instance,
|
||||
float percent_per_second)
|
||||
bool Lighting_Output_Default_Ramp_Rate_Set(uint32_t object_instance,
|
||||
float percent_per_second)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index = 0;
|
||||
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if ((index < MAX_LIGHTING_OUTPUTS) &&
|
||||
(percent_per_second >= 0.1) &&
|
||||
if ((index < MAX_LIGHTING_OUTPUTS) && (percent_per_second >= 0.1) &&
|
||||
(percent_per_second <= 100.0)) {
|
||||
Lighting_Output[index].Default_Ramp_Rate = percent_per_second;
|
||||
status = true;
|
||||
@@ -769,8 +732,7 @@ bool Lighting_Output_Default_Ramp_Rate_Set(
|
||||
*
|
||||
* @return the default-step-increment property value of this object
|
||||
*/
|
||||
float Lighting_Output_Default_Step_Increment(
|
||||
uint32_t object_instance)
|
||||
float Lighting_Output_Default_Step_Increment(uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
unsigned int index = 0;
|
||||
@@ -792,16 +754,14 @@ float Lighting_Output_Default_Step_Increment(
|
||||
*
|
||||
* @return true if value was set
|
||||
*/
|
||||
bool Lighting_Output_Default_Step_Increment_Set(
|
||||
uint32_t object_instance,
|
||||
float step_increment)
|
||||
bool Lighting_Output_Default_Step_Increment_Set(uint32_t object_instance,
|
||||
float step_increment)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index = 0;
|
||||
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if ((index < MAX_LIGHTING_OUTPUTS) &&
|
||||
(step_increment >= 0.1) &&
|
||||
if ((index < MAX_LIGHTING_OUTPUTS) && (step_increment >= 0.1) &&
|
||||
(step_increment <= 100.0)) {
|
||||
Lighting_Output[index].Default_Step_Increment = step_increment;
|
||||
status = true;
|
||||
@@ -820,8 +780,7 @@ bool Lighting_Output_Default_Step_Increment_Set(
|
||||
* @return the lighting-command-default-priority property value of
|
||||
* this object
|
||||
*/
|
||||
unsigned Lighting_Output_Default_Priority(
|
||||
uint32_t object_instance)
|
||||
unsigned Lighting_Output_Default_Priority(uint32_t object_instance)
|
||||
{
|
||||
unsigned value = 0;
|
||||
unsigned int index = 0;
|
||||
@@ -843,16 +802,14 @@ unsigned Lighting_Output_Default_Priority(
|
||||
*
|
||||
* @return true if value was set
|
||||
*/
|
||||
bool Lighting_Output_Default_Priority_Set(
|
||||
uint32_t object_instance,
|
||||
unsigned priority)
|
||||
bool Lighting_Output_Default_Priority_Set(uint32_t object_instance,
|
||||
unsigned priority)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index = 0;
|
||||
|
||||
index = Lighting_Output_Instance_To_Index(object_instance);
|
||||
if ((index < MAX_LIGHTING_OUTPUTS) &&
|
||||
(priority >= BACNET_MIN_PRIORITY) &&
|
||||
if ((index < MAX_LIGHTING_OUTPUTS) && (priority >= BACNET_MIN_PRIORITY) &&
|
||||
(priority <= BACNET_MAX_PRIORITY)) {
|
||||
Lighting_Output[index].Lighting_Command_Default_Priority = priority;
|
||||
status = true;
|
||||
@@ -869,8 +826,7 @@ bool Lighting_Output_Default_Priority_Set(
|
||||
*
|
||||
* @return out-of-service property value
|
||||
*/
|
||||
bool Lighting_Output_Out_Of_Service(
|
||||
uint32_t object_instance)
|
||||
bool Lighting_Output_Out_Of_Service(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned int index = 0;
|
||||
@@ -891,9 +847,7 @@ bool Lighting_Output_Out_Of_Service(
|
||||
*
|
||||
* @return true if the out-of-service property value was set
|
||||
*/
|
||||
void Lighting_Output_Out_Of_Service_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
void Lighting_Output_Out_Of_Service_Set(uint32_t object_instance, bool value)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
|
||||
@@ -911,8 +865,7 @@ void Lighting_Output_Out_Of_Service_Set(
|
||||
*
|
||||
* @return relinquish-default property value
|
||||
*/
|
||||
float Lighting_Output_Relinquish_Default(
|
||||
uint32_t object_instance)
|
||||
float Lighting_Output_Relinquish_Default(uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
unsigned int index = 0;
|
||||
@@ -934,9 +887,8 @@ float Lighting_Output_Relinquish_Default(
|
||||
*
|
||||
* @return true if the relinquish-default property value was set
|
||||
*/
|
||||
bool Lighting_Output_Relinquish_Default_Set(
|
||||
uint32_t object_instance,
|
||||
float value)
|
||||
bool Lighting_Output_Relinquish_Default_Set(uint32_t object_instance,
|
||||
float value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned int index = 0;
|
||||
@@ -959,15 +911,14 @@ bool Lighting_Output_Relinquish_Default_Set(
|
||||
* @return number of APDU bytes in the response, or
|
||||
* BACNET_STATUS_ERROR on error.
|
||||
*/
|
||||
int Lighting_Output_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Lighting_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_LIGHTING_COMMAND lighting_command;
|
||||
float real_value = (float) 1.414;
|
||||
float real_value = (float)1.414;
|
||||
uint32_t unsigned_value = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
@@ -980,9 +931,8 @@ int Lighting_Output_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_LIGHTING_OUTPUT,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_LIGHTING_OUTPUT, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Lighting_Output_Object_Name(rpdata->object_instance, &char_string);
|
||||
@@ -1003,17 +953,14 @@ int Lighting_Output_Read_Property(
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_LIGHTING_COMMAND:
|
||||
Lighting_Output_Lighting_Command(
|
||||
rpdata->object_instance,
|
||||
&lighting_command);
|
||||
apdu_len = lighting_command_encode(&apdu[0],
|
||||
&lighting_command);
|
||||
Lighting_Output_Lighting_Command(rpdata->object_instance,
|
||||
&lighting_command);
|
||||
apdu_len = lighting_command_encode(&apdu[0], &lighting_command);
|
||||
break;
|
||||
case PROP_IN_PROGRESS:
|
||||
unsigned_value = Lighting_Output_In_Progress(
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
unsigned_value);
|
||||
unsigned_value =
|
||||
Lighting_Output_In_Progress(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], unsigned_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
@@ -1033,20 +980,18 @@ int Lighting_Output_Read_Property(
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_EGRESS_TIME:
|
||||
unsigned_value = Lighting_Output_Egress_Time(
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
unsigned_value);
|
||||
unsigned_value =
|
||||
Lighting_Output_Egress_Time(rpdata->object_instance);
|
||||
apdu_len = encode_application_unsigned(&apdu[0], unsigned_value);
|
||||
break;
|
||||
case PROP_EGRESS_ACTIVE:
|
||||
state = Lighting_Output_Egress_Active(rpdata->object_instance);
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_DEFAULT_FADE_TIME:
|
||||
unsigned_value = Lighting_Output_Default_Fade_Time(
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
unsigned_value);
|
||||
unsigned_value =
|
||||
Lighting_Output_Default_Fade_Time(rpdata->object_instance);
|
||||
apdu_len = encode_application_unsigned(&apdu[0], unsigned_value);
|
||||
break;
|
||||
case PROP_DEFAULT_RAMP_RATE:
|
||||
real_value =
|
||||
@@ -1063,17 +1008,17 @@ int Lighting_Output_Read_Property(
|
||||
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. */
|
||||
/* 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 = 1; i <= BACNET_MAX_PRIORITY; i++) {
|
||||
if (Lighting_Output_Priority_Active(
|
||||
rpdata->object_instance, i)) {
|
||||
if (Lighting_Output_Priority_Active(rpdata->object_instance,
|
||||
i)) {
|
||||
real_value = Lighting_Output_Priority_Value(
|
||||
rpdata->object_instance, i);
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
len = encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
} else {
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
}
|
||||
@@ -1089,15 +1034,12 @@ int Lighting_Output_Read_Property(
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Lighting_Output_Priority_Active(
|
||||
rpdata->object_instance,
|
||||
rpdata->array_index)) {
|
||||
if (Lighting_Output_Priority_Active(rpdata->object_instance,
|
||||
rpdata->array_index)) {
|
||||
real_value = Lighting_Output_Priority_Value(
|
||||
rpdata->object_instance,
|
||||
rpdata->array_index);
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
rpdata->object_instance, rpdata->array_index);
|
||||
len = encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
} else {
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
}
|
||||
@@ -1109,15 +1051,14 @@ int Lighting_Output_Read_Property(
|
||||
}
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = Lighting_Output_Relinquish_Default(
|
||||
rpdata->object_instance);
|
||||
real_value =
|
||||
Lighting_Output_Relinquish_Default(rpdata->object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_LIGHTING_COMMAND_DEFAULT_PRIORITY:
|
||||
unsigned_value = Lighting_Output_Default_Priority(
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
unsigned_value);
|
||||
unsigned_value =
|
||||
Lighting_Output_Default_Priority(rpdata->object_instance);
|
||||
apdu_len = encode_application_unsigned(&apdu[0], unsigned_value);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -1145,17 +1086,15 @@ int Lighting_Output_Read_Property(
|
||||
*
|
||||
* @return false if an error is loaded, true if no errors
|
||||
*/
|
||||
bool Lighting_Output_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Lighting_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -1176,9 +1115,9 @@ bool Lighting_Output_Write_Property(
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
status =
|
||||
Lighting_Output_Present_Value_Set(wp_data->object_instance,
|
||||
value.type.Real, wp_data->priority);
|
||||
status = Lighting_Output_Present_Value_Set(
|
||||
wp_data->object_instance, value.type.Real,
|
||||
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
|
||||
@@ -1190,14 +1129,15 @@ bool Lighting_Output_Write_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);
|
||||
status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
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. - Note Lighting_Output_Present_Value_Relinquish()
|
||||
/* Command priority 6 is reserved for use by Minimum
|
||||
On/Off algorithm and may not be used for other
|
||||
purposes in any object. - Note
|
||||
Lighting_Output_Present_Value_Relinquish()
|
||||
will have returned false because of this */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
@@ -1215,8 +1155,7 @@ bool Lighting_Output_Write_Property(
|
||||
case PROP_LIGHTING_COMMAND:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_LIGHTING_COMMAND) {
|
||||
status = Lighting_Output_Lighting_Command_Set(
|
||||
wp_data->object_instance,
|
||||
&value.type.Lighting_Command);
|
||||
wp_data->object_instance, &value.type.Lighting_Command);
|
||||
if (!status) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
@@ -1229,11 +1168,10 @@ bool Lighting_Output_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Lighting_Output_Out_Of_Service_Set(
|
||||
wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
Lighting_Output_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -1270,13 +1208,11 @@ bool Lighting_Output_Write_Property(
|
||||
* @param milliseconds - number of milliseconds elapsed since previously
|
||||
* called. Works best when called about every 10 milliseconds.
|
||||
*/
|
||||
static void Lighting_Output_Ramp_Handler(
|
||||
struct lighting_output_object *pLight,
|
||||
BACNET_LIGHTING_COMMAND *pCommand,
|
||||
uint16_t milliseconds)
|
||||
static void Lighting_Output_Ramp_Handler(struct lighting_output_object *pLight,
|
||||
BACNET_LIGHTING_COMMAND *pCommand,
|
||||
uint16_t milliseconds)
|
||||
{
|
||||
if (pLight && pCommand) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1288,13 +1224,11 @@ static void Lighting_Output_Ramp_Handler(
|
||||
* @param milliseconds - number of milliseconds elapsed since previously
|
||||
* called. Works best when called about every 10 milliseconds.
|
||||
*/
|
||||
static void Lighting_Output_Fade_Handler(
|
||||
struct lighting_output_object *pLight,
|
||||
BACNET_LIGHTING_COMMAND *pCommand,
|
||||
uint16_t milliseconds)
|
||||
static void Lighting_Output_Fade_Handler(struct lighting_output_object *pLight,
|
||||
BACNET_LIGHTING_COMMAND *pCommand,
|
||||
uint16_t milliseconds)
|
||||
{
|
||||
if (pLight && pCommand) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1305,9 +1239,7 @@ static void Lighting_Output_Fade_Handler(
|
||||
* @param milliseconds - number of milliseconds elapsed since previously
|
||||
* called. Works best when called about every 10 milliseconds.
|
||||
*/
|
||||
static void Lighting_Output_Timer_Handler(
|
||||
unsigned index,
|
||||
uint16_t milliseconds)
|
||||
static void Lighting_Output_Timer_Handler(unsigned index, uint16_t milliseconds)
|
||||
{
|
||||
struct lighting_output_object *pLight = NULL;
|
||||
BACNET_LIGHTING_COMMAND *pCommand = NULL;
|
||||
@@ -1352,8 +1284,7 @@ static void Lighting_Output_Timer_Handler(
|
||||
* @param milliseconds - number of milliseconds elapsed since previously
|
||||
* called. Works best when called about every 10 milliseconds.
|
||||
*/
|
||||
void Lighting_Output_Timer(
|
||||
uint16_t milliseconds)
|
||||
void Lighting_Output_Timer(uint16_t milliseconds)
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
@@ -1365,8 +1296,7 @@ void Lighting_Output_Timer(
|
||||
/**
|
||||
* Initializes the Lighting Output object data
|
||||
*/
|
||||
void Lighting_Output_Init(
|
||||
void)
|
||||
void Lighting_Output_Init(void)
|
||||
{
|
||||
unsigned i, p;
|
||||
|
||||
@@ -1410,11 +1340,9 @@ void Lighting_Output_Init(
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -1424,10 +1352,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testLightingOutput(
|
||||
Test * pTest)
|
||||
void testLightingOutput(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -1454,8 +1381,7 @@ void testLightingOutput(
|
||||
}
|
||||
|
||||
#ifdef TEST_LIGHTING_OUTPUT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -1467,7 +1393,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+71
-105
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Life Safety Point Objects - customize for your use */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "lsp.h"
|
||||
@@ -45,8 +45,7 @@
|
||||
|
||||
/* Here are our stored levels.*/
|
||||
static BACNET_LIFE_SAFETY_MODE Life_Safety_Point_Mode[MAX_LIFE_SAFETY_POINTS];
|
||||
static BACNET_LIFE_SAFETY_STATE
|
||||
Life_Safety_Point_State[MAX_LIFE_SAFETY_POINTS];
|
||||
static BACNET_LIFE_SAFETY_STATE Life_Safety_Point_State[MAX_LIFE_SAFETY_POINTS];
|
||||
static BACNET_SILENCED_STATE
|
||||
Life_Safety_Point_Silenced_State[MAX_LIFE_SAFETY_POINTS];
|
||||
static BACNET_LIFE_SAFETY_OPERATION
|
||||
@@ -57,30 +56,18 @@ static bool Life_Safety_Point_Out_Of_Service[MAX_LIFE_SAFETY_POINTS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Life_Safety_Point_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_TRACKING_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_RELIABILITY,
|
||||
PROP_MODE,
|
||||
PROP_ACCEPTED_MODES,
|
||||
PROP_SILENCED,
|
||||
PROP_OPERATION_EXPECTED,
|
||||
-1
|
||||
};
|
||||
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE, PROP_PRESENT_VALUE,
|
||||
PROP_TRACKING_VALUE, PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE, PROP_OUT_OF_SERVICE,
|
||||
PROP_RELIABILITY, PROP_MODE,
|
||||
PROP_ACCEPTED_MODES, PROP_SILENCED,
|
||||
PROP_OPERATION_EXPECTED, -1};
|
||||
|
||||
static const int Life_Safety_Point_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
static const int Life_Safety_Point_Properties_Optional[] = {PROP_DESCRIPTION,
|
||||
-1};
|
||||
|
||||
static const int Life_Safety_Point_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Life_Safety_Point_Properties_Proprietary[] = {-1};
|
||||
|
||||
/**
|
||||
* Returns the list of required, optional, and proprietary properties.
|
||||
@@ -93,10 +80,9 @@ static const int Life_Safety_Point_Properties_Proprietary[] = {
|
||||
* @param pProprietary - pointer to list of int terminated by -1, of
|
||||
* BACnet proprietary properties for this object.
|
||||
*/
|
||||
void Life_Safety_Point_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Life_Safety_Point_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired) {
|
||||
*pRequired = Life_Safety_Point_Properties_Required;
|
||||
@@ -111,8 +97,7 @@ void Life_Safety_Point_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Life_Safety_Point_Init(
|
||||
void)
|
||||
void Life_Safety_Point_Init(void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
@@ -135,8 +120,7 @@ void Life_Safety_Point_Init(
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Life_Safety_Point_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Life_Safety_Point_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_LIFE_SAFETY_POINTS)
|
||||
return true;
|
||||
@@ -146,8 +130,7 @@ bool Life_Safety_Point_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Life_Safety_Point_Count(
|
||||
void)
|
||||
unsigned Life_Safety_Point_Count(void)
|
||||
{
|
||||
return MAX_LIFE_SAFETY_POINTS;
|
||||
}
|
||||
@@ -155,8 +138,7 @@ unsigned Life_Safety_Point_Count(
|
||||
/* 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 Life_Safety_Point_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Life_Safety_Point_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -164,8 +146,7 @@ uint32_t Life_Safety_Point_Index_To_Instance(
|
||||
/* 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 Life_Safety_Point_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Life_Safety_Point_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_LIFE_SAFETY_POINTS;
|
||||
|
||||
@@ -189,11 +170,10 @@ static BACNET_LIFE_SAFETY_STATE Life_Safety_Point_Present_Value(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Life_Safety_Point_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Life_Safety_Point_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_LIFE_SAFETY_POINTS) {
|
||||
@@ -205,11 +185,10 @@ bool Life_Safety_Point_Object_Name(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Life_Safety_Point_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Life_Safety_Point_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_LIFE_SAFETY_STATE present_value = LIFE_SAFETY_STATE_QUIET;
|
||||
@@ -228,21 +207,19 @@ int Life_Safety_Point_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_LIFE_SAFETY_POINT, rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_LIFE_SAFETY_POINT, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
Life_Safety_Point_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
&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_LIFE_SAFETY_POINT);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_LIFE_SAFETY_POINT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
@@ -286,7 +263,7 @@ int Life_Safety_Point_Read_Property(
|
||||
break;
|
||||
case PROP_ACCEPTED_MODES:
|
||||
for (mode = MIN_LIFE_SAFETY_MODE; mode < MAX_LIFE_SAFETY_MODE;
|
||||
mode++) {
|
||||
mode++) {
|
||||
len = encode_application_enumerated(&apdu[apdu_len], mode);
|
||||
apdu_len += len;
|
||||
}
|
||||
@@ -320,18 +297,16 @@ int Life_Safety_Point_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Life_Safety_Point_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Life_Safety_Point_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
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);
|
||||
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 */
|
||||
@@ -349,12 +324,11 @@ bool Life_Safety_Point_Write_Property(
|
||||
case PROP_MODE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
if (value.type.Enumerated <= MAX_LIFE_SAFETY_MODE) {
|
||||
object_index =
|
||||
Life_Safety_Point_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
object_index = Life_Safety_Point_Instance_To_Index(
|
||||
wp_data->object_instance);
|
||||
Life_Safety_Point_Mode[object_index] =
|
||||
value.type.Enumerated;
|
||||
} else {
|
||||
@@ -367,18 +341,15 @@ bool Life_Safety_Point_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
object_index =
|
||||
Life_Safety_Point_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
object_index = Life_Safety_Point_Instance_To_Index(
|
||||
wp_data->object_instance);
|
||||
Life_Safety_Point_Out_Of_Service[object_index] =
|
||||
value.type.Boolean;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
@@ -403,17 +374,14 @@ bool Life_Safety_Point_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -423,10 +391,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testLifeSafetyPoint(
|
||||
Test * pTest)
|
||||
void testLifeSafetyPoint(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -453,8 +420,7 @@ void testLifeSafetyPoint(
|
||||
}
|
||||
|
||||
#ifdef TEST_LIFE_SAFETY_POINT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -466,7 +432,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+139
-197
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Multi-state Input Objects */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "device.h"
|
||||
@@ -59,31 +59,18 @@ static char State_Text[MAX_MULTISTATE_INPUTS][MULTISTATE_NUMBER_OF_STATES][64];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_NUMBER_OF_STATES,
|
||||
-1
|
||||
};
|
||||
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE, PROP_NUMBER_OF_STATES, -1};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
PROP_STATE_TEXT,
|
||||
-1
|
||||
};
|
||||
static const int Properties_Optional[] = {PROP_DESCRIPTION, PROP_STATE_TEXT,
|
||||
-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Multistate_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Multistate_Input_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -95,8 +82,7 @@ void Multistate_Input_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Multistate_Input_Init(
|
||||
void)
|
||||
void Multistate_Input_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
@@ -113,8 +99,7 @@ void Multistate_Input_Init(
|
||||
/* 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 Multistate_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Multistate_Input_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_MULTISTATE_INPUTS;
|
||||
|
||||
@@ -127,22 +112,19 @@ unsigned Multistate_Input_Instance_To_Index(
|
||||
/* 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 Multistate_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Multistate_Input_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Multistate_Input_Count(
|
||||
void)
|
||||
unsigned Multistate_Input_Count(void)
|
||||
{
|
||||
return MAX_MULTISTATE_INPUTS;
|
||||
}
|
||||
|
||||
bool Multistate_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Multistate_Input_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
|
||||
@@ -154,14 +136,12 @@ bool Multistate_Input_Valid_Instance(
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint32_t Multistate_Input_Max_States(
|
||||
uint32_t instance)
|
||||
static uint32_t Multistate_Input_Max_States(uint32_t instance)
|
||||
{
|
||||
return MULTISTATE_NUMBER_OF_STATES;
|
||||
}
|
||||
|
||||
uint32_t Multistate_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
uint32_t Multistate_Input_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
uint32_t value = 1;
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
@@ -174,9 +154,8 @@ uint32_t Multistate_Input_Present_Value(
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Multistate_Input_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
uint32_t value)
|
||||
bool Multistate_Input_Present_Value_Set(uint32_t object_instance,
|
||||
uint32_t value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
@@ -184,7 +163,7 @@ bool Multistate_Input_Present_Value_Set(
|
||||
index = Multistate_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_MULTISTATE_INPUTS) {
|
||||
if ((value > 0) && (value <= MULTISTATE_NUMBER_OF_STATES)) {
|
||||
Present_Value[index] = (uint8_t) value;
|
||||
Present_Value[index] = (uint8_t)value;
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
@@ -192,8 +171,7 @@ bool Multistate_Input_Present_Value_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Multistate_Input_Out_Of_Service(
|
||||
uint32_t object_instance)
|
||||
bool Multistate_Input_Out_Of_Service(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned index = 0;
|
||||
@@ -206,9 +184,7 @@ bool Multistate_Input_Out_Of_Service(
|
||||
return value;
|
||||
}
|
||||
|
||||
void Multistate_Input_Out_Of_Service_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
void Multistate_Input_Out_Of_Service_Set(uint32_t object_instance, bool value)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -220,8 +196,7 @@ void Multistate_Input_Out_Of_Service_Set(
|
||||
return;
|
||||
}
|
||||
|
||||
char *Multistate_Input_Description(
|
||||
uint32_t object_instance)
|
||||
char *Multistate_Input_Description(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
char *pName = NULL; /* return value */
|
||||
@@ -234,13 +209,11 @@ char *Multistate_Input_Description(
|
||||
return pName;
|
||||
}
|
||||
|
||||
bool Multistate_Input_Description_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name)
|
||||
bool Multistate_Input_Description_Set(uint32_t object_instance, char *new_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_MULTISTATE_INPUTS) {
|
||||
@@ -263,15 +236,13 @@ bool Multistate_Input_Description_Set(
|
||||
}
|
||||
|
||||
static bool Multistate_Input_Description_Write(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * char_string,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
uint32_t object_instance, BACNET_CHARACTER_STRING *char_string,
|
||||
BACNET_ERROR_CLASS *error_class, BACNET_ERROR_CODE *error_code)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t length = 0;
|
||||
uint8_t encoding = 0;
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_MULTISTATE_INPUTS) {
|
||||
@@ -279,8 +250,8 @@ static bool Multistate_Input_Description_Write(
|
||||
if (length <= sizeof(Object_Description[index])) {
|
||||
encoding = characterstring_encoding(char_string);
|
||||
if (encoding == CHARACTER_UTF8) {
|
||||
status =
|
||||
characterstring_ansi_copy(Object_Description[index],
|
||||
status = characterstring_ansi_copy(
|
||||
Object_Description[index],
|
||||
sizeof(Object_Description[index]), char_string);
|
||||
if (!status) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -299,10 +270,8 @@ static bool Multistate_Input_Description_Write(
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
bool Multistate_Input_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Multistate_Input_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
bool status = false;
|
||||
@@ -316,13 +285,11 @@ bool Multistate_Input_Object_Name(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Multistate_Input_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name)
|
||||
bool Multistate_Input_Name_Set(uint32_t object_instance, char *new_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_MULTISTATE_INPUTS) {
|
||||
@@ -346,15 +313,13 @@ bool Multistate_Input_Name_Set(
|
||||
}
|
||||
|
||||
static bool Multistate_Input_Object_Name_Write(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * char_string,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
uint32_t object_instance, BACNET_CHARACTER_STRING *char_string,
|
||||
BACNET_ERROR_CLASS *error_class, BACNET_ERROR_CODE *error_code)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t length = 0;
|
||||
uint8_t encoding = 0;
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_MULTISTATE_INPUTS) {
|
||||
@@ -362,9 +327,9 @@ static bool Multistate_Input_Object_Name_Write(
|
||||
if (length <= sizeof(Object_Name[index])) {
|
||||
encoding = characterstring_encoding(char_string);
|
||||
if (encoding == CHARACTER_UTF8) {
|
||||
status =
|
||||
characterstring_ansi_copy(Object_Name[index],
|
||||
sizeof(Object_Name[index]), char_string);
|
||||
status = characterstring_ansi_copy(Object_Name[index],
|
||||
sizeof(Object_Name[index]),
|
||||
char_string);
|
||||
if (!status) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
@@ -382,9 +347,8 @@ static bool Multistate_Input_Object_Name_Write(
|
||||
return status;
|
||||
}
|
||||
|
||||
char *Multistate_Input_State_Text(
|
||||
uint32_t object_instance,
|
||||
uint32_t state_index)
|
||||
char *Multistate_Input_State_Text(uint32_t object_instance,
|
||||
uint32_t state_index)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
char *pName = NULL; /* return value */
|
||||
@@ -400,14 +364,12 @@ char *Multistate_Input_State_Text(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Multistate_Input_State_Text_Set(
|
||||
uint32_t object_instance,
|
||||
uint32_t state_index,
|
||||
char *new_name)
|
||||
bool Multistate_Input_State_Text_Set(uint32_t object_instance,
|
||||
uint32_t state_index, char *new_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Input_Instance_To_Index(object_instance);
|
||||
if ((index < MAX_MULTISTATE_INPUTS) && (state_index > 0) &&
|
||||
@@ -428,20 +390,19 @@ bool Multistate_Input_State_Text_Set(
|
||||
}
|
||||
}
|
||||
|
||||
return status;;
|
||||
return status;
|
||||
;
|
||||
}
|
||||
|
||||
static bool Multistate_Input_State_Text_Write(
|
||||
uint32_t object_instance,
|
||||
uint32_t state_index,
|
||||
BACNET_CHARACTER_STRING * char_string,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
uint32_t object_instance, uint32_t state_index,
|
||||
BACNET_CHARACTER_STRING *char_string, BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t length = 0;
|
||||
uint8_t encoding = 0;
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Input_Instance_To_Index(object_instance);
|
||||
if ((index < MAX_MULTISTATE_INPUTS) && (state_index > 0) &&
|
||||
@@ -451,8 +412,8 @@ static bool Multistate_Input_State_Text_Write(
|
||||
if (length <= sizeof(State_Text[index][state_index])) {
|
||||
encoding = characterstring_encoding(char_string);
|
||||
if (encoding == CHARACTER_UTF8) {
|
||||
status =
|
||||
characterstring_ansi_copy(State_Text[index][state_index],
|
||||
status = characterstring_ansi_copy(
|
||||
State_Text[index][state_index],
|
||||
sizeof(State_Text[index][state_index]), char_string);
|
||||
if (!status) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -475,11 +436,10 @@ static bool Multistate_Input_State_Text_Write(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Multistate_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Multistate_Input_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint32_t present_value = 0;
|
||||
@@ -495,28 +455,26 @@ int Multistate_Input_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_MULTI_STATE_INPUT, rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_MULTI_STATE_INPUT, rpdata->object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
Multistate_Input_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
Multistate_Input_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
characterstring_init_ansi(
|
||||
&char_string,
|
||||
Multistate_Input_Description(rpdata->object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_MULTI_STATE_INPUT);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_MULTI_STATE_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
@@ -531,10 +489,10 @@ int Multistate_Input_Read_Property(
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
if (Multistate_Input_Out_Of_Service(rpdata->object_instance)) {
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
true);
|
||||
true);
|
||||
} else {
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
false);
|
||||
false);
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
@@ -548,29 +506,29 @@ int Multistate_Input_Read_Property(
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_NUMBER_OF_STATES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[apdu_len],
|
||||
Multistate_Input_Max_States(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_STATE_TEXT:
|
||||
if (rpdata->array_index == 0) {
|
||||
/* Array element zero is the number of elements in the array */
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0],
|
||||
Multistate_Input_Max_States(rpdata->object_instance));
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* if no index was specified, then try to encode the entire list
|
||||
*/
|
||||
/* into one packet. */
|
||||
max_states =
|
||||
Multistate_Input_Max_States(rpdata->object_instance);
|
||||
for (i = 1; i <= max_states; i++) {
|
||||
characterstring_init_ansi(&char_string,
|
||||
Multistate_Input_State_Text(rpdata->object_instance,
|
||||
i));
|
||||
Multistate_Input_State_Text(
|
||||
rpdata->object_instance, i));
|
||||
/* FIXME: this might go beyond MAX_APDU length! */
|
||||
len =
|
||||
encode_application_character_string(&apdu[apdu_len],
|
||||
&char_string);
|
||||
len = encode_application_character_string(&apdu[apdu_len],
|
||||
&char_string);
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU) {
|
||||
apdu_len += len;
|
||||
@@ -585,12 +543,12 @@ int Multistate_Input_Read_Property(
|
||||
max_states =
|
||||
Multistate_Input_Max_States(rpdata->object_instance);
|
||||
if (rpdata->array_index <= max_states) {
|
||||
characterstring_init_ansi(&char_string,
|
||||
characterstring_init_ansi(
|
||||
&char_string,
|
||||
Multistate_Input_State_Text(rpdata->object_instance,
|
||||
rpdata->array_index));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0],
|
||||
&char_string);
|
||||
rpdata->array_index));
|
||||
apdu_len = encode_application_character_string(
|
||||
&apdu[0], &char_string);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
@@ -616,10 +574,9 @@ int Multistate_Input_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Multistate_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Multistate_Input_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
int element_len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
@@ -629,9 +586,8 @@ bool Multistate_Input_Write_Property(
|
||||
uint32_t object_instance = 0;
|
||||
|
||||
/* decode the first chunk of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
len = bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* len < application_data_len: extra data for arrays only */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
@@ -651,7 +607,7 @@ bool Multistate_Input_Write_Property(
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
/* All the object names in a device must be unique */
|
||||
if (Device_Valid_Object_Name(&value.type.Character_String,
|
||||
&object_type, &object_instance)) {
|
||||
&object_type, &object_instance)) {
|
||||
if ((object_type == wp_data->object_type) &&
|
||||
(object_instance == wp_data->object_instance)) {
|
||||
/* writing same name to same object */
|
||||
@@ -662,9 +618,8 @@ bool Multistate_Input_Write_Property(
|
||||
wp_data->error_code = ERROR_CODE_DUPLICATE_NAME;
|
||||
}
|
||||
} else {
|
||||
status =
|
||||
Multistate_Input_Object_Name_Write(wp_data->
|
||||
object_instance, &value.type.Character_String,
|
||||
status = Multistate_Input_Object_Name_Write(
|
||||
wp_data->object_instance, &value.type.Character_String,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
}
|
||||
} else {
|
||||
@@ -674,9 +629,8 @@ bool Multistate_Input_Write_Property(
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
status =
|
||||
Multistate_Input_Description_Write(wp_data->
|
||||
object_instance, &value.type.Character_String,
|
||||
status = Multistate_Input_Description_Write(
|
||||
wp_data->object_instance, &value.type.Character_String,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -686,11 +640,10 @@ bool Multistate_Input_Write_Property(
|
||||
case PROP_PRESENT_VALUE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
status =
|
||||
Multistate_Input_Present_Value_Set
|
||||
(wp_data->object_instance, value.type.Unsigned_Int);
|
||||
status = Multistate_Input_Present_Value_Set(
|
||||
wp_data->object_instance, value.type.Unsigned_Int);
|
||||
if (!status) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
@@ -700,10 +653,10 @@ bool Multistate_Input_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Multistate_Input_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_STATE_TEXT:
|
||||
@@ -721,18 +674,16 @@ bool Multistate_Input_Write_Property(
|
||||
element_len = len;
|
||||
do {
|
||||
if (element_len) {
|
||||
status =
|
||||
Multistate_Input_State_Text_Write(wp_data->
|
||||
object_instance, array_index,
|
||||
status = Multistate_Input_State_Text_Write(
|
||||
wp_data->object_instance, array_index,
|
||||
&value.type.Character_String,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
}
|
||||
max_states--;
|
||||
array_index++;
|
||||
if (max_states) {
|
||||
element_len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[len],
|
||||
element_len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[len],
|
||||
wp_data->application_data_len - len, &value);
|
||||
if (element_len < 0) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -747,11 +698,10 @@ bool Multistate_Input_Write_Property(
|
||||
max_states =
|
||||
Multistate_Input_Max_States(wp_data->object_instance);
|
||||
if (wp_data->array_index <= max_states) {
|
||||
status =
|
||||
Multistate_Input_State_Text_Write(wp_data->
|
||||
object_instance, wp_data->array_index,
|
||||
&value.type.Character_String,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
status = Multistate_Input_State_Text_Write(
|
||||
wp_data->object_instance, wp_data->array_index,
|
||||
&value.type.Character_String, &wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
@@ -779,26 +729,20 @@ bool Multistate_Input_Write_Property(
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
|
||||
bool Device_Valid_Object_Name(
|
||||
BACNET_CHARACTER_STRING * object_name,
|
||||
int *object_type,
|
||||
uint32_t * object_instance)
|
||||
bool Device_Valid_Object_Name(BACNET_CHARACTER_STRING *object_name,
|
||||
int *object_type, uint32_t *object_instance)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -808,10 +752,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testMultistateInput(
|
||||
Test * pTest)
|
||||
void testMultistateInput(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -838,8 +781,7 @@ void testMultistateInput(
|
||||
}
|
||||
|
||||
#ifdef TEST_MULTISTATE_INPUT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -851,7 +793,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+98
-127
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Multi-state Output Objects - customize for your use */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "mso.h"
|
||||
@@ -51,8 +51,8 @@
|
||||
/* how many states? 1 to 254 states, 0 is not allowed */
|
||||
#define MULTISTATE_NUMBER_OF_STATES (254)
|
||||
/* Here is our Priority Array.*/
|
||||
static uint8_t
|
||||
Multistate_Output_Level[MAX_MULTISTATE_OUTPUTS][BACNET_MAX_PRIORITY];
|
||||
static uint8_t Multistate_Output_Level[MAX_MULTISTATE_OUTPUTS]
|
||||
[BACNET_MAX_PRIORITY];
|
||||
/* Writable out-of-service allows others to play with our Present Value */
|
||||
/* without changing the physical output */
|
||||
static bool Out_Of_Service[MAX_MULTISTATE_OUTPUTS];
|
||||
@@ -69,22 +69,16 @@ static const int Multistate_Output_Properties_Required[] = {
|
||||
PROP_NUMBER_OF_STATES,
|
||||
PROP_PRIORITY_ARRAY,
|
||||
PROP_RELINQUISH_DEFAULT,
|
||||
-1
|
||||
};
|
||||
-1};
|
||||
|
||||
static const int Multistate_Output_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
static const int Multistate_Output_Properties_Optional[] = {PROP_DESCRIPTION,
|
||||
-1};
|
||||
|
||||
static const int Multistate_Output_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Multistate_Output_Properties_Proprietary[] = {-1};
|
||||
|
||||
void Multistate_Output_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Multistate_Output_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Multistate_Output_Properties_Required;
|
||||
@@ -96,8 +90,7 @@ void Multistate_Output_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Multistate_Output_Init(
|
||||
void)
|
||||
void Multistate_Output_Init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
static bool initialized = false;
|
||||
@@ -119,8 +112,7 @@ void Multistate_Output_Init(
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Multistate_Output_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Multistate_Output_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_MULTISTATE_OUTPUTS)
|
||||
return true;
|
||||
@@ -130,8 +122,7 @@ bool Multistate_Output_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Multistate_Output_Count(
|
||||
void)
|
||||
unsigned Multistate_Output_Count(void)
|
||||
{
|
||||
return MAX_MULTISTATE_OUTPUTS;
|
||||
}
|
||||
@@ -139,8 +130,7 @@ unsigned Multistate_Output_Count(
|
||||
/* 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 Multistate_Output_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Multistate_Output_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -148,8 +138,7 @@ uint32_t Multistate_Output_Index_To_Instance(
|
||||
/* 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 Multistate_Output_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Multistate_Output_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_MULTISTATE_OUTPUTS;
|
||||
|
||||
@@ -159,8 +148,7 @@ unsigned Multistate_Output_Instance_To_Index(
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t Multistate_Output_Present_Value(
|
||||
uint32_t object_instance)
|
||||
uint32_t Multistate_Output_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
uint32_t value = MULTISTATE_RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
@@ -180,11 +168,10 @@ uint32_t Multistate_Output_Present_Value(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Multistate_Output_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Multistate_Output_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_MULTISTATE_OUTPUTS) {
|
||||
@@ -195,8 +182,7 @@ bool Multistate_Output_Object_Name(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Multistate_Output_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
bool Multistate_Output_Out_Of_Service(uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
@@ -209,9 +195,7 @@ bool Multistate_Output_Out_Of_Service(
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Multistate_Output_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
void Multistate_Output_Out_Of_Service_Set(uint32_t instance, bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -222,11 +206,10 @@ void Multistate_Output_Out_Of_Service_Set(
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Multistate_Output_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Multistate_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint32_t present_value = 0;
|
||||
@@ -242,23 +225,21 @@ int Multistate_Output_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_MULTI_STATE_OUTPUT, rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_MULTI_STATE_OUTPUT, rpdata->object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
Multistate_Output_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
&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_MULTI_STATE_OUTPUT);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_MULTI_STATE_OUTPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
@@ -292,9 +273,8 @@ int Multistate_Output_Read_Property(
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. */
|
||||
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
object_index =
|
||||
Multistate_Output_Instance_To_Index
|
||||
(rpdata->object_instance);
|
||||
object_index = Multistate_Output_Instance_To_Index(
|
||||
rpdata->object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Multistate_Output_Level[object_index][i] ==
|
||||
@@ -303,9 +283,8 @@ int Multistate_Output_Read_Property(
|
||||
else {
|
||||
present_value =
|
||||
Multistate_Output_Level[object_index][i];
|
||||
len =
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
present_value);
|
||||
len = encode_application_unsigned(&apdu[apdu_len],
|
||||
present_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
@@ -318,19 +297,19 @@ int Multistate_Output_Read_Property(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object_index =
|
||||
Multistate_Output_Instance_To_Index
|
||||
(rpdata->object_instance);
|
||||
object_index = Multistate_Output_Instance_To_Index(
|
||||
rpdata->object_instance);
|
||||
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Multistate_Output_Level[object_index]
|
||||
[rpdata->array_index - 1] == MULTISTATE_NULL)
|
||||
[rpdata->array_index - 1] ==
|
||||
MULTISTATE_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
present_value = Multistate_Output_Level[object_index]
|
||||
[rpdata->array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
present_value);
|
||||
present_value =
|
||||
Multistate_Output_Level[object_index]
|
||||
[rpdata->array_index - 1];
|
||||
apdu_len = encode_application_unsigned(&apdu[0],
|
||||
present_value);
|
||||
}
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -345,9 +324,8 @@ int Multistate_Output_Read_Property(
|
||||
apdu_len = encode_application_unsigned(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_NUMBER_OF_STATES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
MULTISTATE_NUMBER_OF_STATES);
|
||||
apdu_len = encode_application_unsigned(&apdu[apdu_len],
|
||||
MULTISTATE_NUMBER_OF_STATES);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -369,10 +347,9 @@ int Multistate_Output_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Multistate_Output_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Multistate_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
uint32_t level = 0;
|
||||
@@ -380,9 +357,8 @@ bool Multistate_Output_Write_Property(
|
||||
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);
|
||||
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 */
|
||||
@@ -406,21 +382,21 @@ bool Multistate_Output_Write_Property(
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(priority != 6 /* reserved */) &&
|
||||
(value.type.Unsigned_Int > 0) &&
|
||||
(value.type.Unsigned_Int <= MULTISTATE_NUMBER_OF_STATES)) {
|
||||
level = value.type.Unsigned_Int;
|
||||
object_index =
|
||||
Multistate_Output_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
object_index = Multistate_Output_Instance_To_Index(
|
||||
wp_data->object_instance);
|
||||
priority--;
|
||||
Multistate_Output_Level[object_index][priority] =
|
||||
(uint8_t) level;
|
||||
(uint8_t)level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
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) */
|
||||
main loop (i.e. check out of service before changing
|
||||
output) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
@@ -433,25 +409,25 @@ bool Multistate_Output_Write_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);
|
||||
status = WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
level = MULTISTATE_NULL;
|
||||
object_index =
|
||||
Multistate_Output_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
object_index = Multistate_Output_Instance_To_Index(
|
||||
wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Multistate_Output_Level[object_index][priority] =
|
||||
(uint8_t) level;
|
||||
/* 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) */
|
||||
(uint8_t)level;
|
||||
/* 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) */
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -463,10 +439,10 @@ bool Multistate_Output_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Multistate_Output_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -490,17 +466,14 @@ bool Multistate_Output_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -510,10 +483,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testMultistateOutput(
|
||||
Test * pTest)
|
||||
void testMultistateOutput(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -540,8 +512,7 @@ void testMultistateOutput(
|
||||
}
|
||||
|
||||
#ifdef TEST_MULTISTATE_OUTPUT
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -553,7 +524,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+114
-163
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Multi-state Value Objects */
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "msv.h"
|
||||
@@ -63,31 +63,18 @@ static char State_Text[MAX_MULTISTATE_VALUES][MULTISTATE_NUMBER_OF_STATES][64];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_NUMBER_OF_STATES,
|
||||
-1
|
||||
};
|
||||
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE, PROP_NUMBER_OF_STATES, -1};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
PROP_STATE_TEXT,
|
||||
-1
|
||||
};
|
||||
static const int Properties_Optional[] = {PROP_DESCRIPTION, PROP_STATE_TEXT,
|
||||
-1};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Properties_Proprietary[] = {-1};
|
||||
|
||||
void Multistate_Value_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Multistate_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
@@ -99,8 +86,7 @@ void Multistate_Value_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Multistate_Value_Init(
|
||||
void)
|
||||
void Multistate_Value_Init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -117,8 +103,7 @@ void Multistate_Value_Init(
|
||||
/* 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 Multistate_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Multistate_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_MULTISTATE_VALUES;
|
||||
|
||||
@@ -131,22 +116,19 @@ unsigned Multistate_Value_Instance_To_Index(
|
||||
/* 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 Multistate_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Multistate_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Multistate_Value_Count(
|
||||
void)
|
||||
unsigned Multistate_Value_Count(void)
|
||||
{
|
||||
return MAX_MULTISTATE_VALUES;
|
||||
}
|
||||
|
||||
bool Multistate_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Multistate_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
|
||||
@@ -158,8 +140,7 @@ bool Multistate_Value_Valid_Instance(
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t Multistate_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
uint32_t Multistate_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
uint32_t value = 1;
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
@@ -172,9 +153,8 @@ uint32_t Multistate_Value_Present_Value(
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Multistate_Value_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
uint32_t value)
|
||||
bool Multistate_Value_Present_Value_Set(uint32_t object_instance,
|
||||
uint32_t value)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
@@ -185,7 +165,7 @@ bool Multistate_Value_Present_Value_Set(
|
||||
if (Present_Value[index] != (uint8_t)value) {
|
||||
Change_Of_Value[index] = true;
|
||||
}
|
||||
Present_Value[index] = (uint8_t) value;
|
||||
Present_Value[index] = (uint8_t)value;
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
@@ -193,8 +173,7 @@ bool Multistate_Value_Present_Value_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Multistate_Value_Out_Of_Service(
|
||||
uint32_t object_instance)
|
||||
bool Multistate_Value_Out_Of_Service(uint32_t object_instance)
|
||||
{
|
||||
bool value = false;
|
||||
unsigned index = 0;
|
||||
@@ -207,9 +186,7 @@ bool Multistate_Value_Out_Of_Service(
|
||||
return value;
|
||||
}
|
||||
|
||||
void Multistate_Value_Out_Of_Service_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
void Multistate_Value_Out_Of_Service_Set(uint32_t object_instance, bool value)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -224,8 +201,7 @@ void Multistate_Value_Out_Of_Service_Set(
|
||||
return;
|
||||
}
|
||||
|
||||
char *Multistate_Value_Description(
|
||||
uint32_t object_instance)
|
||||
char *Multistate_Value_Description(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
char *pName = NULL; /* return value */
|
||||
@@ -238,13 +214,11 @@ char *Multistate_Value_Description(
|
||||
return pName;
|
||||
}
|
||||
|
||||
bool Multistate_Value_Description_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name)
|
||||
bool Multistate_Value_Description_Set(uint32_t object_instance, char *new_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_MULTISTATE_VALUES) {
|
||||
@@ -266,9 +240,8 @@ bool Multistate_Value_Description_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Multistate_Value_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Multistate_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
bool status = false;
|
||||
@@ -282,13 +255,11 @@ bool Multistate_Value_Object_Name(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Multistate_Value_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name)
|
||||
bool Multistate_Value_Name_Set(uint32_t object_instance, char *new_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_MULTISTATE_VALUES) {
|
||||
@@ -311,9 +282,8 @@ bool Multistate_Value_Name_Set(
|
||||
return status;
|
||||
}
|
||||
|
||||
char *Multistate_Value_State_Text(
|
||||
uint32_t object_instance,
|
||||
uint32_t state_index)
|
||||
char *Multistate_Value_State_Text(uint32_t object_instance,
|
||||
uint32_t state_index)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
char *pName = NULL; /* return value */
|
||||
@@ -329,14 +299,12 @@ char *Multistate_Value_State_Text(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Multistate_Value_State_Text_Set(
|
||||
uint32_t object_instance,
|
||||
uint32_t state_index,
|
||||
char *new_name)
|
||||
bool Multistate_Value_State_Text_Set(uint32_t object_instance,
|
||||
uint32_t state_index, char *new_name)
|
||||
{
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
unsigned index = 0; /* offset from instance lookup */
|
||||
size_t i = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
|
||||
index = Multistate_Value_Instance_To_Index(object_instance);
|
||||
if ((index < MAX_MULTISTATE_VALUES) && (state_index > 0) &&
|
||||
@@ -357,11 +325,11 @@ bool Multistate_Value_State_Text_Set(
|
||||
}
|
||||
}
|
||||
|
||||
return status;;
|
||||
return status;
|
||||
;
|
||||
}
|
||||
|
||||
bool Multistate_Value_Change_Of_Value(
|
||||
uint32_t object_instance)
|
||||
bool Multistate_Value_Change_Of_Value(uint32_t object_instance)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index;
|
||||
@@ -374,8 +342,7 @@ bool Multistate_Value_Change_Of_Value(
|
||||
return status;
|
||||
}
|
||||
|
||||
void Multistate_Value_Change_Of_Value_Clear(
|
||||
uint32_t object_instance)
|
||||
void Multistate_Value_Change_Of_Value_Clear(uint32_t object_instance)
|
||||
{
|
||||
unsigned index;
|
||||
|
||||
@@ -395,9 +362,8 @@ void Multistate_Value_Change_Of_Value_Clear(
|
||||
*
|
||||
* @return true if the value list is encoded
|
||||
*/
|
||||
bool Multistate_Value_Encode_Value_List(
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list)
|
||||
bool Multistate_Value_Encode_Value_List(uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE *value_list)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
@@ -420,17 +386,17 @@ bool Multistate_Value_Encode_Value_List(
|
||||
value_list->value.next = NULL;
|
||||
bitstring_init(&value_list->value.type.Bit_String);
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_IN_ALARM, false);
|
||||
STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String, STATUS_FLAG_FAULT,
|
||||
false);
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_OVERRIDDEN, false);
|
||||
STATUS_FLAG_OVERRIDDEN, false);
|
||||
if (Multistate_Value_Out_Of_Service(object_instance)) {
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_OUT_OF_SERVICE, true);
|
||||
STATUS_FLAG_OUT_OF_SERVICE, true);
|
||||
} else {
|
||||
bitstring_set_bit(&value_list->value.type.Bit_String,
|
||||
STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
}
|
||||
value_list->priority = BACNET_NO_PRIORITY;
|
||||
value_list->next = NULL;
|
||||
@@ -440,14 +406,11 @@ bool Multistate_Value_Encode_Value_List(
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Multistate_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Multistate_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint32_t present_value = 0;
|
||||
@@ -462,28 +425,26 @@ int Multistate_Value_Read_Property(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_MULTI_STATE_VALUE, rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_MULTI_STATE_VALUE, rpdata->object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
Multistate_Value_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
Multistate_Value_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
characterstring_init_ansi(
|
||||
&char_string,
|
||||
Multistate_Value_Description(rpdata->object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_MULTI_STATE_VALUE);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_MULTI_STATE_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
@@ -510,27 +471,25 @@ int Multistate_Value_Read_Property(
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_NUMBER_OF_STATES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
MULTISTATE_NUMBER_OF_STATES);
|
||||
apdu_len = encode_application_unsigned(&apdu[apdu_len],
|
||||
MULTISTATE_NUMBER_OF_STATES);
|
||||
break;
|
||||
case PROP_STATE_TEXT:
|
||||
if (rpdata->array_index == 0) {
|
||||
/* Array element zero is the number of elements in the array */
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
MULTISTATE_NUMBER_OF_STATES);
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0], MULTISTATE_NUMBER_OF_STATES);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* if no index was specified, then try to encode the entire list
|
||||
*/
|
||||
/* into one packet. */
|
||||
for (i = 1; i <= MULTISTATE_NUMBER_OF_STATES; i++) {
|
||||
characterstring_init_ansi(&char_string,
|
||||
Multistate_Value_State_Text(rpdata->object_instance,
|
||||
i));
|
||||
Multistate_Value_State_Text(
|
||||
rpdata->object_instance, i));
|
||||
/* FIXME: this might go beyond MAX_APDU length! */
|
||||
len =
|
||||
encode_application_character_string(&apdu[apdu_len],
|
||||
&char_string);
|
||||
len = encode_application_character_string(&apdu[apdu_len],
|
||||
&char_string);
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU) {
|
||||
apdu_len += len;
|
||||
@@ -543,12 +502,12 @@ int Multistate_Value_Read_Property(
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <= MULTISTATE_NUMBER_OF_STATES) {
|
||||
characterstring_init_ansi(&char_string,
|
||||
characterstring_init_ansi(
|
||||
&char_string,
|
||||
Multistate_Value_State_Text(rpdata->object_instance,
|
||||
rpdata->array_index));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0],
|
||||
&char_string);
|
||||
rpdata->array_index));
|
||||
apdu_len = encode_application_character_string(
|
||||
&apdu[0], &char_string);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
@@ -575,17 +534,15 @@ int Multistate_Value_Read_Property(
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Multistate_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Multistate_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
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);
|
||||
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 */
|
||||
@@ -605,11 +562,10 @@ bool Multistate_Value_Write_Property(
|
||||
case PROP_PRESENT_VALUE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
status =
|
||||
Multistate_Value_Present_Value_Set
|
||||
(wp_data->object_instance, value.type.Unsigned_Int);
|
||||
status = Multistate_Value_Present_Value_Set(
|
||||
wp_data->object_instance, value.type.Unsigned_Int);
|
||||
if (!status) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
@@ -619,10 +575,10 @@ bool Multistate_Value_Write_Property(
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Multistate_Value_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -645,17 +601,14 @@ bool Multistate_Value_Write_Property(
|
||||
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)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -665,10 +618,9 @@ bool WPValidateArgType(
|
||||
return false;
|
||||
}
|
||||
|
||||
void testMultistateInput(
|
||||
Test * pTest)
|
||||
void testMultistateInput(Test *pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -695,8 +647,7 @@ void testMultistateInput(
|
||||
}
|
||||
|
||||
#ifdef TEST_MULTISTATE_VALUE
|
||||
int main(
|
||||
void)
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
@@ -708,7 +659,7 @@ int main(
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+243
-272
@@ -1,32 +1,32 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2011 Krzysztof Malorny <malornykrzysztof@gmail.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.
|
||||
*
|
||||
* Additional changes, Copyright (c) 2018 Ed Hague <edward@bac-test.com>
|
||||
*
|
||||
* 2018.06.17 - Attempting to write to Object_Name returned UNKNOWN_PROPERTY.
|
||||
* Now returns WRITE_ACCESS_DENIED
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2011 Krzysztof Malorny <malornykrzysztof@gmail.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.
|
||||
*
|
||||
* Additional changes, Copyright (c) 2018 Ed Hague <edward@bac-test.com>
|
||||
*
|
||||
* 2018.06.17 - Attempting to write to Object_Name returned
|
||||
*UNKNOWN_PROPERTY. Now returns WRITE_ACCESS_DENIED
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -47,40 +47,27 @@
|
||||
#include "wp.h"
|
||||
#include "nc.h"
|
||||
|
||||
|
||||
#ifndef MAX_NOTIFICATION_CLASSES
|
||||
#define MAX_NOTIFICATION_CLASSES 2
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(INTRINSIC_REPORTING)
|
||||
static NOTIFICATION_CLASS_INFO NC_Info[MAX_NOTIFICATION_CLASSES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Notification_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_NOTIFICATION_CLASS,
|
||||
PROP_PRIORITY,
|
||||
PROP_ACK_REQUIRED,
|
||||
PROP_RECIPIENT_LIST,
|
||||
-1
|
||||
};
|
||||
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE, PROP_NOTIFICATION_CLASS,
|
||||
PROP_PRIORITY, PROP_ACK_REQUIRED,
|
||||
PROP_RECIPIENT_LIST, -1};
|
||||
|
||||
static const int Notification_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
static const int Notification_Properties_Optional[] = {PROP_DESCRIPTION, -1};
|
||||
|
||||
static const int Notification_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Notification_Properties_Proprietary[] = {-1};
|
||||
|
||||
void Notification_Class_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Notification_Class_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Notification_Properties_Required;
|
||||
@@ -91,8 +78,7 @@ void Notification_Class_Property_Lists(
|
||||
return;
|
||||
}
|
||||
|
||||
void Notification_Class_Init(
|
||||
void)
|
||||
void Notification_Class_Init(void)
|
||||
{
|
||||
uint8_t NotifyIdx = 0;
|
||||
|
||||
@@ -101,20 +87,21 @@ void Notification_Class_Init(
|
||||
memset(&NC_Info[NotifyIdx], 0x00, sizeof(NOTIFICATION_CLASS_INFO));
|
||||
/* set the basic parameters */
|
||||
NC_Info[NotifyIdx].Ack_Required = 0;
|
||||
NC_Info[NotifyIdx].Priority[TRANSITION_TO_OFFNORMAL] = 255; /* The lowest priority for Normal message. */
|
||||
NC_Info[NotifyIdx].Priority[TRANSITION_TO_FAULT] = 255; /* The lowest priority for Normal message. */
|
||||
NC_Info[NotifyIdx].Priority[TRANSITION_TO_NORMAL] = 255; /* The lowest priority for Normal message. */
|
||||
NC_Info[NotifyIdx].Priority[TRANSITION_TO_OFFNORMAL] =
|
||||
255; /* The lowest priority for Normal message. */
|
||||
NC_Info[NotifyIdx].Priority[TRANSITION_TO_FAULT] =
|
||||
255; /* The lowest priority for Normal message. */
|
||||
NC_Info[NotifyIdx].Priority[TRANSITION_TO_NORMAL] =
|
||||
255; /* The lowest priority for Normal message. */
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Notification_Class_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
bool Notification_Class_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
@@ -127,8 +114,7 @@ bool Notification_Class_Valid_Instance(
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Notification_Class_Count(
|
||||
void)
|
||||
unsigned Notification_Class_Count(void)
|
||||
{
|
||||
return MAX_NOTIFICATION_CLASSES;
|
||||
}
|
||||
@@ -136,8 +122,7 @@ unsigned Notification_Class_Count(
|
||||
/* 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 Notification_Class_Index_To_Instance(
|
||||
unsigned index)
|
||||
uint32_t Notification_Class_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
@@ -145,8 +130,7 @@ uint32_t Notification_Class_Index_To_Instance(
|
||||
/* 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 Notification_Class_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
unsigned Notification_Class_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_NOTIFICATION_CLASSES;
|
||||
|
||||
@@ -156,27 +140,23 @@ unsigned Notification_Class_Instance_To_Index(
|
||||
return index;
|
||||
}
|
||||
|
||||
bool Notification_Class_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
bool Notification_Class_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
unsigned int index;
|
||||
bool status = false;
|
||||
|
||||
index = Notification_Class_Instance_To_Index(object_instance);
|
||||
if (index < MAX_NOTIFICATION_CLASSES) {
|
||||
sprintf(text_string, "NOTIFICATION CLASS %lu", (unsigned long) index);
|
||||
sprintf(text_string, "NOTIFICATION CLASS %lu", (unsigned long)index);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int Notification_Class_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Notification_Class_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
NOTIFICATION_CLASS_INFO *CurrentNotify;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
@@ -185,8 +165,7 @@ int Notification_Class_Read_Property(
|
||||
uint8_t *apdu = NULL;
|
||||
uint8_t u8Val;
|
||||
int idx;
|
||||
int apdu_len = 0; /* return value */
|
||||
|
||||
int apdu_len = 0; /* return value */
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
@@ -195,28 +174,25 @@ int Notification_Class_Read_Property(
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
CurrentNotify =
|
||||
&NC_Info[Notification_Class_Instance_To_Index(rpdata->
|
||||
object_instance)];
|
||||
&NC_Info[Notification_Class_Instance_To_Index(rpdata->object_instance)];
|
||||
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_NOTIFICATION_CLASS, rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_NOTIFICATION_CLASS, rpdata->object_instance);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
Notification_Class_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
&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_NOTIFICATION_CLASS);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_NOTIFICATION_CLASS);
|
||||
break;
|
||||
|
||||
case PROP_NOTIFICATION_CLASS:
|
||||
@@ -229,18 +205,18 @@ int Notification_Class_Read_Property(
|
||||
apdu_len += encode_application_unsigned(&apdu[0], 3);
|
||||
else {
|
||||
if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
apdu_len +=
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
apdu_len += encode_application_unsigned(
|
||||
&apdu[apdu_len],
|
||||
CurrentNotify->Priority[TRANSITION_TO_OFFNORMAL]);
|
||||
apdu_len +=
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
apdu_len += encode_application_unsigned(
|
||||
&apdu[apdu_len],
|
||||
CurrentNotify->Priority[TRANSITION_TO_FAULT]);
|
||||
apdu_len +=
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
apdu_len += encode_application_unsigned(
|
||||
&apdu[apdu_len],
|
||||
CurrentNotify->Priority[TRANSITION_TO_NORMAL]);
|
||||
} else if (rpdata->array_index <= MAX_BACNET_EVENT_TRANSITION) {
|
||||
apdu_len +=
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
apdu_len += encode_application_unsigned(
|
||||
&apdu[apdu_len],
|
||||
CurrentNotify->Priority[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -254,11 +230,14 @@ int Notification_Class_Read_Property(
|
||||
u8Val = CurrentNotify->Ack_Required;
|
||||
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL,
|
||||
bitstring_set_bit(
|
||||
&bit_string, TRANSITION_TO_OFFNORMAL,
|
||||
(u8Val & TRANSITION_TO_OFFNORMAL_MASKED) ? true : false);
|
||||
bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT,
|
||||
bitstring_set_bit(
|
||||
&bit_string, TRANSITION_TO_FAULT,
|
||||
(u8Val & TRANSITION_TO_FAULT_MASKED) ? true : false);
|
||||
bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL,
|
||||
bitstring_set_bit(
|
||||
&bit_string, TRANSITION_TO_NORMAL,
|
||||
(u8Val & TRANSITION_TO_NORMAL_MASKED) ? true : false);
|
||||
/* encode bitstring */
|
||||
apdu_len +=
|
||||
@@ -271,11 +250,13 @@ int Notification_Class_Read_Property(
|
||||
BACNET_DESTINATION *RecipientEntry;
|
||||
int i = 0;
|
||||
|
||||
/* get pointer of current element for Recipient_List - easier for use */
|
||||
/* get pointer of current element for Recipient_List - easier
|
||||
* for use */
|
||||
RecipientEntry = &CurrentNotify->Recipient_List[idx];
|
||||
if (RecipientEntry->Recipient.RecipientType !=
|
||||
RECIPIENT_TYPE_NOTINITIALIZED) {
|
||||
/* Valid Days - BACnetDaysOfWeek - [bitstring] monday-sunday */
|
||||
/* Valid Days - BACnetDaysOfWeek - [bitstring] monday-sunday
|
||||
*/
|
||||
u8Val = 0x01;
|
||||
bitstring_init(&bit_string);
|
||||
|
||||
@@ -284,21 +265,18 @@ int Notification_Class_Read_Property(
|
||||
bitstring_set_bit(&bit_string, i, true);
|
||||
else
|
||||
bitstring_set_bit(&bit_string, i, false);
|
||||
u8Val <<= 1; /* next day */
|
||||
u8Val <<= 1; /* next day */
|
||||
}
|
||||
apdu_len +=
|
||||
encode_application_bitstring(&apdu[apdu_len],
|
||||
&bit_string);
|
||||
apdu_len += encode_application_bitstring(&apdu[apdu_len],
|
||||
&bit_string);
|
||||
|
||||
/* From Time */
|
||||
apdu_len +=
|
||||
encode_application_time(&apdu[apdu_len],
|
||||
&RecipientEntry->FromTime);
|
||||
apdu_len += encode_application_time(
|
||||
&apdu[apdu_len], &RecipientEntry->FromTime);
|
||||
|
||||
/* To Time */
|
||||
apdu_len +=
|
||||
encode_application_time(&apdu[apdu_len],
|
||||
&RecipientEntry->ToTime);
|
||||
apdu_len += encode_application_time(
|
||||
&apdu[apdu_len], &RecipientEntry->ToTime);
|
||||
|
||||
/*
|
||||
BACnetRecipient ::= CHOICE {
|
||||
@@ -309,66 +287,67 @@ int Notification_Class_Read_Property(
|
||||
/* CHOICE - device [0] BACnetObjectIdentifier */
|
||||
if (RecipientEntry->Recipient.RecipientType ==
|
||||
RECIPIENT_TYPE_DEVICE) {
|
||||
apdu_len +=
|
||||
encode_context_object_id(&apdu[apdu_len], 0,
|
||||
OBJECT_DEVICE,
|
||||
apdu_len += encode_context_object_id(
|
||||
&apdu[apdu_len], 0, OBJECT_DEVICE,
|
||||
RecipientEntry->Recipient._.DeviceIdentifier);
|
||||
}
|
||||
/* CHOICE - address [1] BACnetAddress */
|
||||
else if (RecipientEntry->Recipient.RecipientType ==
|
||||
RECIPIENT_TYPE_ADDRESS) {
|
||||
RECIPIENT_TYPE_ADDRESS) {
|
||||
/* opening tag 1 */
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 1);
|
||||
/* network-number Unsigned16, */
|
||||
apdu_len +=
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
apdu_len += encode_application_unsigned(
|
||||
&apdu[apdu_len],
|
||||
RecipientEntry->Recipient._.Address.net);
|
||||
|
||||
/* mac-address OCTET STRING */
|
||||
if (RecipientEntry->Recipient._.Address.net) {
|
||||
octetstring_init(&octet_string,
|
||||
octetstring_init(
|
||||
&octet_string,
|
||||
RecipientEntry->Recipient._.Address.adr,
|
||||
RecipientEntry->Recipient._.Address.len);
|
||||
} else {
|
||||
octetstring_init(&octet_string,
|
||||
octetstring_init(
|
||||
&octet_string,
|
||||
RecipientEntry->Recipient._.Address.mac,
|
||||
RecipientEntry->Recipient._.Address.mac_len);
|
||||
}
|
||||
apdu_len +=
|
||||
encode_application_octet_string(&apdu[apdu_len],
|
||||
&octet_string);
|
||||
apdu_len += encode_application_octet_string(
|
||||
&apdu[apdu_len], &octet_string);
|
||||
|
||||
/* closing tag 1 */
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 1);
|
||||
|
||||
} else {;
|
||||
} /* shouldn't happen */
|
||||
} else {
|
||||
;
|
||||
} /* shouldn't happen */
|
||||
|
||||
/* Process Identifier - Unsigned32 */
|
||||
apdu_len +=
|
||||
encode_application_unsigned(&apdu[apdu_len],
|
||||
RecipientEntry->ProcessIdentifier);
|
||||
apdu_len += encode_application_unsigned(
|
||||
&apdu[apdu_len], RecipientEntry->ProcessIdentifier);
|
||||
|
||||
/* Issue Confirmed Notifications - boolean */
|
||||
apdu_len +=
|
||||
encode_application_boolean(&apdu[apdu_len],
|
||||
RecipientEntry->ConfirmedNotify);
|
||||
apdu_len += encode_application_boolean(
|
||||
&apdu[apdu_len], RecipientEntry->ConfirmedNotify);
|
||||
|
||||
/* Transitions - BACnet Event Transition Bits [bitstring] */
|
||||
u8Val = RecipientEntry->Transitions;
|
||||
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL,
|
||||
(u8Val & TRANSITION_TO_OFFNORMAL_MASKED) ? true :
|
||||
false);
|
||||
bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT,
|
||||
(u8Val & TRANSITION_TO_OFFNORMAL_MASKED)
|
||||
? true
|
||||
: false);
|
||||
bitstring_set_bit(
|
||||
&bit_string, TRANSITION_TO_FAULT,
|
||||
(u8Val & TRANSITION_TO_FAULT_MASKED) ? true : false);
|
||||
bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL,
|
||||
bitstring_set_bit(
|
||||
&bit_string, TRANSITION_TO_NORMAL,
|
||||
(u8Val & TRANSITION_TO_NORMAL_MASKED) ? true : false);
|
||||
|
||||
apdu_len +=
|
||||
encode_application_bitstring(&apdu[apdu_len],
|
||||
&bit_string);
|
||||
apdu_len += encode_application_bitstring(&apdu[apdu_len],
|
||||
&bit_string);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -391,29 +370,24 @@ int Notification_Class_Read_Property(
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
|
||||
bool Notification_Class_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Notification_Class_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
NOTIFICATION_CLASS_INFO *CurrentNotify;
|
||||
NOTIFICATION_CLASS_INFO TmpNotify;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
uint8_t TmpPriority[MAX_BACNET_EVENT_TRANSITION]; /* BACnetARRAY[3] of Unsigned */
|
||||
uint8_t TmpPriority[MAX_BACNET_EVENT_TRANSITION]; /* BACnetARRAY[3] of
|
||||
Unsigned */
|
||||
bool status = false;
|
||||
int iOffset;
|
||||
uint8_t idx;
|
||||
int len = 0;
|
||||
|
||||
|
||||
|
||||
CurrentNotify =
|
||||
&NC_Info[Notification_Class_Instance_To_Index(wp_data->
|
||||
object_instance)];
|
||||
CurrentNotify = &NC_Info[Notification_Class_Instance_To_Index(
|
||||
wp_data->object_instance)];
|
||||
|
||||
/* decode some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
len = bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -431,7 +405,7 @@ bool Notification_Class_Write_Property(
|
||||
case PROP_PRIORITY:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
|
||||
if (status) {
|
||||
if (wp_data->array_index == 0) {
|
||||
@@ -440,16 +414,15 @@ bool Notification_Class_Write_Property(
|
||||
status = false;
|
||||
} else if (wp_data->array_index == BACNET_ARRAY_ALL) {
|
||||
iOffset = 0;
|
||||
for (idx = 0; idx < MAX_BACNET_EVENT_TRANSITION; idx++)
|
||||
{
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset], wp_data->application_data_len,
|
||||
&value);
|
||||
for (idx = 0; idx < MAX_BACNET_EVENT_TRANSITION; idx++) {
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
if ((len == 0) ||
|
||||
(value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT))
|
||||
{
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
(value.tag !=
|
||||
BACNET_APPLICATION_TAG_UNSIGNED_INT)) {
|
||||
/* Bad decode, wrong tag or following required
|
||||
* parameter missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
status = false;
|
||||
@@ -461,22 +434,21 @@ bool Notification_Class_Write_Property(
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
TmpPriority[idx] = (uint8_t) value.type.Unsigned_Int;
|
||||
TmpPriority[idx] = (uint8_t)value.type.Unsigned_Int;
|
||||
iOffset += len;
|
||||
}
|
||||
if (status == true) {
|
||||
for (idx = 0; idx < MAX_BACNET_EVENT_TRANSITION; idx++)
|
||||
CurrentNotify->Priority[idx] = TmpPriority[idx];
|
||||
CurrentNotify->Priority[idx] = TmpPriority[idx];
|
||||
}
|
||||
} else if (wp_data->array_index <= 3) {
|
||||
if (value.type.Unsigned_Int > 255) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
status = false;
|
||||
}
|
||||
else
|
||||
CurrentNotify->Priority[wp_data->array_index - 1] =
|
||||
value.type.Unsigned_Int;
|
||||
} else
|
||||
CurrentNotify->Priority[wp_data->array_index - 1] =
|
||||
value.type.Unsigned_Int;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
@@ -488,7 +460,7 @@ bool Notification_Class_Write_Property(
|
||||
case PROP_ACK_REQUIRED:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BIT_STRING,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
|
||||
if (status) {
|
||||
if (value.type.Bit_String.bits_used == 3) {
|
||||
@@ -509,14 +481,14 @@ bool Notification_Class_Write_Property(
|
||||
/* decode all packed */
|
||||
while (iOffset < wp_data->application_data_len) {
|
||||
/* Decode Valid Days */
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset], wp_data->application_data_len,
|
||||
&value);
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
|
||||
if ((len == 0) ||
|
||||
(value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
@@ -534,13 +506,13 @@ bool Notification_Class_Write_Property(
|
||||
|
||||
iOffset += len;
|
||||
/* Decode From Time */
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset], wp_data->application_data_len,
|
||||
&value);
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
|
||||
if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_TIME)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
@@ -550,13 +522,13 @@ bool Notification_Class_Write_Property(
|
||||
|
||||
iOffset += len;
|
||||
/* Decode To Time */
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset], wp_data->application_data_len,
|
||||
&value);
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
|
||||
if ((len == 0) || (value.tag != BACNET_APPLICATION_TAG_TIME)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
@@ -567,44 +539,44 @@ bool Notification_Class_Write_Property(
|
||||
iOffset += len;
|
||||
/* context tag [0] - Device */
|
||||
if (decode_is_context_tag(&wp_data->application_data[iOffset],
|
||||
0)) {
|
||||
0)) {
|
||||
TmpNotify.Recipient_List[idx].Recipient.RecipientType =
|
||||
RECIPIENT_TYPE_DEVICE;
|
||||
/* Decode Network Number */
|
||||
len =
|
||||
bacapp_decode_context_data(&wp_data->
|
||||
application_data[iOffset],
|
||||
len = bacapp_decode_context_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value,
|
||||
PROP_RECIPIENT_LIST);
|
||||
|
||||
if ((len == 0) ||
|
||||
(value.tag != BACNET_APPLICATION_TAG_OBJECT_ID)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
}
|
||||
/* store value */
|
||||
TmpNotify.Recipient_List[idx].Recipient._.
|
||||
DeviceIdentifier = value.type.Object_Id.instance;
|
||||
TmpNotify.Recipient_List[idx].Recipient._.DeviceIdentifier =
|
||||
value.type.Object_Id.instance;
|
||||
|
||||
iOffset += len;
|
||||
}
|
||||
/* opening tag [1] - Recipient */
|
||||
else if (decode_is_opening_tag_number(&wp_data->
|
||||
application_data[iOffset], 1)) {
|
||||
else if (decode_is_opening_tag_number(
|
||||
&wp_data->application_data[iOffset], 1)) {
|
||||
iOffset++;
|
||||
TmpNotify.Recipient_List[idx].Recipient.RecipientType =
|
||||
RECIPIENT_TYPE_ADDRESS;
|
||||
/* Decode Network Number */
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset],
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
|
||||
if ((len == 0) ||
|
||||
(value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
@@ -615,61 +587,66 @@ bool Notification_Class_Write_Property(
|
||||
|
||||
iOffset += len;
|
||||
/* Decode Address */
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset],
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
|
||||
if ((len == 0) ||
|
||||
(value.tag != BACNET_APPLICATION_TAG_OCTET_STRING)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
}
|
||||
/* store value */
|
||||
if (TmpNotify.Recipient_List[idx].Recipient._.Address.
|
||||
net == 0) {
|
||||
memcpy(TmpNotify.Recipient_List[idx].Recipient._.
|
||||
Address.mac, value.type.Octet_String.value,
|
||||
value.type.Octet_String.length);
|
||||
TmpNotify.Recipient_List[idx].Recipient._.Address.
|
||||
mac_len = value.type.Octet_String.length;
|
||||
if (TmpNotify.Recipient_List[idx].Recipient._.Address.net ==
|
||||
0) {
|
||||
memcpy(TmpNotify.Recipient_List[idx]
|
||||
.Recipient._.Address.mac,
|
||||
value.type.Octet_String.value,
|
||||
value.type.Octet_String.length);
|
||||
TmpNotify.Recipient_List[idx]
|
||||
.Recipient._.Address.mac_len =
|
||||
value.type.Octet_String.length;
|
||||
} else {
|
||||
memcpy(TmpNotify.Recipient_List[idx].Recipient._.
|
||||
Address.adr, value.type.Octet_String.value,
|
||||
value.type.Octet_String.length);
|
||||
memcpy(TmpNotify.Recipient_List[idx]
|
||||
.Recipient._.Address.adr,
|
||||
value.type.Octet_String.value,
|
||||
value.type.Octet_String.length);
|
||||
TmpNotify.Recipient_List[idx].Recipient._.Address.len =
|
||||
value.type.Octet_String.length;
|
||||
}
|
||||
|
||||
iOffset += len;
|
||||
/* closing tag [1] - Recipient */
|
||||
if (decode_is_closing_tag_number(&wp_data->
|
||||
application_data[iOffset], 1))
|
||||
if (decode_is_closing_tag_number(
|
||||
&wp_data->application_data[iOffset], 1))
|
||||
iOffset++;
|
||||
else {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Process Identifier */
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset], wp_data->application_data_len,
|
||||
&value);
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
|
||||
if ((len == 0) ||
|
||||
(value.tag != BACNET_APPLICATION_TAG_UNSIGNED_INT)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
@@ -680,14 +657,14 @@ bool Notification_Class_Write_Property(
|
||||
|
||||
iOffset += len;
|
||||
/* Issue Confirmed Notifications */
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset], wp_data->application_data_len,
|
||||
&value);
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
|
||||
if ((len == 0) ||
|
||||
(value.tag != BACNET_APPLICATION_TAG_BOOLEAN)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
@@ -698,14 +675,14 @@ bool Notification_Class_Write_Property(
|
||||
|
||||
iOffset += len;
|
||||
/* Transitions */
|
||||
len =
|
||||
bacapp_decode_application_data(&wp_data->
|
||||
application_data[iOffset], wp_data->application_data_len,
|
||||
&value);
|
||||
len = bacapp_decode_application_data(
|
||||
&wp_data->application_data[iOffset],
|
||||
wp_data->application_data_len, &value);
|
||||
|
||||
if ((len == 0) ||
|
||||
(value.tag != BACNET_APPLICATION_TAG_BIT_STRING)) {
|
||||
/* Bad decode, wrong tag or following required parameter missing */
|
||||
/* Bad decode, wrong tag or following required parameter
|
||||
* missing */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
return false;
|
||||
@@ -726,8 +703,7 @@ bool Notification_Class_Write_Property(
|
||||
/* Increasing element of list */
|
||||
if (++idx >= NC_MAX_RECIPIENTS) {
|
||||
wp_data->error_class = ERROR_CLASS_RESOURCES;
|
||||
wp_data->error_code =
|
||||
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -735,26 +711,29 @@ bool Notification_Class_Write_Property(
|
||||
/* Decoded all recipient list */
|
||||
/* copy elements from temporary object */
|
||||
for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++) {
|
||||
BACNET_ADDRESS src = { 0 };
|
||||
BACNET_ADDRESS src = {0};
|
||||
unsigned max_apdu = 0;
|
||||
int32_t DeviceID;
|
||||
|
||||
CurrentNotify->Recipient_List[idx] =
|
||||
TmpNotify.Recipient_List[idx];
|
||||
|
||||
if (CurrentNotify->Recipient_List[idx].Recipient.
|
||||
RecipientType == RECIPIENT_TYPE_DEVICE) {
|
||||
if (CurrentNotify->Recipient_List[idx]
|
||||
.Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) {
|
||||
/* copy Device_ID */
|
||||
DeviceID =
|
||||
CurrentNotify->Recipient_List[idx].Recipient._.
|
||||
DeviceIdentifier;
|
||||
DeviceID = CurrentNotify->Recipient_List[idx]
|
||||
.Recipient._.DeviceIdentifier;
|
||||
address_bind_request(DeviceID, &max_apdu, &src);
|
||||
|
||||
} else if (CurrentNotify->Recipient_List[idx].Recipient.
|
||||
RecipientType == RECIPIENT_TYPE_ADDRESS) {
|
||||
} else if (CurrentNotify->Recipient_List[idx]
|
||||
.Recipient.RecipientType ==
|
||||
RECIPIENT_TYPE_ADDRESS) {
|
||||
/* copy Address */
|
||||
/* src = CurrentNotify->Recipient_List[idx].Recipient._.Address; */
|
||||
/* address_bind_request(BACNET_MAX_INSTANCE, &max_apdu, &src); */
|
||||
/* src =
|
||||
* CurrentNotify->Recipient_List[idx].Recipient._.Address;
|
||||
*/
|
||||
/* address_bind_request(BACNET_MAX_INSTANCE, &max_apdu,
|
||||
* &src); */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,10 +753,8 @@ bool Notification_Class_Write_Property(
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void Notification_Class_Get_Priorities(
|
||||
uint32_t Object_Instance,
|
||||
uint32_t * pPriorityArray)
|
||||
void Notification_Class_Get_Priorities(uint32_t Object_Instance,
|
||||
uint32_t *pPriorityArray)
|
||||
{
|
||||
NOTIFICATION_CLASS_INFO *CurrentNotify;
|
||||
uint32_t object_index;
|
||||
@@ -797,10 +774,8 @@ void Notification_Class_Get_Priorities(
|
||||
pPriorityArray[i] = CurrentNotify->Priority[i];
|
||||
}
|
||||
|
||||
|
||||
static bool IsRecipientActive(
|
||||
BACNET_DESTINATION * pBacDest,
|
||||
uint8_t EventToState)
|
||||
static bool IsRecipientActive(BACNET_DESTINATION *pBacDest,
|
||||
uint8_t EventToState)
|
||||
{
|
||||
BACNET_DATE_TIME DateTime;
|
||||
|
||||
@@ -824,7 +799,7 @@ static bool IsRecipientActive(
|
||||
break;
|
||||
|
||||
default:
|
||||
return false; /* shouldn't happen */
|
||||
return false; /* shouldn't happen */
|
||||
}
|
||||
|
||||
/* get actual date and time */
|
||||
@@ -845,9 +820,8 @@ static bool IsRecipientActive(
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Notification_Class_common_reporting_function(
|
||||
BACNET_EVENT_NOTIFICATION_DATA * event_data)
|
||||
BACNET_EVENT_NOTIFICATION_DATA *event_data)
|
||||
{
|
||||
/* Fill the parameters common for all types of events. */
|
||||
|
||||
@@ -856,7 +830,6 @@ void Notification_Class_common_reporting_function(
|
||||
uint32_t notify_index;
|
||||
uint8_t index;
|
||||
|
||||
|
||||
notify_index =
|
||||
Notification_Class_Instance_To_Index(event_data->notificationClass);
|
||||
|
||||
@@ -865,7 +838,6 @@ void Notification_Class_common_reporting_function(
|
||||
else
|
||||
return;
|
||||
|
||||
|
||||
/* Initiating Device Identifier */
|
||||
event_data->initiatingObjectIdentifier.type = OBJECT_DEVICE;
|
||||
event_data->initiatingObjectIdentifier.instance =
|
||||
@@ -877,16 +849,17 @@ void Notification_Class_common_reporting_function(
|
||||
event_data->priority =
|
||||
CurrentNotify->Priority[TRANSITION_TO_NORMAL];
|
||||
event_data->ackRequired =
|
||||
(CurrentNotify->
|
||||
Ack_Required & TRANSITION_TO_NORMAL_MASKED) ? true : false;
|
||||
(CurrentNotify->Ack_Required & TRANSITION_TO_NORMAL_MASKED)
|
||||
? true
|
||||
: false;
|
||||
break;
|
||||
|
||||
case EVENT_STATE_FAULT:
|
||||
event_data->priority =
|
||||
CurrentNotify->Priority[TRANSITION_TO_FAULT];
|
||||
event_data->priority = CurrentNotify->Priority[TRANSITION_TO_FAULT];
|
||||
event_data->ackRequired =
|
||||
(CurrentNotify->
|
||||
Ack_Required & TRANSITION_TO_FAULT_MASKED) ? true : false;
|
||||
(CurrentNotify->Ack_Required & TRANSITION_TO_FAULT_MASKED)
|
||||
? true
|
||||
: false;
|
||||
break;
|
||||
|
||||
case EVENT_STATE_OFFNORMAL:
|
||||
@@ -896,10 +869,11 @@ void Notification_Class_common_reporting_function(
|
||||
CurrentNotify->Priority[TRANSITION_TO_OFFNORMAL];
|
||||
event_data->ackRequired =
|
||||
(CurrentNotify->Ack_Required & TRANSITION_TO_OFFNORMAL_MASKED)
|
||||
? true : false;
|
||||
? true
|
||||
: false;
|
||||
break;
|
||||
|
||||
default: /* shouldn't happen */
|
||||
default: /* shouldn't happen */
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -909,7 +883,7 @@ void Notification_Class_common_reporting_function(
|
||||
for (index = 0; index < NC_MAX_RECIPIENTS; index++, pBacDest++) {
|
||||
/* check if recipient is defined */
|
||||
if (pBacDest->Recipient.RecipientType == RECIPIENT_TYPE_NOTINITIALIZED)
|
||||
break; /* recipient doesn't defined - end of list */
|
||||
break; /* recipient doesn't defined - end of list */
|
||||
|
||||
if (IsRecipientActive(pBacDest, event_data->toState) == true) {
|
||||
BACNET_ADDRESS dest;
|
||||
@@ -928,9 +902,9 @@ void Notification_Class_common_reporting_function(
|
||||
Send_CEvent_Notify(device_id, event_data);
|
||||
else if (address_get_by_device(device_id, &max_apdu, &dest))
|
||||
Send_UEvent_Notify(Handler_Transmit_Buffer, event_data,
|
||||
&dest);
|
||||
&dest);
|
||||
} else if (pBacDest->Recipient.RecipientType ==
|
||||
RECIPIENT_TYPE_ADDRESS) {
|
||||
RECIPIENT_TYPE_ADDRESS) {
|
||||
/* send notification to the address indicated */
|
||||
if (pBacDest->ConfirmedNotify == true) {
|
||||
if (address_get_device_id(&dest, &device_id))
|
||||
@@ -938,7 +912,7 @@ void Notification_Class_common_reporting_function(
|
||||
} else {
|
||||
dest = pBacDest->Recipient._.Address;
|
||||
Send_UEvent_Notify(Handler_Transmit_Buffer, event_data,
|
||||
&dest);
|
||||
&dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -947,20 +921,18 @@ void Notification_Class_common_reporting_function(
|
||||
|
||||
/* This function tries to find the addresses of the defined devices. */
|
||||
/* It should be called periodically (example once per minute). */
|
||||
void Notification_Class_find_recipient(
|
||||
void)
|
||||
void Notification_Class_find_recipient(void)
|
||||
{
|
||||
NOTIFICATION_CLASS_INFO *CurrentNotify;
|
||||
BACNET_DESTINATION *pBacDest;
|
||||
BACNET_ADDRESS src = { 0 };
|
||||
BACNET_ADDRESS src = {0};
|
||||
unsigned max_apdu = 0;
|
||||
uint32_t notify_index;
|
||||
uint32_t DeviceID;
|
||||
uint8_t idx;
|
||||
|
||||
|
||||
for (notify_index = 0; notify_index < MAX_NOTIFICATION_CLASSES;
|
||||
notify_index++) {
|
||||
notify_index++) {
|
||||
/* pointer to current notification */
|
||||
CurrentNotify =
|
||||
&NC_Info[Notification_Class_Instance_To_Index(notify_index)];
|
||||
@@ -970,15 +942,14 @@ void Notification_Class_find_recipient(
|
||||
if (CurrentNotify->Recipient_List[idx].Recipient.RecipientType ==
|
||||
RECIPIENT_TYPE_DEVICE) {
|
||||
/* Device ID */
|
||||
DeviceID =
|
||||
CurrentNotify->Recipient_List[idx].Recipient._.
|
||||
DeviceIdentifier;
|
||||
/* Send who_ is request only when address of device is unknown. */
|
||||
DeviceID = CurrentNotify->Recipient_List[idx]
|
||||
.Recipient._.DeviceIdentifier;
|
||||
/* Send who_ is request only when address of device is unknown.
|
||||
*/
|
||||
if (!address_bind_request(DeviceID, &max_apdu, &src))
|
||||
Send_WhoIs(DeviceID, DeviceID);
|
||||
} else if (CurrentNotify->Recipient_List[idx].Recipient.
|
||||
RecipientType == RECIPIENT_TYPE_ADDRESS) {
|
||||
|
||||
} else if (CurrentNotify->Recipient_List[idx]
|
||||
.Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+239
-358
File diff suppressed because it is too large
Load Diff
+57
-75
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* OctetString Value Objects - customize for your use */
|
||||
|
||||
@@ -35,12 +35,11 @@
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "osv.h"
|
||||
|
||||
|
||||
#ifndef MAX_OCTETSTRING_VALUES
|
||||
#define MAX_OCTETSTRING_VALUES 4
|
||||
#endif
|
||||
@@ -49,28 +48,17 @@ OCTETSTRING_VALUE_DESCR AV_Descr[MAX_OCTETSTRING_VALUES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int OctetString_Value_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
-1
|
||||
};
|
||||
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, -1};
|
||||
|
||||
static const int OctetString_Value_Properties_Optional[] = {
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
PROP_EVENT_STATE, PROP_OUT_OF_SERVICE, PROP_DESCRIPTION, -1};
|
||||
|
||||
static const int OctetString_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int OctetString_Value_Properties_Proprietary[] = {-1};
|
||||
|
||||
void OctetString_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = OctetString_Value_Properties_Required;
|
||||
@@ -142,8 +130,8 @@ unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance)
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
|
||||
BACNET_OCTET_STRING * value,
|
||||
uint8_t priority)
|
||||
BACNET_OCTET_STRING *value,
|
||||
uint8_t priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -171,14 +159,14 @@ BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t object_instance)
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool OctetString_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_OCTETSTRING_VALUES) {
|
||||
sprintf(text_string, "OCTETSTRING VALUE %lu",
|
||||
(unsigned long) object_instance);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -186,9 +174,9 @@ bool OctetString_Value_Object_Name(uint32_t object_instance,
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_OCTET_STRING *real_value = NULL;
|
||||
@@ -204,8 +192,7 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
|
||||
object_index =
|
||||
OctetString_Value_Instance_To_Index(rpdata->object_instance);
|
||||
object_index = OctetString_Value_Instance_To_Index(rpdata->object_instance);
|
||||
if (object_index < MAX_OCTETSTRING_VALUES)
|
||||
CurrentAV = &AV_Descr[object_index];
|
||||
else
|
||||
@@ -213,23 +200,21 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_OCTETSTRING_VALUE, rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_OCTETSTRING_VALUE, rpdata->object_instance);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
OctetString_Value_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_OCTETSTRING_VALUE);
|
||||
apdu_len = encode_application_enumerated(&apdu[0],
|
||||
OBJECT_OCTETSTRING_VALUE);
|
||||
break;
|
||||
|
||||
case PROP_PRESENT_VALUE:
|
||||
@@ -244,7 +229,7 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
CurrentAV->Out_Of_Service);
|
||||
CurrentAV->Out_Of_Service);
|
||||
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
@@ -277,18 +262,17 @@ int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
OCTETSTRING_VALUE_DESCR *CurrentAV;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
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 */
|
||||
@@ -317,8 +301,8 @@ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (OctetString_Value_Present_Value_Set(wp_data->
|
||||
object_instance, &value.type.Octet_String,
|
||||
if (OctetString_Value_Present_Value_Set(
|
||||
wp_data->object_instance, &value.type.Octet_String,
|
||||
wp_data->priority)) {
|
||||
status = true;
|
||||
} else if (wp_data->priority == 6) {
|
||||
@@ -341,7 +325,7 @@ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
CurrentAV->Out_Of_Service = value.type.Boolean;
|
||||
}
|
||||
@@ -365,7 +349,6 @@ bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
{
|
||||
}
|
||||
@@ -375,10 +358,9 @@ void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -388,10 +370,10 @@ bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
return false;
|
||||
}
|
||||
|
||||
void testOctetString_Value(Test * pTest)
|
||||
void testOctetString_Value(Test *pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -429,7 +411,7 @@ int main(void)
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+66
-78
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Positiveinteger Value Objects - customize for your use */
|
||||
|
||||
@@ -35,12 +35,11 @@
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "piv.h"
|
||||
|
||||
|
||||
#ifndef MAX_POSITIVEINTEGER_VALUES
|
||||
#define MAX_POSITIVEINTEGER_VALUES 4
|
||||
#endif
|
||||
@@ -55,21 +54,16 @@ static const int PositiveInteger_Value_Properties_Required[] = {
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_UNITS,
|
||||
- 1
|
||||
};
|
||||
-1};
|
||||
|
||||
static const int PositiveInteger_Value_Properties_Optional[] = {
|
||||
PROP_OUT_OF_SERVICE,
|
||||
-1
|
||||
};
|
||||
PROP_OUT_OF_SERVICE, -1};
|
||||
|
||||
static const int PositiveInteger_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int PositiveInteger_Value_Properties_Proprietary[] = {-1};
|
||||
|
||||
void PositiveInteger_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = PositiveInteger_Value_Properties_Required;
|
||||
@@ -140,8 +134,7 @@ unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance)
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
|
||||
uint32_t value,
|
||||
uint8_t priority)
|
||||
uint32_t value, uint8_t priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
@@ -169,14 +162,14 @@ uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance)
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_POSITIVEINTEGER_VALUES) {
|
||||
sprintf(text_string, "POSITIVEINTEGER VALUE %lu",
|
||||
(unsigned long) object_instance);
|
||||
(unsigned long)object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -184,9 +177,9 @@ bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
@@ -210,27 +203,26 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_POSITIVE_INTEGER_VALUE, rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(
|
||||
&apdu[0], OBJECT_POSITIVE_INTEGER_VALUE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_NAME:
|
||||
PositiveInteger_Value_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_POSITIVE_INTEGER_VALUE);
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], OBJECT_POSITIVE_INTEGER_VALUE);
|
||||
break;
|
||||
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0],
|
||||
PositiveInteger_Value_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
|
||||
@@ -240,7 +232,7 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
CurrentAV->Out_Of_Service);
|
||||
CurrentAV->Out_Of_Service);
|
||||
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
@@ -248,16 +240,15 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
case PROP_UNITS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], CurrentAV->Units);
|
||||
break;
|
||||
/* BACnet Testing Observed Incident oi00109
|
||||
Positive Integer Value / Units returned wrong datatype - missing break.
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00031
|
||||
BC 135.1: 9.20.1.7
|
||||
BC 135.1: 9.20.1.9
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes have been reviewed
|
||||
by all interested parties. Say 6 months -> September 2016 */
|
||||
break;
|
||||
/* BACnet Testing Observed Incident oi00109
|
||||
Positive Integer Value / Units returned wrong datatype -
|
||||
missing break. Revealed by BACnet Test Client v1.8.16 (
|
||||
www.bac-test.com/bacnet-test-client-download ) BITS: BIT00031 BC
|
||||
135.1: 9.20.1.7 BC 135.1: 9.20.1.9 Any discussions can be
|
||||
directed to edward@bac-test.com Please feel free to remove this
|
||||
comment when my changes have been reviewed by all interested
|
||||
parties. Say 6 months -> September 2016 */
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = CurrentAV->Out_Of_Service;
|
||||
@@ -282,18 +273,17 @@ int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
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 */
|
||||
@@ -322,8 +312,8 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (PositiveInteger_Value_Present_Value_Set(wp_data->
|
||||
object_instance, value.type.Unsigned_Int,
|
||||
if (PositiveInteger_Value_Present_Value_Set(
|
||||
wp_data->object_instance, value.type.Unsigned_Int,
|
||||
wp_data->priority)) {
|
||||
status = true;
|
||||
} else if (wp_data->priority == 6) {
|
||||
@@ -346,7 +336,7 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
CurrentAV->Out_Of_Service = value.type.Boolean;
|
||||
}
|
||||
@@ -369,7 +359,6 @@ bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
{
|
||||
}
|
||||
@@ -379,10 +368,9 @@ void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE *pValue,
|
||||
uint8_t ucExpectedTag, BACNET_ERROR_CLASS *pErrorClass,
|
||||
BACNET_ERROR_CODE *pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
@@ -392,10 +380,10 @@ bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
return false;
|
||||
}
|
||||
|
||||
void testPositiveInteger_Value(Test * pTest)
|
||||
void testPositiveInteger_Value(Test *pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -433,7 +421,7 @@ int main(void)
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+138
-147
@@ -1,27 +1,27 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
@@ -55,21 +55,14 @@ static const int Schedule_Properties_Required[] = {
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
-1
|
||||
};
|
||||
-1};
|
||||
|
||||
static const int Schedule_Properties_Optional[] = {
|
||||
PROP_WEEKLY_SCHEDULE,
|
||||
-1
|
||||
};
|
||||
static const int Schedule_Properties_Optional[] = {PROP_WEEKLY_SCHEDULE, -1};
|
||||
|
||||
static const int Schedule_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
static const int Schedule_Properties_Proprietary[] = {-1};
|
||||
|
||||
void Schedule_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
void Schedule_Property_Lists(const int **pRequired, const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Schedule_Properties_Required;
|
||||
@@ -98,9 +91,11 @@ void Schedule_Init(void)
|
||||
Schedule_Descr[i].Present_Value = &Schedule_Descr[i].Schedule_Default;
|
||||
Schedule_Descr[i].Schedule_Default.context_specific = false;
|
||||
Schedule_Descr[i].Schedule_Default.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
Schedule_Descr[i].Schedule_Default.type.Real = 21.0; /* 21 C, room temperature */
|
||||
Schedule_Descr[i].obj_prop_ref_cnt = 0; /* no references, add as needed */
|
||||
Schedule_Descr[i].Priority_For_Writing = 16; /* lowest priority */
|
||||
Schedule_Descr[i].Schedule_Default.type.Real =
|
||||
21.0; /* 21 C, room temperature */
|
||||
Schedule_Descr[i].obj_prop_ref_cnt =
|
||||
0; /* no references, add as needed */
|
||||
Schedule_Descr[i].Priority_For_Writing = 16; /* lowest priority */
|
||||
Schedule_Descr[i].Out_Of_Service = false;
|
||||
}
|
||||
}
|
||||
@@ -135,15 +130,15 @@ unsigned Schedule_Instance_To_Index(uint32_t instance)
|
||||
}
|
||||
|
||||
bool Schedule_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
unsigned int index;
|
||||
bool status = false;
|
||||
|
||||
index = Schedule_Instance_To_Index(object_instance);
|
||||
if (index < MAX_SCHEDULES) {
|
||||
sprintf(text_string, "SCHEDULE %lu", (unsigned long) index);
|
||||
sprintf(text_string, "SCHEDULE %lu", (unsigned long)index);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
@@ -151,15 +146,13 @@ bool Schedule_Object_Name(uint32_t object_instance,
|
||||
}
|
||||
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
void Schedule_Out_Of_Service_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 (
|
||||
www.bac-test.com/bacnet-test-client-download ) BITS: BIT00032 Any discussions
|
||||
can be directed to edward@bac-test.com Please feel free to remove this
|
||||
comment when my changes accepted after suitable time for review by all
|
||||
interested parties. Say 6 months -> September 2016 */
|
||||
void Schedule_Out_Of_Service_Set(uint32_t object_instance, bool value)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
@@ -169,8 +162,7 @@ void Schedule_Out_Of_Service_Set(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
{
|
||||
int apdu_len = 0;
|
||||
unsigned object_index = 0;
|
||||
@@ -192,11 +184,10 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
return BACNET_STATUS_ERROR;
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
switch ((int) rpdata->object_property) {
|
||||
switch ((int)rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_SCHEDULE,
|
||||
rpdata->object_instance);
|
||||
apdu_len = encode_application_object_id(&apdu[0], OBJECT_SCHEDULE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Schedule_Object_Name(rpdata->object_instance, &char_string);
|
||||
@@ -204,49 +195,51 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_SCHEDULE);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_SCHEDULE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len = bacapp_encode_data(&apdu[0], CurrentSC->Present_Value);
|
||||
break;
|
||||
case PROP_EFFECTIVE_PERIOD:
|
||||
/* BACnet Testing Observed Incident oi00110
|
||||
Effective Period of Schedule object not correctly formatted
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00031
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
apdu_len = encode_application_date(&apdu[0], &CurrentSC->Start_Date);
|
||||
/* BACnet Testing Observed Incident oi00110
|
||||
Effective Period of Schedule object not correctly formatted
|
||||
Revealed by BACnet Test Client v1.8.16 (
|
||||
www.bac-test.com/bacnet-test-client-download ) BITS: BIT00031 Any
|
||||
discussions can be directed to edward@bac-test.com Please feel
|
||||
free to remove this comment when my changes accepted after
|
||||
suitable time for
|
||||
review by all interested parties. Say 6 months -> September
|
||||
2016 */
|
||||
apdu_len =
|
||||
encode_application_date(&apdu[0], &CurrentSC->Start_Date);
|
||||
apdu_len +=
|
||||
encode_application_date(&apdu[apdu_len], &CurrentSC->End_Date);
|
||||
break;
|
||||
case PROP_WEEKLY_SCHEDULE:
|
||||
if (rpdata->array_index == 0) /* count, always 7 */
|
||||
if (rpdata->array_index == 0) /* count, always 7 */
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 7);
|
||||
else if (rpdata->array_index == BACNET_ARRAY_ALL) { /* full array */
|
||||
int day;
|
||||
for (day = 0; day < 7; day++) {
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count;
|
||||
i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_time_value(&apdu[apdu_len],
|
||||
i++) {
|
||||
apdu_len += bacapp_encode_time_value(
|
||||
&apdu[apdu_len],
|
||||
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
|
||||
}
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
}
|
||||
} else if (rpdata->array_index <= 7) { /* some array element */
|
||||
} else if (rpdata->array_index <= 7) { /* some array element */
|
||||
int day = rpdata->array_index - 1;
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count; i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_time_value(&apdu[apdu_len],
|
||||
apdu_len += bacapp_encode_time_value(
|
||||
&apdu[apdu_len],
|
||||
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
|
||||
}
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
} else { /* out of bounds */
|
||||
} else { /* out of bounds */
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
@@ -258,15 +251,13 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
break;
|
||||
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
|
||||
for (i = 0; i < CurrentSC->obj_prop_ref_cnt; i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_device_obj_property_ref(&apdu[apdu_len],
|
||||
&CurrentSC->Object_Property_References[i]);
|
||||
apdu_len += bacapp_encode_device_obj_property_ref(
|
||||
&apdu[apdu_len], &CurrentSC->Object_Property_References[i]);
|
||||
}
|
||||
break;
|
||||
case PROP_PRIORITY_FOR_WRITING:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
CurrentSC->Priority_For_Writing);
|
||||
apdu_len = encode_application_unsigned(
|
||||
&apdu[0], CurrentSC->Priority_For_Writing);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
@@ -277,21 +268,22 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
RELIABILITY_NO_FAULT_DETECTED);
|
||||
apdu_len = encode_application_enumerated(
|
||||
&apdu[0], RELIABILITY_NO_FAULT_DETECTED);
|
||||
break;
|
||||
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
apdu_len = encode_application_boolean(&apdu[0],
|
||||
CurrentSC->Out_Of_Service );
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 (
|
||||
www.bac-test.com/bacnet-test-client-download ) BITS: BIT00032 Any
|
||||
discussions can be directed to edward@bac-test.com Please feel
|
||||
free to remove this comment when my changes accepted after
|
||||
suitable time for
|
||||
review by all interested parties. Say 6 months -> September
|
||||
2016 */
|
||||
apdu_len =
|
||||
encode_application_boolean(&apdu[0], CurrentSC->Out_Of_Service);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
@@ -300,8 +292,8 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_WEEKLY_SCHEDULE)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_WEEKLY_SCHEDULE) &&
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
@@ -310,28 +302,29 @@ int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
/* Ed->Steve, I know that initializing stack values used to be 'safer', but warnings in latest compilers indicate when
|
||||
uninitialized values are being used, and I think that the warnings are more useful to reveal bad code flow than the
|
||||
"safety: of pre-intializing variables. Please give this some thought let me know if you agree we should start to
|
||||
remove initializations */
|
||||
unsigned object_index ;
|
||||
bool status = false; /* return value */
|
||||
int len ;
|
||||
/* Ed->Steve, I know that initializing stack values used to be 'safer', but
|
||||
warnings in latest compilers indicate when uninitialized values are being
|
||||
used, and I think that the warnings are more useful to reveal bad code
|
||||
flow than the "safety: of pre-intializing variables. Please give this
|
||||
some thought let me know if you agree we should start to remove
|
||||
initializations */
|
||||
unsigned object_index;
|
||||
bool status = false; /* return value */
|
||||
int len;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 (
|
||||
www.bac-test.com/bacnet-test-client-download ) BITS: BIT00032 Any
|
||||
discussions can be directed to edward@bac-test.com Please feel free to
|
||||
remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
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 */
|
||||
@@ -345,22 +338,23 @@ bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ((int) wp_data->object_property) {
|
||||
switch ((int)wp_data->object_property) {
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 (
|
||||
www.bac-test.com/bacnet-test-client-download ) BITS: BIT00032 Any
|
||||
discussions can be directed to edward@bac-test.com Please feel
|
||||
free to remove this comment when my changes accepted after
|
||||
suitable time for
|
||||
review by all interested parties. Say 6 months -> September
|
||||
2016 */
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Schedule_Out_Of_Service_Set(
|
||||
wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
Schedule_Out_Of_Service_Set(wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -387,8 +381,7 @@ bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
|
||||
BACNET_DATE * date)
|
||||
bool Schedule_In_Effective_Period(SCHEDULE_DESCR *desc, BACNET_DATE *date)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
@@ -401,29 +394,29 @@ bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
|
||||
return res;
|
||||
}
|
||||
|
||||
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
|
||||
BACNET_WEEKDAY wday,
|
||||
BACNET_TIME * time)
|
||||
void Schedule_Recalculate_PV(SCHEDULE_DESCR *desc, BACNET_WEEKDAY wday,
|
||||
BACNET_TIME *time)
|
||||
{
|
||||
int i;
|
||||
desc->Present_Value = NULL;
|
||||
|
||||
/* for future development, here should be the loop for Exception Schedule */
|
||||
|
||||
/* Just a note to developers: We have a paying customer who has asked us to fully implement the Schedule Object.
|
||||
In good spirit, they have agreed to allow us to release the code we develop back to the Open Source community after a 6-12 month waiting period.
|
||||
However, if you are about to work on this yourself, please ping us at info@connect-ex.com, we may be able to broker an early release on a
|
||||
case-by-case basis. */
|
||||
|
||||
|
||||
for (i = 0;
|
||||
i < desc->Weekly_Schedule[wday - 1].TV_Count &&
|
||||
desc->Present_Value == NULL; i++) {
|
||||
int diff = datetime_wildcard_compare_time(time,
|
||||
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Time);
|
||||
/* Just a note to developers: We have a paying customer who has asked us to
|
||||
fully implement the Schedule Object. In good spirit, they have agreed to
|
||||
allow us to release the code we develop back to the Open Source community
|
||||
after a 6-12 month waiting period. However, if you are about to work on
|
||||
this yourself, please ping us at info@connect-ex.com, we may be able to
|
||||
broker an early release on a case-by-case basis. */
|
||||
|
||||
for (i = 0; i < desc->Weekly_Schedule[wday - 1].TV_Count &&
|
||||
desc->Present_Value == NULL;
|
||||
i++) {
|
||||
int diff = datetime_wildcard_compare_time(
|
||||
time, &desc->Weekly_Schedule[wday - 1].Time_Values[i].Time);
|
||||
if (diff >= 0 &&
|
||||
desc->Weekly_Schedule[wday - 1].Time_Values[i].Value.tag !=
|
||||
BACNET_APPLICATION_TAG_NULL) {
|
||||
BACNET_APPLICATION_TAG_NULL) {
|
||||
desc->Present_Value =
|
||||
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Value;
|
||||
}
|
||||
@@ -438,11 +431,10 @@ void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
|
||||
void testSchedule(Test * pTest)
|
||||
void testSchedule(Test *pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
uint8_t apdu[MAX_APDU] = {0};
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
@@ -467,7 +459,6 @@ void testSchedule(Test * pTest)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST_SCHEDULE
|
||||
|
||||
int main(void)
|
||||
@@ -482,7 +473,7 @@ int main(void)
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
(void)ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
|
||||
+385
-414
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user