Fixed line endings and SVN props with fixup.sh script
This commit is contained in:
@@ -1,480 +1,480 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the credential to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access Credential Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_credential.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_Credential_Initialized = false;
|
||||
|
||||
static ACCESS_CREDENTIAL_DESCR ac_descr[MAX_ACCESS_CREDENTIALS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_CREDENTIAL_STATUS,
|
||||
PROP_REASON_FOR_DISABLE,
|
||||
PROP_AUTHENTICATION_FACTORS,
|
||||
PROP_ACTIVATION_TIME,
|
||||
PROP_EXPIRATION_TIME,
|
||||
PROP_CREDENTIAL_DISABLE,
|
||||
PROP_ASSIGNED_ACCESS_RIGHTS,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_Credential_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Credential_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_Credential_Initialized) {
|
||||
Access_Credential_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_CREDENTIALS; i++) {
|
||||
ac_descr[i].global_identifier = 0; /* set to some meaningful value */
|
||||
ac_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
ac_descr[i].credential_status = false;
|
||||
ac_descr[i].reasons_count = 0;
|
||||
ac_descr[i].auth_factors_count = 0;
|
||||
memset(&ac_descr[i].activation_time, 0, sizeof(BACNET_DATE_TIME));
|
||||
memset(&ac_descr[i].expiration_time, 0, sizeof(BACNET_DATE_TIME));
|
||||
ac_descr[i].credential_disable = ACCESS_CREDENTIAL_DISABLE_NONE;
|
||||
ac_descr[i].assigned_access_rights_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_Credential_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_CREDENTIALS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Credential_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_CREDENTIALS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_Credential_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_Credential_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_CREDENTIALS;
|
||||
|
||||
if (object_instance < MAX_ACCESS_CREDENTIALS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Credential_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_CREDENTIALS) {
|
||||
sprintf(text_string, "ACCESS CREDENTIAL %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Credential_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index =
|
||||
Access_Credential_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_ACCESS_CREDENTIAL, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_Credential_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_ACCESS_CREDENTIAL);
|
||||
break;
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ac_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ac_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_CREDENTIAL_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ac_descr[object_index].credential_status);
|
||||
break;
|
||||
case PROP_REASON_FOR_DISABLE:
|
||||
for (i = 0; i < ac_descr[object_index].reasons_count; i++) {
|
||||
len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ac_descr[object_index].reason_for_disable[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_AUTHENTICATION_FACTORS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ac_descr[object_index].auth_factors_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0; i < ac_descr[object_index].auth_factors_count; i++) {
|
||||
len =
|
||||
bacapp_encode_credential_authentication_factor(&apdu
|
||||
[0], &ac_descr[object_index].auth_factors[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
ac_descr[object_index].auth_factors_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_credential_authentication_factor(&apdu
|
||||
[0],
|
||||
&ac_descr[object_index].
|
||||
auth_factors[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_ACTIVATION_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_datetime(&apdu[0],
|
||||
&ac_descr[object_index].activation_time);
|
||||
break;
|
||||
case PROP_EXPIRATION_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_datetime(&apdu[0],
|
||||
&ac_descr[object_index].expiration_time);
|
||||
break;
|
||||
case PROP_CREDENTIAL_DISABLE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ac_descr[object_index].credential_disable);
|
||||
break;
|
||||
case PROP_ASSIGNED_ACCESS_RIGHTS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ac_descr[object_index].assigned_access_rights_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0;
|
||||
i < ac_descr[object_index].assigned_access_rights_count;
|
||||
i++) {
|
||||
len =
|
||||
bacapp_encode_assigned_access_rights(&apdu[0],
|
||||
&ac_descr[object_index].assigned_access_rights[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
ac_descr[object_index].assigned_access_rights_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_assigned_access_rights(&apdu[0],
|
||||
&ac_descr[object_index].
|
||||
assigned_access_rights[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) &&
|
||||
(rpdata->object_property != PROP_AUTHENTICATION_FACTORS)
|
||||
&& (rpdata->object_property != PROP_ASSIGNED_ACCESS_RIGHTS)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Credential_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->object_property != PROP_AUTHENTICATION_FACTORS)
|
||||
&& (wp_data->object_property != PROP_ASSIGNED_ACCESS_RIGHTS)
|
||||
&& (wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index =
|
||||
Access_Credential_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
ac_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_RELIABILITY:
|
||||
case PROP_CREDENTIAL_STATUS:
|
||||
case PROP_REASON_FOR_DISABLE:
|
||||
case PROP_AUTHENTICATION_FACTORS:
|
||||
case PROP_ACTIVATION_TIME:
|
||||
case PROP_EXPIRATION_TIME:
|
||||
case PROP_CREDENTIAL_DISABLE:
|
||||
case PROP_ASSIGNED_ACCESS_RIGHTS:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessCredential(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_Credential_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_CREDENTIAL;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_Credential_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_CREDENTIAL
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access Credential", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessCredential);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_CREDENTIAL */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the credential to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access Credential Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_credential.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_Credential_Initialized = false;
|
||||
|
||||
static ACCESS_CREDENTIAL_DESCR ac_descr[MAX_ACCESS_CREDENTIALS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_CREDENTIAL_STATUS,
|
||||
PROP_REASON_FOR_DISABLE,
|
||||
PROP_AUTHENTICATION_FACTORS,
|
||||
PROP_ACTIVATION_TIME,
|
||||
PROP_EXPIRATION_TIME,
|
||||
PROP_CREDENTIAL_DISABLE,
|
||||
PROP_ASSIGNED_ACCESS_RIGHTS,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_Credential_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Credential_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_Credential_Initialized) {
|
||||
Access_Credential_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_CREDENTIALS; i++) {
|
||||
ac_descr[i].global_identifier = 0; /* set to some meaningful value */
|
||||
ac_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
ac_descr[i].credential_status = false;
|
||||
ac_descr[i].reasons_count = 0;
|
||||
ac_descr[i].auth_factors_count = 0;
|
||||
memset(&ac_descr[i].activation_time, 0, sizeof(BACNET_DATE_TIME));
|
||||
memset(&ac_descr[i].expiration_time, 0, sizeof(BACNET_DATE_TIME));
|
||||
ac_descr[i].credential_disable = ACCESS_CREDENTIAL_DISABLE_NONE;
|
||||
ac_descr[i].assigned_access_rights_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_Credential_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_CREDENTIALS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Credential_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_CREDENTIALS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_Credential_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_Credential_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_CREDENTIALS;
|
||||
|
||||
if (object_instance < MAX_ACCESS_CREDENTIALS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Credential_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_CREDENTIALS) {
|
||||
sprintf(text_string, "ACCESS CREDENTIAL %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Credential_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index =
|
||||
Access_Credential_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_ACCESS_CREDENTIAL, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_Credential_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_ACCESS_CREDENTIAL);
|
||||
break;
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ac_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ac_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_CREDENTIAL_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ac_descr[object_index].credential_status);
|
||||
break;
|
||||
case PROP_REASON_FOR_DISABLE:
|
||||
for (i = 0; i < ac_descr[object_index].reasons_count; i++) {
|
||||
len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ac_descr[object_index].reason_for_disable[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_AUTHENTICATION_FACTORS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ac_descr[object_index].auth_factors_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0; i < ac_descr[object_index].auth_factors_count; i++) {
|
||||
len =
|
||||
bacapp_encode_credential_authentication_factor(&apdu
|
||||
[0], &ac_descr[object_index].auth_factors[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
ac_descr[object_index].auth_factors_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_credential_authentication_factor(&apdu
|
||||
[0],
|
||||
&ac_descr[object_index].
|
||||
auth_factors[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_ACTIVATION_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_datetime(&apdu[0],
|
||||
&ac_descr[object_index].activation_time);
|
||||
break;
|
||||
case PROP_EXPIRATION_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_datetime(&apdu[0],
|
||||
&ac_descr[object_index].expiration_time);
|
||||
break;
|
||||
case PROP_CREDENTIAL_DISABLE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ac_descr[object_index].credential_disable);
|
||||
break;
|
||||
case PROP_ASSIGNED_ACCESS_RIGHTS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ac_descr[object_index].assigned_access_rights_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0;
|
||||
i < ac_descr[object_index].assigned_access_rights_count;
|
||||
i++) {
|
||||
len =
|
||||
bacapp_encode_assigned_access_rights(&apdu[0],
|
||||
&ac_descr[object_index].assigned_access_rights[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
ac_descr[object_index].assigned_access_rights_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_assigned_access_rights(&apdu[0],
|
||||
&ac_descr[object_index].
|
||||
assigned_access_rights[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) &&
|
||||
(rpdata->object_property != PROP_AUTHENTICATION_FACTORS)
|
||||
&& (rpdata->object_property != PROP_ASSIGNED_ACCESS_RIGHTS)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Credential_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->object_property != PROP_AUTHENTICATION_FACTORS)
|
||||
&& (wp_data->object_property != PROP_ASSIGNED_ACCESS_RIGHTS)
|
||||
&& (wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index =
|
||||
Access_Credential_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
ac_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_RELIABILITY:
|
||||
case PROP_CREDENTIAL_STATUS:
|
||||
case PROP_REASON_FOR_DISABLE:
|
||||
case PROP_AUTHENTICATION_FACTORS:
|
||||
case PROP_ACTIVATION_TIME:
|
||||
case PROP_EXPIRATION_TIME:
|
||||
case PROP_CREDENTIAL_DISABLE:
|
||||
case PROP_ASSIGNED_ACCESS_RIGHTS:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessCredential(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_Credential_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_CREDENTIAL;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_Credential_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_CREDENTIAL
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access Credential", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessCredential);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_CREDENTIAL */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,124 +1,124 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_CREDENTIAL_H
|
||||
#define ACCESS_CREDENTIAL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "datetime.h"
|
||||
#include "timestamp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "assigned_access_rights.h"
|
||||
#include "credential_authentication_factor.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_CREDENTIALS
|
||||
#define MAX_ACCESS_CREDENTIALS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_REASONS_FOR_DISABLE
|
||||
#define MAX_REASONS_FOR_DISABLE 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_AUTHENTICATION_FACTORS
|
||||
#define MAX_AUTHENTICATION_FACTORS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ASSIGNED_ACCESS_RIGHTS
|
||||
#define MAX_ASSIGNED_ACCESS_RIGHTS 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
uint32_t global_identifier;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool credential_status;
|
||||
uint32_t reasons_count;
|
||||
BACNET_ACCESS_CREDENTIAL_DISABLE_REASON
|
||||
reason_for_disable[MAX_REASONS_FOR_DISABLE];
|
||||
uint32_t auth_factors_count;
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR
|
||||
auth_factors[MAX_AUTHENTICATION_FACTORS];
|
||||
BACNET_DATE_TIME activation_time, expiration_time;
|
||||
BACNET_ACCESS_CREDENTIAL_DISABLE credential_disable;
|
||||
uint32_t assigned_access_rights_count;
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS
|
||||
assigned_access_rights[MAX_ASSIGNED_ACCESS_RIGHTS];
|
||||
} ACCESS_CREDENTIAL_DESCR;
|
||||
|
||||
void Access_Credential_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Credential_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Credential_Count(
|
||||
void);
|
||||
uint32_t Access_Credential_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Credential_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Credential_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
|
||||
bool Access_Credential_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Credential_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
int Access_Credential_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Credential_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Credential_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Credential_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Credential_Cleanup(
|
||||
void);
|
||||
void Access_Credential_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessCredential(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_CREDENTIAL_H
|
||||
#define ACCESS_CREDENTIAL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "datetime.h"
|
||||
#include "timestamp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "assigned_access_rights.h"
|
||||
#include "credential_authentication_factor.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_CREDENTIALS
|
||||
#define MAX_ACCESS_CREDENTIALS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_REASONS_FOR_DISABLE
|
||||
#define MAX_REASONS_FOR_DISABLE 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_AUTHENTICATION_FACTORS
|
||||
#define MAX_AUTHENTICATION_FACTORS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ASSIGNED_ACCESS_RIGHTS
|
||||
#define MAX_ASSIGNED_ACCESS_RIGHTS 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
uint32_t global_identifier;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool credential_status;
|
||||
uint32_t reasons_count;
|
||||
BACNET_ACCESS_CREDENTIAL_DISABLE_REASON
|
||||
reason_for_disable[MAX_REASONS_FOR_DISABLE];
|
||||
uint32_t auth_factors_count;
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR
|
||||
auth_factors[MAX_AUTHENTICATION_FACTORS];
|
||||
BACNET_DATE_TIME activation_time, expiration_time;
|
||||
BACNET_ACCESS_CREDENTIAL_DISABLE credential_disable;
|
||||
uint32_t assigned_access_rights_count;
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS
|
||||
assigned_access_rights[MAX_ASSIGNED_ACCESS_RIGHTS];
|
||||
} ACCESS_CREDENTIAL_DESCR;
|
||||
|
||||
void Access_Credential_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Credential_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Credential_Count(
|
||||
void);
|
||||
uint32_t Access_Credential_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Credential_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Credential_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
|
||||
bool Access_Credential_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Credential_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
int Access_Credential_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Credential_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Credential_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Credential_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Credential_Cleanup(
|
||||
void);
|
||||
void Access_Credential_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessCredential(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_CREDENTIAL
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_credential.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/assigned_access_rights.c \
|
||||
$(SRC_DIR)/authentication_factor.c \
|
||||
$(SRC_DIR)/credential_authentication_factor.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_credential
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_CREDENTIAL
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_credential.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/assigned_access_rights.c \
|
||||
$(SRC_DIR)/authentication_factor.c \
|
||||
$(SRC_DIR)/credential_authentication_factor.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_credential
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,143 +1,143 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_DOOR_H
|
||||
#define ACCESS_DOOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_DOORS
|
||||
#define MAX_ACCESS_DOORS 4
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
bool value_active[BACNET_MAX_PRIORITY];
|
||||
BACNET_DOOR_VALUE priority_array[BACNET_MAX_PRIORITY];
|
||||
BACNET_DOOR_VALUE relinquish_default;
|
||||
BACNET_EVENT_STATE event_state;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool out_of_service;
|
||||
BACNET_DOOR_STATUS door_status;
|
||||
BACNET_LOCK_STATUS lock_status;
|
||||
BACNET_DOOR_SECURED_STATUS secured_status;
|
||||
uint32_t door_pulse_time, door_extended_pulse_time,
|
||||
door_unlock_delay_time, door_open_too_long_time;
|
||||
BACNET_DOOR_ALARM_STATE door_alarm_state;
|
||||
} ACCESS_DOOR_DESCR;
|
||||
|
||||
void Access_Door_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Door_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Door_Count(
|
||||
void);
|
||||
uint32_t Access_Door_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Door_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Door_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
BACNET_DOOR_VALUE Access_Door_Present_Value(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Door_Present_Value_Priority(
|
||||
uint32_t object_instance);
|
||||
bool Access_Door_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_DOOR_VALUE value,
|
||||
unsigned priority);
|
||||
bool Access_Door_Present_Value_Relinquish(
|
||||
uint32_t object_instance,
|
||||
unsigned priority);
|
||||
|
||||
BACNET_DOOR_VALUE Access_Door_Relinquish_Default(
|
||||
uint32_t object_instance);
|
||||
bool Access_Door_Relinquish_Default_Set(
|
||||
uint32_t object_instance,
|
||||
float value);
|
||||
|
||||
bool Access_Door_Change_Of_Value(
|
||||
uint32_t instance);
|
||||
void Access_Door_Change_Of_Value_Clear(
|
||||
uint32_t instance);
|
||||
bool Access_Door_Encode_Value_List(
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list);
|
||||
|
||||
bool Access_Door_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Door_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
char *Access_Door_Description(
|
||||
uint32_t instance);
|
||||
bool Access_Door_Description_Set(
|
||||
uint32_t instance,
|
||||
char *new_name);
|
||||
|
||||
bool Access_Door_Out_Of_Service(
|
||||
uint32_t instance);
|
||||
void Access_Door_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
int Access_Door_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Door_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Door_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Door_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Door_Cleanup(
|
||||
void);
|
||||
void Access_Door_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessDoor(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_DOOR_H
|
||||
#define ACCESS_DOOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_DOORS
|
||||
#define MAX_ACCESS_DOORS 4
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
bool value_active[BACNET_MAX_PRIORITY];
|
||||
BACNET_DOOR_VALUE priority_array[BACNET_MAX_PRIORITY];
|
||||
BACNET_DOOR_VALUE relinquish_default;
|
||||
BACNET_EVENT_STATE event_state;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool out_of_service;
|
||||
BACNET_DOOR_STATUS door_status;
|
||||
BACNET_LOCK_STATUS lock_status;
|
||||
BACNET_DOOR_SECURED_STATUS secured_status;
|
||||
uint32_t door_pulse_time, door_extended_pulse_time,
|
||||
door_unlock_delay_time, door_open_too_long_time;
|
||||
BACNET_DOOR_ALARM_STATE door_alarm_state;
|
||||
} ACCESS_DOOR_DESCR;
|
||||
|
||||
void Access_Door_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Door_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Door_Count(
|
||||
void);
|
||||
uint32_t Access_Door_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Door_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Door_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
BACNET_DOOR_VALUE Access_Door_Present_Value(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Door_Present_Value_Priority(
|
||||
uint32_t object_instance);
|
||||
bool Access_Door_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
BACNET_DOOR_VALUE value,
|
||||
unsigned priority);
|
||||
bool Access_Door_Present_Value_Relinquish(
|
||||
uint32_t object_instance,
|
||||
unsigned priority);
|
||||
|
||||
BACNET_DOOR_VALUE Access_Door_Relinquish_Default(
|
||||
uint32_t object_instance);
|
||||
bool Access_Door_Relinquish_Default_Set(
|
||||
uint32_t object_instance,
|
||||
float value);
|
||||
|
||||
bool Access_Door_Change_Of_Value(
|
||||
uint32_t instance);
|
||||
void Access_Door_Change_Of_Value_Clear(
|
||||
uint32_t instance);
|
||||
bool Access_Door_Encode_Value_List(
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list);
|
||||
|
||||
bool Access_Door_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Door_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
char *Access_Door_Description(
|
||||
uint32_t instance);
|
||||
bool Access_Door_Description_Set(
|
||||
uint32_t instance,
|
||||
char *new_name);
|
||||
|
||||
bool Access_Door_Out_Of_Service(
|
||||
uint32_t instance);
|
||||
void Access_Door_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
int Access_Door_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Door_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Door_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Door_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Door_Cleanup(
|
||||
void);
|
||||
void Access_Door_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessDoor(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_DOOR
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_door.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_door
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_DOOR
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_door.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_door
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
@@ -1,476 +1,476 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access Point Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_point.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_Point_Initialized = false;
|
||||
|
||||
static ACCESS_POINT_DESCR ap_descr[MAX_ACCESS_POINTS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_AUTHENTICATION_STATUS,
|
||||
PROP_ACTIVE_AUTHENTICATION_POLICY,
|
||||
PROP_NUMBER_OF_AUTHENTICATION_POLICIES,
|
||||
PROP_AUTHORIZATION_MODE,
|
||||
PROP_ACCESS_EVENT,
|
||||
PROP_ACCESS_EVENT_TAG,
|
||||
PROP_ACCESS_EVENT_TIME,
|
||||
PROP_ACCESS_EVENT_CREDENTIAL,
|
||||
PROP_ACCESS_DOORS,
|
||||
PROP_PRIORITY_FOR_WRITING,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_Point_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Point_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_Point_Initialized) {
|
||||
Access_Point_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_POINTS; i++) {
|
||||
ap_descr[i].event_state = EVENT_STATE_NORMAL;
|
||||
ap_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
ap_descr[i].out_of_service = false;
|
||||
ap_descr[i].authentication_status =
|
||||
AUTHENTICATION_STATUS_NOT_READY;
|
||||
ap_descr[i].active_authentication_policy = 0;
|
||||
ap_descr[i].number_of_authentication_policies = 0;
|
||||
ap_descr[i].authorization_mode = AUTHORIZATION_MODE_AUTHORIZE;
|
||||
ap_descr[i].access_event = ACCESS_EVENT_NONE;
|
||||
/* timestamp uninitialized */
|
||||
/* access_event_credential should be set to some meaningful value */
|
||||
ap_descr[i].num_doors = 0;
|
||||
/* fill in the access doors with proper ids */
|
||||
ap_descr[i].priority_for_writing = 16; /* lowest possible for now */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_Point_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_POINTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Point_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_POINTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_Point_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_Point_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_POINTS;
|
||||
|
||||
if (object_instance < MAX_ACCESS_POINTS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Point_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_POINTS) {
|
||||
sprintf(text_string, "ACCESS POINT %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Access_Point_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
|
||||
index = Access_Point_Instance_To_Index(instance);
|
||||
if (index < MAX_ACCESS_POINTS) {
|
||||
oos_flag = ap_descr[index].out_of_service;
|
||||
}
|
||||
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Access_Point_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
index = Access_Point_Instance_To_Index(instance);
|
||||
if (index < MAX_ACCESS_POINTS) {
|
||||
ap_descr[index].out_of_service = oos_flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Point_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index = Access_Point_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ACCESS_POINT,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_Point_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_POINT);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
state = Access_Point_Out_Of_Service(rpdata->object_instance);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].event_state);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = Access_Point_Out_Of_Service(rpdata->object_instance);
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_AUTHENTICATION_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].authentication_status);
|
||||
break;
|
||||
case PROP_ACTIVE_AUTHENTICATION_POLICY:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ap_descr[object_index].active_authentication_policy);
|
||||
break;
|
||||
case PROP_NUMBER_OF_AUTHENTICATION_POLICIES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ap_descr[object_index].number_of_authentication_policies);
|
||||
break;
|
||||
case PROP_AUTHORIZATION_MODE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].authorization_mode);
|
||||
break;
|
||||
case PROP_ACCESS_EVENT:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].access_event);
|
||||
break;
|
||||
case PROP_ACCESS_EVENT_TAG:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ap_descr[object_index].access_event_tag);
|
||||
break;
|
||||
case PROP_ACCESS_EVENT_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_timestamp(&apdu[0],
|
||||
&ap_descr[object_index].access_event_time);
|
||||
break;
|
||||
case PROP_ACCESS_EVENT_CREDENTIAL:
|
||||
apdu_len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&ap_descr[object_index].access_event_credential);
|
||||
break;
|
||||
case PROP_ACCESS_DOORS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ap_descr[object_index].num_doors);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0; i < ap_descr[object_index].num_doors; i++) {
|
||||
len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&ap_descr[object_index].access_doors[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <= ap_descr[object_index].num_doors) {
|
||||
apdu_len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&ap_descr[object_index].access_doors[rpdata->
|
||||
array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_ACCESS_DOORS) &&
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Point_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->object_property != PROP_ACCESS_DOORS) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_RELIABILITY:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_AUTHENTICATION_STATUS:
|
||||
case PROP_ACTIVE_AUTHENTICATION_POLICY:
|
||||
case PROP_NUMBER_OF_AUTHENTICATION_POLICIES:
|
||||
case PROP_AUTHORIZATION_MODE:
|
||||
case PROP_ACCESS_EVENT:
|
||||
case PROP_ACCESS_EVENT_TAG:
|
||||
case PROP_ACCESS_EVENT_TIME:
|
||||
case PROP_ACCESS_EVENT_CREDENTIAL:
|
||||
case PROP_ACCESS_DOORS:
|
||||
case PROP_PRIORITY_FOR_WRITING:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessPoint(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_Point_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_POINT;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_Point_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_POINT
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access Point", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessPoint);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_POINT */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access Point Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_point.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_Point_Initialized = false;
|
||||
|
||||
static ACCESS_POINT_DESCR ap_descr[MAX_ACCESS_POINTS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_AUTHENTICATION_STATUS,
|
||||
PROP_ACTIVE_AUTHENTICATION_POLICY,
|
||||
PROP_NUMBER_OF_AUTHENTICATION_POLICIES,
|
||||
PROP_AUTHORIZATION_MODE,
|
||||
PROP_ACCESS_EVENT,
|
||||
PROP_ACCESS_EVENT_TAG,
|
||||
PROP_ACCESS_EVENT_TIME,
|
||||
PROP_ACCESS_EVENT_CREDENTIAL,
|
||||
PROP_ACCESS_DOORS,
|
||||
PROP_PRIORITY_FOR_WRITING,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_Point_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Point_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_Point_Initialized) {
|
||||
Access_Point_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_POINTS; i++) {
|
||||
ap_descr[i].event_state = EVENT_STATE_NORMAL;
|
||||
ap_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
ap_descr[i].out_of_service = false;
|
||||
ap_descr[i].authentication_status =
|
||||
AUTHENTICATION_STATUS_NOT_READY;
|
||||
ap_descr[i].active_authentication_policy = 0;
|
||||
ap_descr[i].number_of_authentication_policies = 0;
|
||||
ap_descr[i].authorization_mode = AUTHORIZATION_MODE_AUTHORIZE;
|
||||
ap_descr[i].access_event = ACCESS_EVENT_NONE;
|
||||
/* timestamp uninitialized */
|
||||
/* access_event_credential should be set to some meaningful value */
|
||||
ap_descr[i].num_doors = 0;
|
||||
/* fill in the access doors with proper ids */
|
||||
ap_descr[i].priority_for_writing = 16; /* lowest possible for now */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_Point_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_POINTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Point_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_POINTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_Point_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_Point_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_POINTS;
|
||||
|
||||
if (object_instance < MAX_ACCESS_POINTS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Point_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_POINTS) {
|
||||
sprintf(text_string, "ACCESS POINT %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Access_Point_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
|
||||
index = Access_Point_Instance_To_Index(instance);
|
||||
if (index < MAX_ACCESS_POINTS) {
|
||||
oos_flag = ap_descr[index].out_of_service;
|
||||
}
|
||||
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Access_Point_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
index = Access_Point_Instance_To_Index(instance);
|
||||
if (index < MAX_ACCESS_POINTS) {
|
||||
ap_descr[index].out_of_service = oos_flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Point_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index = Access_Point_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ACCESS_POINT,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_Point_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_POINT);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
state = Access_Point_Out_Of_Service(rpdata->object_instance);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].event_state);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = Access_Point_Out_Of_Service(rpdata->object_instance);
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_AUTHENTICATION_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].authentication_status);
|
||||
break;
|
||||
case PROP_ACTIVE_AUTHENTICATION_POLICY:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ap_descr[object_index].active_authentication_policy);
|
||||
break;
|
||||
case PROP_NUMBER_OF_AUTHENTICATION_POLICIES:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ap_descr[object_index].number_of_authentication_policies);
|
||||
break;
|
||||
case PROP_AUTHORIZATION_MODE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].authorization_mode);
|
||||
break;
|
||||
case PROP_ACCESS_EVENT:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ap_descr[object_index].access_event);
|
||||
break;
|
||||
case PROP_ACCESS_EVENT_TAG:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ap_descr[object_index].access_event_tag);
|
||||
break;
|
||||
case PROP_ACCESS_EVENT_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_timestamp(&apdu[0],
|
||||
&ap_descr[object_index].access_event_time);
|
||||
break;
|
||||
case PROP_ACCESS_EVENT_CREDENTIAL:
|
||||
apdu_len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&ap_descr[object_index].access_event_credential);
|
||||
break;
|
||||
case PROP_ACCESS_DOORS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ap_descr[object_index].num_doors);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0; i < ap_descr[object_index].num_doors; i++) {
|
||||
len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&ap_descr[object_index].access_doors[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <= ap_descr[object_index].num_doors) {
|
||||
apdu_len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&ap_descr[object_index].access_doors[rpdata->
|
||||
array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_ACCESS_DOORS) &&
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Point_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->object_property != PROP_ACCESS_DOORS) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_RELIABILITY:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_AUTHENTICATION_STATUS:
|
||||
case PROP_ACTIVE_AUTHENTICATION_POLICY:
|
||||
case PROP_NUMBER_OF_AUTHENTICATION_POLICIES:
|
||||
case PROP_AUTHORIZATION_MODE:
|
||||
case PROP_ACCESS_EVENT:
|
||||
case PROP_ACCESS_EVENT_TAG:
|
||||
case PROP_ACCESS_EVENT_TIME:
|
||||
case PROP_ACCESS_EVENT_CREDENTIAL:
|
||||
case PROP_ACCESS_DOORS:
|
||||
case PROP_PRIORITY_FOR_WRITING:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessPoint(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_Point_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_POINT;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_Point_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_POINT
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access Point", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessPoint);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_POINT */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,120 +1,120 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_POINT_H
|
||||
#define ACCESS_POINT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "timestamp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_POINTS
|
||||
#define MAX_ACCESS_POINTS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ACCESS_DOORS_COUNT
|
||||
#define MAX_ACCESS_DOORS_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
BACNET_EVENT_STATE event_state;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool out_of_service;
|
||||
BACNET_AUTHENTICATION_STATUS authentication_status;
|
||||
uint32_t active_authentication_policy,
|
||||
number_of_authentication_policies;
|
||||
BACNET_AUTHORIZATION_MODE authorization_mode;
|
||||
BACNET_ACCESS_EVENT access_event;
|
||||
uint32_t access_event_tag;
|
||||
BACNET_TIMESTAMP access_event_time;
|
||||
BACNET_DEVICE_OBJECT_REFERENCE access_event_credential;
|
||||
uint32_t num_doors; /* helper value, not a property */
|
||||
BACNET_DEVICE_OBJECT_REFERENCE access_doors[MAX_ACCESS_DOORS_COUNT];
|
||||
uint8_t priority_for_writing;
|
||||
} ACCESS_POINT_DESCR;
|
||||
|
||||
void Access_Point_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Point_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Point_Count(
|
||||
void);
|
||||
uint32_t Access_Point_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Point_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Point_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
|
||||
bool Access_Point_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Point_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
|
||||
bool Access_Point_Out_Of_Service(
|
||||
uint32_t instance);
|
||||
void Access_Point_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
int Access_Point_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Point_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Point_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Point_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Point_Cleanup(
|
||||
void);
|
||||
void Access_Point_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessPoint(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_POINT_H
|
||||
#define ACCESS_POINT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "timestamp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_POINTS
|
||||
#define MAX_ACCESS_POINTS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ACCESS_DOORS_COUNT
|
||||
#define MAX_ACCESS_DOORS_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
BACNET_EVENT_STATE event_state;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool out_of_service;
|
||||
BACNET_AUTHENTICATION_STATUS authentication_status;
|
||||
uint32_t active_authentication_policy,
|
||||
number_of_authentication_policies;
|
||||
BACNET_AUTHORIZATION_MODE authorization_mode;
|
||||
BACNET_ACCESS_EVENT access_event;
|
||||
uint32_t access_event_tag;
|
||||
BACNET_TIMESTAMP access_event_time;
|
||||
BACNET_DEVICE_OBJECT_REFERENCE access_event_credential;
|
||||
uint32_t num_doors; /* helper value, not a property */
|
||||
BACNET_DEVICE_OBJECT_REFERENCE access_doors[MAX_ACCESS_DOORS_COUNT];
|
||||
uint8_t priority_for_writing;
|
||||
} ACCESS_POINT_DESCR;
|
||||
|
||||
void Access_Point_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Point_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Point_Count(
|
||||
void);
|
||||
uint32_t Access_Point_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Point_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Point_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
|
||||
bool Access_Point_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Point_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
|
||||
bool Access_Point_Out_Of_Service(
|
||||
uint32_t instance);
|
||||
void Access_Point_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
int Access_Point_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Point_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Point_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Point_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Point_Cleanup(
|
||||
void);
|
||||
void Access_Point_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessPoint(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_POINT
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_point.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(SRC_DIR)/timestamp.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_point
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_POINT
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_point.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(SRC_DIR)/timestamp.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_point
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
@@ -1,435 +1,435 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access Rights Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_rights.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_Rights_Initialized = false;
|
||||
|
||||
static ACCESS_RIGHTS_DESCR ar_descr[MAX_ACCESS_RIGHTSS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_ENABLE,
|
||||
PROP_NEGATIVE_ACCESS_RULES,
|
||||
PROP_POSITIVE_ACCESS_RULES,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_Rights_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Rights_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_Rights_Initialized) {
|
||||
Access_Rights_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_RIGHTSS; i++) {
|
||||
ar_descr[i].global_identifier = 0; /* set to some meaningful value */
|
||||
ar_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
ar_descr[i].enable = false;
|
||||
ar_descr[i].negative_access_rules_count = 0;
|
||||
ar_descr[i].positive_access_rules_count = 0;
|
||||
/* fill in the positive and negative access rules with proper ids */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_Rights_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_RIGHTSS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Rights_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_RIGHTSS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_Rights_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_Rights_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_RIGHTSS;
|
||||
|
||||
if (object_instance < MAX_ACCESS_RIGHTSS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Rights_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_RIGHTSS) {
|
||||
sprintf(text_string, "ACCESS RIGHTS %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Rights_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index = Access_Rights_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ACCESS_RIGHTS,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_Rights_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_RIGHTS);
|
||||
break;
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ar_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ar_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_ENABLE:
|
||||
apdu_len =
|
||||
encode_application_boolean(&apdu[0],
|
||||
ar_descr[object_index].enable);
|
||||
break;
|
||||
case PROP_NEGATIVE_ACCESS_RULES:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ar_descr[object_index].negative_access_rules_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0;
|
||||
i < ar_descr[object_index].negative_access_rules_count;
|
||||
i++) {
|
||||
len =
|
||||
bacapp_encode_access_rule(&apdu[0],
|
||||
&ar_descr[object_index].negative_access_rules[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
ar_descr[object_index].negative_access_rules_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_access_rule(&apdu[0],
|
||||
&ar_descr[object_index].
|
||||
negative_access_rules[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_POSITIVE_ACCESS_RULES:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ar_descr[object_index].positive_access_rules_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0;
|
||||
i < ar_descr[object_index].positive_access_rules_count;
|
||||
i++) {
|
||||
len =
|
||||
bacapp_encode_access_rule(&apdu[0],
|
||||
&ar_descr[object_index].positive_access_rules[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
ar_descr[object_index].positive_access_rules_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_access_rule(&apdu[0],
|
||||
&ar_descr[object_index].
|
||||
positive_access_rules[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) &&
|
||||
(rpdata->object_property != PROP_NEGATIVE_ACCESS_RULES)
|
||||
&& (rpdata->object_property != PROP_POSITIVE_ACCESS_RULES)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Rights_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->object_property != PROP_NEGATIVE_ACCESS_RULES)
|
||||
&& (wp_data->object_property != PROP_POSITIVE_ACCESS_RULES)
|
||||
&& (wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index = Access_Rights_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
ar_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_RELIABILITY:
|
||||
case PROP_ENABLE:
|
||||
case PROP_NEGATIVE_ACCESS_RULES:
|
||||
case PROP_POSITIVE_ACCESS_RULES:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessRights(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_Rights_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_RIGHTS;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_Rights_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_RIGHTS
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access Rights", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessRights);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_RIGHTS */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access Rights Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_rights.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_Rights_Initialized = false;
|
||||
|
||||
static ACCESS_RIGHTS_DESCR ar_descr[MAX_ACCESS_RIGHTSS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_ENABLE,
|
||||
PROP_NEGATIVE_ACCESS_RULES,
|
||||
PROP_POSITIVE_ACCESS_RULES,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_Rights_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Rights_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_Rights_Initialized) {
|
||||
Access_Rights_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_RIGHTSS; i++) {
|
||||
ar_descr[i].global_identifier = 0; /* set to some meaningful value */
|
||||
ar_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
ar_descr[i].enable = false;
|
||||
ar_descr[i].negative_access_rules_count = 0;
|
||||
ar_descr[i].positive_access_rules_count = 0;
|
||||
/* fill in the positive and negative access rules with proper ids */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_Rights_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_RIGHTSS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Rights_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_RIGHTSS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_Rights_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_Rights_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_RIGHTSS;
|
||||
|
||||
if (object_instance < MAX_ACCESS_RIGHTSS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Rights_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_RIGHTSS) {
|
||||
sprintf(text_string, "ACCESS RIGHTS %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Rights_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index = Access_Rights_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ACCESS_RIGHTS,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_Rights_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_RIGHTS);
|
||||
break;
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ar_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
ar_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_ENABLE:
|
||||
apdu_len =
|
||||
encode_application_boolean(&apdu[0],
|
||||
ar_descr[object_index].enable);
|
||||
break;
|
||||
case PROP_NEGATIVE_ACCESS_RULES:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ar_descr[object_index].negative_access_rules_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0;
|
||||
i < ar_descr[object_index].negative_access_rules_count;
|
||||
i++) {
|
||||
len =
|
||||
bacapp_encode_access_rule(&apdu[0],
|
||||
&ar_descr[object_index].negative_access_rules[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
ar_descr[object_index].negative_access_rules_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_access_rule(&apdu[0],
|
||||
&ar_descr[object_index].
|
||||
negative_access_rules[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_POSITIVE_ACCESS_RULES:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
ar_descr[object_index].positive_access_rules_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0;
|
||||
i < ar_descr[object_index].positive_access_rules_count;
|
||||
i++) {
|
||||
len =
|
||||
bacapp_encode_access_rule(&apdu[0],
|
||||
&ar_descr[object_index].positive_access_rules[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
ar_descr[object_index].positive_access_rules_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_access_rule(&apdu[0],
|
||||
&ar_descr[object_index].
|
||||
positive_access_rules[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) &&
|
||||
(rpdata->object_property != PROP_NEGATIVE_ACCESS_RULES)
|
||||
&& (rpdata->object_property != PROP_POSITIVE_ACCESS_RULES)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Rights_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->object_property != PROP_NEGATIVE_ACCESS_RULES)
|
||||
&& (wp_data->object_property != PROP_POSITIVE_ACCESS_RULES)
|
||||
&& (wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index = Access_Rights_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
ar_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_RELIABILITY:
|
||||
case PROP_ENABLE:
|
||||
case PROP_NEGATIVE_ACCESS_RULES:
|
||||
case PROP_POSITIVE_ACCESS_RULES:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessRights(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_Rights_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_RIGHTS;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_Rights_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_RIGHTS
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access Rights", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessRights);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_RIGHTS */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,110 +1,110 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_RIGHTS_H
|
||||
#define ACCESS_RIGHTS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "access_rule.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_RIGHTSS
|
||||
#define MAX_ACCESS_RIGHTSS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_NEGATIVE_ACCESS_RIGHTS_RULES
|
||||
#define MAX_NEGATIVE_ACCESS_RIGHTS_RULES 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_POSITIVE_ACCESS_RIGHTS_RULES
|
||||
#define MAX_POSITIVE_ACCESS_RIGHTS_RULES 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
uint32_t global_identifier;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool enable;
|
||||
uint32_t negative_access_rules_count, positive_access_rules_count;
|
||||
BACNET_ACCESS_RULE
|
||||
negative_access_rules[MAX_NEGATIVE_ACCESS_RIGHTS_RULES];
|
||||
BACNET_ACCESS_RULE
|
||||
positive_access_rules[MAX_POSITIVE_ACCESS_RIGHTS_RULES];
|
||||
} ACCESS_RIGHTS_DESCR;
|
||||
|
||||
void Access_Rights_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Rights_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Rights_Count(
|
||||
void);
|
||||
uint32_t Access_Rights_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Rights_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Rights_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
bool Access_Rights_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Rights_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
int Access_Rights_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Rights_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Rights_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Rights_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Rights_Cleanup(
|
||||
void);
|
||||
void Access_Rights_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessRights(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_RIGHTS_H
|
||||
#define ACCESS_RIGHTS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "access_rule.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_RIGHTSS
|
||||
#define MAX_ACCESS_RIGHTSS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_NEGATIVE_ACCESS_RIGHTS_RULES
|
||||
#define MAX_NEGATIVE_ACCESS_RIGHTS_RULES 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_POSITIVE_ACCESS_RIGHTS_RULES
|
||||
#define MAX_POSITIVE_ACCESS_RIGHTS_RULES 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
uint32_t global_identifier;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool enable;
|
||||
uint32_t negative_access_rules_count, positive_access_rules_count;
|
||||
BACNET_ACCESS_RULE
|
||||
negative_access_rules[MAX_NEGATIVE_ACCESS_RIGHTS_RULES];
|
||||
BACNET_ACCESS_RULE
|
||||
positive_access_rules[MAX_POSITIVE_ACCESS_RIGHTS_RULES];
|
||||
} ACCESS_RIGHTS_DESCR;
|
||||
|
||||
void Access_Rights_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Rights_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Rights_Count(
|
||||
void);
|
||||
uint32_t Access_Rights_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Rights_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Rights_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
bool Access_Rights_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Rights_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
int Access_Rights_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Rights_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Rights_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Rights_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Rights_Cleanup(
|
||||
void);
|
||||
void Access_Rights_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessRights(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_RIGHTS
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_rights.c \
|
||||
$(SRC_DIR)/access_rule.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_rights
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_RIGHTS
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_rights.c \
|
||||
$(SRC_DIR)/access_rule.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_rights
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
@@ -1,373 +1,373 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access User Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_user.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_User_Initialized = false;
|
||||
|
||||
static ACCESS_USER_DESCR au_descr[MAX_ACCESS_USERS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_USER_TYPE,
|
||||
PROP_CREDENTIALS,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_User_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_User_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_User_Initialized) {
|
||||
Access_User_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_USERS; i++) {
|
||||
au_descr[i].global_identifier = 0; /* set to some meaningful value */
|
||||
au_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
au_descr[i].user_type = ACCESS_USER_TYPE_PERSON;
|
||||
au_descr[i].credentials_count = 0;
|
||||
/* fill in the credentials with proper ids */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_User_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_USERS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_User_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_USERS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_User_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_User_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_USERS;
|
||||
|
||||
if (object_instance < MAX_ACCESS_USERS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_User_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_USERS) {
|
||||
sprintf(text_string, "ACCESS USER %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_User_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index = Access_User_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ACCESS_USER,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_User_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_USER);
|
||||
break;
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
au_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
au_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_USER_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
au_descr[object_index].user_type);
|
||||
break;
|
||||
case PROP_CREDENTIALS:
|
||||
for (i = 0; i < au_descr[object_index].credentials_count; i++) {
|
||||
len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&au_descr[object_index].credentials[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_User_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index = Access_User_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
au_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_RELIABILITY:
|
||||
case PROP_USER_TYPE:
|
||||
case PROP_CREDENTIALS:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessUser(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_User_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_USER;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_User_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_USER
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access User", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessUser);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_USER */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access User Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_user.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_User_Initialized = false;
|
||||
|
||||
static ACCESS_USER_DESCR au_descr[MAX_ACCESS_USERS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_USER_TYPE,
|
||||
PROP_CREDENTIALS,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_User_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_User_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_User_Initialized) {
|
||||
Access_User_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_USERS; i++) {
|
||||
au_descr[i].global_identifier = 0; /* set to some meaningful value */
|
||||
au_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
au_descr[i].user_type = ACCESS_USER_TYPE_PERSON;
|
||||
au_descr[i].credentials_count = 0;
|
||||
/* fill in the credentials with proper ids */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_User_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_USERS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_User_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_USERS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_User_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_User_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_USERS;
|
||||
|
||||
if (object_instance < MAX_ACCESS_USERS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_User_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_USERS) {
|
||||
sprintf(text_string, "ACCESS USER %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_User_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index = Access_User_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ACCESS_USER,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_User_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_USER);
|
||||
break;
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
au_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
au_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_USER_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
au_descr[object_index].user_type);
|
||||
break;
|
||||
case PROP_CREDENTIALS:
|
||||
for (i = 0; i < au_descr[object_index].credentials_count; i++) {
|
||||
len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&au_descr[object_index].credentials[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_User_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index = Access_User_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
au_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_RELIABILITY:
|
||||
case PROP_USER_TYPE:
|
||||
case PROP_CREDENTIALS:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessUser(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_User_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_USER;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_User_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_USER
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access User", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessUser);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_USER */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,103 +1,103 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_USER_H
|
||||
#define ACCESS_USER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_USERS
|
||||
#define MAX_ACCESS_USERS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ACCESS_USER_CREDENTIALS_COUNT
|
||||
#define MAX_ACCESS_USER_CREDENTIALS_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
uint32_t global_identifier;
|
||||
BACNET_RELIABILITY reliability;
|
||||
BACNET_ACCESS_USER_TYPE user_type;
|
||||
uint32_t credentials_count;
|
||||
BACNET_DEVICE_OBJECT_REFERENCE
|
||||
credentials[MAX_ACCESS_USER_CREDENTIALS_COUNT];
|
||||
} ACCESS_USER_DESCR;
|
||||
|
||||
void Access_User_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_User_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_User_Count(
|
||||
void);
|
||||
uint32_t Access_User_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_User_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_User_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
bool Access_User_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_User_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
int Access_User_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_User_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_User_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_User_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_User_Cleanup(
|
||||
void);
|
||||
void Access_User_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessUser(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_USER_H
|
||||
#define ACCESS_USER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_USERS
|
||||
#define MAX_ACCESS_USERS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ACCESS_USER_CREDENTIALS_COUNT
|
||||
#define MAX_ACCESS_USER_CREDENTIALS_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
uint32_t global_identifier;
|
||||
BACNET_RELIABILITY reliability;
|
||||
BACNET_ACCESS_USER_TYPE user_type;
|
||||
uint32_t credentials_count;
|
||||
BACNET_DEVICE_OBJECT_REFERENCE
|
||||
credentials[MAX_ACCESS_USER_CREDENTIALS_COUNT];
|
||||
} ACCESS_USER_DESCR;
|
||||
|
||||
void Access_User_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_User_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_User_Count(
|
||||
void);
|
||||
uint32_t Access_User_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_User_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_User_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
bool Access_User_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_User_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
int Access_User_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_User_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_User_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_User_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_User_Cleanup(
|
||||
void);
|
||||
void Access_User_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessUser(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_USER
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_user.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_user
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_USER
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_user.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_user
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
@@ -1,446 +1,446 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access Zone Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_zone.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_Zone_Initialized = false;
|
||||
|
||||
static ACCESS_ZONE_DESCR az_descr[MAX_ACCESS_ZONES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_OCCUPANCY_STATE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_ENTRY_POINTS,
|
||||
PROP_EXIT_POINTS,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_Zone_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Zone_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_Zone_Initialized) {
|
||||
Access_Zone_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_ZONES; i++) {
|
||||
az_descr[i].global_identifier = 0; /* set to some meaningful value */
|
||||
az_descr[i].occupancy_state = ACCESS_ZONE_OCCUPANCY_STATE_DISABLED;
|
||||
az_descr[i].event_state = EVENT_STATE_NORMAL;
|
||||
az_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
az_descr[i].out_of_service = false;
|
||||
az_descr[i].entry_points_count = 0;
|
||||
az_descr[i].exit_points_count = 0;
|
||||
/* fill in the entry points and exit points with proper ids */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_Zone_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_ZONES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Zone_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_ZONES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_Zone_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_Zone_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_ZONES;
|
||||
|
||||
if (object_instance < MAX_ACCESS_ZONES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Zone_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_ZONES) {
|
||||
sprintf(text_string, "ACCESS ZONE %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Access_Zone_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
|
||||
index = Access_Zone_Instance_To_Index(instance);
|
||||
if (index < MAX_ACCESS_ZONES) {
|
||||
oos_flag = az_descr[index].out_of_service;
|
||||
}
|
||||
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Access_Zone_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
index = Access_Zone_Instance_To_Index(instance);
|
||||
if (index < MAX_ACCESS_ZONES) {
|
||||
az_descr[index].out_of_service = oos_flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Zone_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index = Access_Zone_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ACCESS_ZONE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_Zone_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_ZONE);
|
||||
break;
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
az_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_OCCUPANCY_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
az_descr[object_index].occupancy_state);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
state = Access_Zone_Out_Of_Service(rpdata->object_instance);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
az_descr[object_index].event_state);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
az_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = Access_Zone_Out_Of_Service(rpdata->object_instance);
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_ENTRY_POINTS:
|
||||
for (i = 0; i < az_descr[object_index].entry_points_count; i++) {
|
||||
len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&az_descr[object_index].entry_points[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_EXIT_POINTS:
|
||||
for (i = 0; i < az_descr[object_index].exit_points_count; i++) {
|
||||
len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&az_descr[object_index].exit_points[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Zone_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index = Access_Zone_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
az_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
}
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
if (Access_Zone_Out_Of_Service(wp_data->object_instance)) {
|
||||
status =
|
||||
WPValidateArgType(&value,
|
||||
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
az_descr[object_index].reliability = value.type.Enumerated;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_OCCUPANCY_STATE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_ENTRY_POINTS:
|
||||
case PROP_EXIT_POINTS:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessZone(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_Zone_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_ZONE;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_Zone_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_ZONE
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access Zone", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessZone);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_ZONE */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Access Zone Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "access_zone.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Access_Zone_Initialized = false;
|
||||
|
||||
static ACCESS_ZONE_DESCR az_descr[MAX_ACCESS_ZONES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_GLOBAL_IDENTIFIER,
|
||||
PROP_OCCUPANCY_STATE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_ENTRY_POINTS,
|
||||
PROP_EXIT_POINTS,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Access_Zone_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Access_Zone_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Access_Zone_Initialized) {
|
||||
Access_Zone_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_ACCESS_ZONES; i++) {
|
||||
az_descr[i].global_identifier = 0; /* set to some meaningful value */
|
||||
az_descr[i].occupancy_state = ACCESS_ZONE_OCCUPANCY_STATE_DISABLED;
|
||||
az_descr[i].event_state = EVENT_STATE_NORMAL;
|
||||
az_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
az_descr[i].out_of_service = false;
|
||||
az_descr[i].entry_points_count = 0;
|
||||
az_descr[i].exit_points_count = 0;
|
||||
/* fill in the entry points and exit points with proper ids */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Access_Zone_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ACCESS_ZONES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Access_Zone_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ACCESS_ZONES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Access_Zone_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Access_Zone_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ACCESS_ZONES;
|
||||
|
||||
if (object_instance < MAX_ACCESS_ZONES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Access_Zone_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ACCESS_ZONES) {
|
||||
sprintf(text_string, "ACCESS ZONE %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Access_Zone_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
|
||||
index = Access_Zone_Instance_To_Index(instance);
|
||||
if (index < MAX_ACCESS_ZONES) {
|
||||
oos_flag = az_descr[index].out_of_service;
|
||||
}
|
||||
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Access_Zone_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
index = Access_Zone_Instance_To_Index(instance);
|
||||
if (index < MAX_ACCESS_ZONES) {
|
||||
az_descr[index].out_of_service = oos_flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Access_Zone_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index = Access_Zone_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ACCESS_ZONE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Access_Zone_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ACCESS_ZONE);
|
||||
break;
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
az_descr[object_index].global_identifier);
|
||||
break;
|
||||
case PROP_OCCUPANCY_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
az_descr[object_index].occupancy_state);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
state = Access_Zone_Out_Of_Service(rpdata->object_instance);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
az_descr[object_index].event_state);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
az_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = Access_Zone_Out_Of_Service(rpdata->object_instance);
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_ENTRY_POINTS:
|
||||
for (i = 0; i < az_descr[object_index].entry_points_count; i++) {
|
||||
len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&az_descr[object_index].entry_points[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_EXIT_POINTS:
|
||||
for (i = 0; i < az_descr[object_index].exit_points_count; i++) {
|
||||
len =
|
||||
bacapp_encode_device_obj_ref(&apdu[0],
|
||||
&az_descr[object_index].exit_points[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Access_Zone_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index = Access_Zone_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_GLOBAL_IDENTIFIER:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
az_descr[object_index].global_identifier =
|
||||
value.type.Unsigned_Int;
|
||||
}
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
if (Access_Zone_Out_Of_Service(wp_data->object_instance)) {
|
||||
status =
|
||||
WPValidateArgType(&value,
|
||||
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
az_descr[object_index].reliability = value.type.Enumerated;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_OCCUPANCY_STATE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_ENTRY_POINTS:
|
||||
case PROP_EXIT_POINTS:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testAccessZone(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Access_Zone_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_ACCESS_ZONE;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Access_Zone_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ACCESS_ZONE
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Access Zone", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAccessZone);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ACCESS_ZONE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,117 +1,117 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_ZONE_H
|
||||
#define ACCESS_ZONE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_ZONES
|
||||
#define MAX_ACCESS_ZONES 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ACCESS_ZONE_ENTRY_POINTS
|
||||
#define MAX_ACCESS_ZONE_ENTRY_POINTS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ACCESS_ZONE_EXIT_POINTS
|
||||
#define MAX_ACCESS_ZONE_EXIT_POINTS 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
uint32_t global_identifier;
|
||||
BACNET_ACCESS_ZONE_OCCUPANCY_STATE occupancy_state;
|
||||
BACNET_EVENT_STATE event_state;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool out_of_service;
|
||||
uint32_t entry_points_count, exit_points_count;
|
||||
BACNET_DEVICE_OBJECT_REFERENCE
|
||||
entry_points[MAX_ACCESS_ZONE_ENTRY_POINTS];
|
||||
BACNET_DEVICE_OBJECT_REFERENCE
|
||||
exit_points[MAX_ACCESS_ZONE_EXIT_POINTS];
|
||||
} ACCESS_ZONE_DESCR;
|
||||
|
||||
void Access_Zone_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Zone_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Zone_Count(
|
||||
void);
|
||||
uint32_t Access_Zone_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Zone_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Zone_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
bool Access_Zone_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Zone_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
bool Access_Zone_Out_Of_Service(
|
||||
uint32_t instance);
|
||||
void Access_Zone_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
int Access_Zone_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Zone_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Zone_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Zone_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Zone_Cleanup(
|
||||
void);
|
||||
void Access_Zone_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessZone(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ACCESS_ZONE_H
|
||||
#define ACCESS_ZONE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_ACCESS_ZONES
|
||||
#define MAX_ACCESS_ZONES 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ACCESS_ZONE_ENTRY_POINTS
|
||||
#define MAX_ACCESS_ZONE_ENTRY_POINTS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_ACCESS_ZONE_EXIT_POINTS
|
||||
#define MAX_ACCESS_ZONE_EXIT_POINTS 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
uint32_t global_identifier;
|
||||
BACNET_ACCESS_ZONE_OCCUPANCY_STATE occupancy_state;
|
||||
BACNET_EVENT_STATE event_state;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool out_of_service;
|
||||
uint32_t entry_points_count, exit_points_count;
|
||||
BACNET_DEVICE_OBJECT_REFERENCE
|
||||
entry_points[MAX_ACCESS_ZONE_ENTRY_POINTS];
|
||||
BACNET_DEVICE_OBJECT_REFERENCE
|
||||
exit_points[MAX_ACCESS_ZONE_EXIT_POINTS];
|
||||
} ACCESS_ZONE_DESCR;
|
||||
|
||||
void Access_Zone_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Access_Zone_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Access_Zone_Count(
|
||||
void);
|
||||
uint32_t Access_Zone_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Access_Zone_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Access_Zone_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
bool Access_Zone_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Access_Zone_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
bool Access_Zone_Out_Of_Service(
|
||||
uint32_t instance);
|
||||
void Access_Zone_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
int Access_Zone_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Access_Zone_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Access_Zone_Create(
|
||||
uint32_t object_instance);
|
||||
bool Access_Zone_Delete(
|
||||
uint32_t object_instance);
|
||||
void Access_Zone_Cleanup(
|
||||
void);
|
||||
void Access_Zone_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAccessZone(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_ZONE
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_zone.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_zone
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_ACCESS_ZONE
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = access_zone.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = access_zone
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
+1709
-1709
File diff suppressed because it is too large
Load Diff
+203
-203
@@ -1,203 +1,203 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Steve Karg
|
||||
* @date 2013
|
||||
* @brief Channel objects, customize for your use
|
||||
*
|
||||
* @section DESCRIPTION
|
||||
*
|
||||
* The Channel object is a command object without a priority array, and the
|
||||
* present-value property uses a priority array and a single precision floating point
|
||||
* data type.
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef CHANNEL_H
|
||||
#define CHANNEL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "lo.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* BACNET_CHANNEL_VALUE decodes WriteProperty service requests
|
||||
Choose the datatypes that your application supports */
|
||||
#if !(defined(CHANNEL_NUMERIC) || \
|
||||
defined(CHANNEL_NULL) || \
|
||||
defined(CHANNEL_BOOLEAN) || \
|
||||
defined(CHANNEL_UNSIGNED) || \
|
||||
defined(CHANNEL_SIGNED) || \
|
||||
defined(CHANNEL_REAL) || \
|
||||
defined(CHANNEL_DOUBLE) || \
|
||||
defined(CHANNEL_OCTET_STRING) || \
|
||||
defined(CHANNEL_CHARACTER_STRING) || \
|
||||
defined(CHANNEL_BIT_STRING) || \
|
||||
defined(CHANNEL_ENUMERATED) || \
|
||||
defined(CHANNEL_DATE) || \
|
||||
defined(CHANNEL_TIME) || \
|
||||
defined(CHANNEL_OBJECT_ID) || \
|
||||
defined(CHANNEL_LIGHTING_COMMAND))
|
||||
#define CHANNEL_NUMERIC
|
||||
#endif
|
||||
|
||||
#if defined (CHANNEL_NUMERIC)
|
||||
#define CHANNEL_NULL
|
||||
#define CHANNEL_BOOLEAN
|
||||
#define CHANNEL_UNSIGNED
|
||||
#define CHANNEL_SIGNED
|
||||
#define CHANNEL_REAL
|
||||
#define CHANNEL_DOUBLE
|
||||
#define CHANNEL_ENUMERATED
|
||||
#define CHANNEL_LIGHTING_COMMAND
|
||||
#endif
|
||||
|
||||
typedef struct BACnet_Channel_Value_t {
|
||||
uint8_t tag;
|
||||
union {
|
||||
/* NULL - not needed as it is encoded in the tag alone */
|
||||
#if defined (CHANNEL_BOOLEAN)
|
||||
bool Boolean;
|
||||
#endif
|
||||
#if defined (CHANNEL_UNSIGNED)
|
||||
uint32_t Unsigned_Int;
|
||||
#endif
|
||||
#if defined (CHANNEL_SIGNED)
|
||||
int32_t Signed_Int;
|
||||
#endif
|
||||
#if defined (CHANNEL_REAL)
|
||||
float Real;
|
||||
#endif
|
||||
#if defined (CHANNEL_DOUBLE)
|
||||
double Double;
|
||||
#endif
|
||||
#if defined (CHANNEL_OCTET_STRING)
|
||||
BACNET_OCTET_STRING Octet_String;
|
||||
#endif
|
||||
#if defined (CHANNEL_CHARACTER_STRING)
|
||||
BACNET_CHARACTER_STRING Character_String;
|
||||
#endif
|
||||
#if defined (CHANNEL_BIT_STRING)
|
||||
BACNET_BIT_STRING Bit_String;
|
||||
#endif
|
||||
#if defined (CHANNEL_ENUMERATED)
|
||||
uint32_t Enumerated;
|
||||
#endif
|
||||
#if defined (CHANNEL_DATE)
|
||||
BACNET_DATE Date;
|
||||
#endif
|
||||
#if defined (CHANNEL_TIME)
|
||||
BACNET_TIME Time;
|
||||
#endif
|
||||
#if defined (CHANNEL_OBJECT_ID)
|
||||
BACNET_OBJECT_ID Object_Id;
|
||||
#endif
|
||||
#if defined (CHANNEL_LIGHTING_COMMAND)
|
||||
BACNET_LIGHTING_COMMAND Lighting_Command;
|
||||
#endif
|
||||
} type;
|
||||
/* simple linked list if needed */
|
||||
struct BACnet_Channel_Value_t *next;
|
||||
} BACNET_CHANNEL_VALUE;
|
||||
|
||||
void Channel_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Channel_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Channel_Count(void);
|
||||
uint32_t Channel_Index_To_Instance(unsigned index);
|
||||
unsigned Channel_Instance_To_Index(uint32_t instance);
|
||||
bool Channel_Object_Instance_Add(uint32_t instance);
|
||||
|
||||
bool Channel_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Channel_Name_Set(uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
int Channel_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Channel_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
BACNET_CHANNEL_VALUE * Channel_Present_Value(uint32_t object_instance);
|
||||
bool Channel_Present_Value_Set(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
bool Channel_Out_Of_Service(uint32_t object_instance);
|
||||
void Channel_Out_Of_Service_Set(uint32_t object_instance,
|
||||
bool oos_flag);
|
||||
|
||||
unsigned Channel_Last_Priority(uint32_t object_instance);
|
||||
BACNET_WRITE_STATUS Channel_Write_Status(uint32_t object_instance);
|
||||
uint16_t Channel_Number(uint32_t object_instance);
|
||||
bool Channel_Number_Set(uint32_t object_instance, uint16_t value);
|
||||
|
||||
unsigned Channel_Reference_List_Member_Count(uint32_t object_instance);
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *
|
||||
Channel_Reference_List_Member_Element(uint32_t object_instance,
|
||||
unsigned element);
|
||||
bool Channel_Reference_List_Member_Element_Set(uint32_t object_instance,
|
||||
unsigned array_index,
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMemberSrc);
|
||||
unsigned Channel_Reference_List_Member_Element_Add(uint32_t object_instance,
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMemberSrc);
|
||||
unsigned Channel_Reference_List_Member_Local_Add(
|
||||
uint32_t object_instance,
|
||||
uint16_t type,
|
||||
uint32_t instance,
|
||||
BACNET_PROPERTY_ID propertyIdentifier,
|
||||
uint32_t arrayIndex);
|
||||
uint16_t Channel_Control_Groups_Element(
|
||||
uint32_t object_instance,
|
||||
int32_t array_index);
|
||||
bool Channel_Control_Groups_Element_Set(
|
||||
uint32_t object_instance,
|
||||
int32_t array_index,
|
||||
uint16_t value);
|
||||
bool Channel_Value_Copy(BACNET_CHANNEL_VALUE * cvalue,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
int Channel_Value_Encode(uint8_t *apdu, int apdu_max,
|
||||
BACNET_CHANNEL_VALUE * value);
|
||||
int Channel_Coerce_Data_Encode(
|
||||
uint8_t * apdu,
|
||||
unsigned max_apdu,
|
||||
BACNET_APPLICATION_DATA_VALUE * value,
|
||||
BACNET_APPLICATION_TAG tag);
|
||||
bool Channel_Write_Member_Value(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
void Channel_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testChannelObject(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**
|
||||
* @file
|
||||
* @author Steve Karg
|
||||
* @date 2013
|
||||
* @brief Channel objects, customize for your use
|
||||
*
|
||||
* @section DESCRIPTION
|
||||
*
|
||||
* The Channel object is a command object without a priority array, and the
|
||||
* present-value property uses a priority array and a single precision floating point
|
||||
* data type.
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef CHANNEL_H
|
||||
#define CHANNEL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
#include "lo.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* BACNET_CHANNEL_VALUE decodes WriteProperty service requests
|
||||
Choose the datatypes that your application supports */
|
||||
#if !(defined(CHANNEL_NUMERIC) || \
|
||||
defined(CHANNEL_NULL) || \
|
||||
defined(CHANNEL_BOOLEAN) || \
|
||||
defined(CHANNEL_UNSIGNED) || \
|
||||
defined(CHANNEL_SIGNED) || \
|
||||
defined(CHANNEL_REAL) || \
|
||||
defined(CHANNEL_DOUBLE) || \
|
||||
defined(CHANNEL_OCTET_STRING) || \
|
||||
defined(CHANNEL_CHARACTER_STRING) || \
|
||||
defined(CHANNEL_BIT_STRING) || \
|
||||
defined(CHANNEL_ENUMERATED) || \
|
||||
defined(CHANNEL_DATE) || \
|
||||
defined(CHANNEL_TIME) || \
|
||||
defined(CHANNEL_OBJECT_ID) || \
|
||||
defined(CHANNEL_LIGHTING_COMMAND))
|
||||
#define CHANNEL_NUMERIC
|
||||
#endif
|
||||
|
||||
#if defined (CHANNEL_NUMERIC)
|
||||
#define CHANNEL_NULL
|
||||
#define CHANNEL_BOOLEAN
|
||||
#define CHANNEL_UNSIGNED
|
||||
#define CHANNEL_SIGNED
|
||||
#define CHANNEL_REAL
|
||||
#define CHANNEL_DOUBLE
|
||||
#define CHANNEL_ENUMERATED
|
||||
#define CHANNEL_LIGHTING_COMMAND
|
||||
#endif
|
||||
|
||||
typedef struct BACnet_Channel_Value_t {
|
||||
uint8_t tag;
|
||||
union {
|
||||
/* NULL - not needed as it is encoded in the tag alone */
|
||||
#if defined (CHANNEL_BOOLEAN)
|
||||
bool Boolean;
|
||||
#endif
|
||||
#if defined (CHANNEL_UNSIGNED)
|
||||
uint32_t Unsigned_Int;
|
||||
#endif
|
||||
#if defined (CHANNEL_SIGNED)
|
||||
int32_t Signed_Int;
|
||||
#endif
|
||||
#if defined (CHANNEL_REAL)
|
||||
float Real;
|
||||
#endif
|
||||
#if defined (CHANNEL_DOUBLE)
|
||||
double Double;
|
||||
#endif
|
||||
#if defined (CHANNEL_OCTET_STRING)
|
||||
BACNET_OCTET_STRING Octet_String;
|
||||
#endif
|
||||
#if defined (CHANNEL_CHARACTER_STRING)
|
||||
BACNET_CHARACTER_STRING Character_String;
|
||||
#endif
|
||||
#if defined (CHANNEL_BIT_STRING)
|
||||
BACNET_BIT_STRING Bit_String;
|
||||
#endif
|
||||
#if defined (CHANNEL_ENUMERATED)
|
||||
uint32_t Enumerated;
|
||||
#endif
|
||||
#if defined (CHANNEL_DATE)
|
||||
BACNET_DATE Date;
|
||||
#endif
|
||||
#if defined (CHANNEL_TIME)
|
||||
BACNET_TIME Time;
|
||||
#endif
|
||||
#if defined (CHANNEL_OBJECT_ID)
|
||||
BACNET_OBJECT_ID Object_Id;
|
||||
#endif
|
||||
#if defined (CHANNEL_LIGHTING_COMMAND)
|
||||
BACNET_LIGHTING_COMMAND Lighting_Command;
|
||||
#endif
|
||||
} type;
|
||||
/* simple linked list if needed */
|
||||
struct BACnet_Channel_Value_t *next;
|
||||
} BACNET_CHANNEL_VALUE;
|
||||
|
||||
void Channel_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Channel_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Channel_Count(void);
|
||||
uint32_t Channel_Index_To_Instance(unsigned index);
|
||||
unsigned Channel_Instance_To_Index(uint32_t instance);
|
||||
bool Channel_Object_Instance_Add(uint32_t instance);
|
||||
|
||||
bool Channel_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Channel_Name_Set(uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
int Channel_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Channel_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
BACNET_CHANNEL_VALUE * Channel_Present_Value(uint32_t object_instance);
|
||||
bool Channel_Present_Value_Set(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
bool Channel_Out_Of_Service(uint32_t object_instance);
|
||||
void Channel_Out_Of_Service_Set(uint32_t object_instance,
|
||||
bool oos_flag);
|
||||
|
||||
unsigned Channel_Last_Priority(uint32_t object_instance);
|
||||
BACNET_WRITE_STATUS Channel_Write_Status(uint32_t object_instance);
|
||||
uint16_t Channel_Number(uint32_t object_instance);
|
||||
bool Channel_Number_Set(uint32_t object_instance, uint16_t value);
|
||||
|
||||
unsigned Channel_Reference_List_Member_Count(uint32_t object_instance);
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *
|
||||
Channel_Reference_List_Member_Element(uint32_t object_instance,
|
||||
unsigned element);
|
||||
bool Channel_Reference_List_Member_Element_Set(uint32_t object_instance,
|
||||
unsigned array_index,
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMemberSrc);
|
||||
unsigned Channel_Reference_List_Member_Element_Add(uint32_t object_instance,
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *pMemberSrc);
|
||||
unsigned Channel_Reference_List_Member_Local_Add(
|
||||
uint32_t object_instance,
|
||||
uint16_t type,
|
||||
uint32_t instance,
|
||||
BACNET_PROPERTY_ID propertyIdentifier,
|
||||
uint32_t arrayIndex);
|
||||
uint16_t Channel_Control_Groups_Element(
|
||||
uint32_t object_instance,
|
||||
int32_t array_index);
|
||||
bool Channel_Control_Groups_Element_Set(
|
||||
uint32_t object_instance,
|
||||
int32_t array_index,
|
||||
uint16_t value);
|
||||
bool Channel_Value_Copy(BACNET_CHANNEL_VALUE * cvalue,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
int Channel_Value_Encode(uint8_t *apdu, int apdu_max,
|
||||
BACNET_CHANNEL_VALUE * value);
|
||||
int Channel_Coerce_Data_Encode(
|
||||
uint8_t * apdu,
|
||||
unsigned max_apdu,
|
||||
BACNET_APPLICATION_DATA_VALUE * value,
|
||||
BACNET_APPLICATION_TAG tag);
|
||||
bool Channel_Write_Member_Value(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_APPLICATION_DATA_VALUE * value);
|
||||
|
||||
void Channel_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testChannelObject(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,462 +1,462 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Credential Data Input Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "credential_data_input.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Credential_Data_Input_Initialized = false;
|
||||
|
||||
static CREDENTIAL_DATA_INPUT_DESCR cdi_descr[MAX_CREDENTIAL_DATA_INPUTS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_SUPPORTED_FORMATS,
|
||||
PROP_UPDATE_TIME,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Credential_Data_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Credential_Data_Input_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Credential_Data_Input_Initialized) {
|
||||
Credential_Data_Input_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_CREDENTIAL_DATA_INPUTS; i++) {
|
||||
/* there should be a meaningful setup for present value */
|
||||
cdi_descr[i].present_value.format_type =
|
||||
AUTHENTICATION_FACTOR_UNDEFINED;
|
||||
cdi_descr[i].present_value.format_class = 0;
|
||||
octetstring_init(&cdi_descr[i].present_value.value, NULL, 0);
|
||||
cdi_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
cdi_descr[i].out_of_service = false;
|
||||
/* set supported formats */
|
||||
cdi_descr[i].supported_formats_count = 0;
|
||||
/* timestamp uninitialized */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Credential_Data_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Credential_Data_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_CREDENTIAL_DATA_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Credential_Data_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Credential_Data_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_CREDENTIAL_DATA_INPUTS;
|
||||
|
||||
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Credential_Data_Input_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS) {
|
||||
sprintf(text_string, "CREDENTIAL DATA INPUT %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Credential_Data_Input_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
|
||||
index = Credential_Data_Input_Instance_To_Index(instance);
|
||||
if (index < MAX_CREDENTIAL_DATA_INPUTS) {
|
||||
oos_flag = cdi_descr[index].out_of_service;
|
||||
}
|
||||
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Credential_Data_Input_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
index = Credential_Data_Input_Instance_To_Index(instance);
|
||||
if (index < MAX_CREDENTIAL_DATA_INPUTS) {
|
||||
cdi_descr[index].out_of_service = oos_flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Credential_Data_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index =
|
||||
Credential_Data_Input_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_CREDENTIAL_DATA_INPUT, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Credential_Data_Input_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_CREDENTIAL_DATA_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
bacapp_encode_authentication_factor(&apdu[apdu_len],
|
||||
&cdi_descr[object_index].present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
state =
|
||||
Credential_Data_Input_Out_Of_Service(rpdata->object_instance);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
cdi_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state =
|
||||
Credential_Data_Input_Out_Of_Service(rpdata->object_instance);
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
cdi_descr[object_index].supported_formats_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0; i < cdi_descr[object_index].supported_formats_count;
|
||||
i++) {
|
||||
len =
|
||||
bacapp_encode_authentication_factor_format(&apdu[0],
|
||||
&cdi_descr[object_index].supported_formats[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
cdi_descr[object_index].supported_formats_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_authentication_factor_format(&apdu[0],
|
||||
&cdi_descr[object_index].
|
||||
supported_formats[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PROP_UPDATE_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_timestamp(&apdu[0],
|
||||
&cdi_descr[object_index].timestamp);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_SUPPORTED_FORMATS)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Credential_Data_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->object_property != PROP_SUPPORTED_FORMATS) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index = Credential_Data_Input_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (Credential_Data_Input_Out_Of_Service(wp_data->object_instance)) {
|
||||
BACNET_AUTHENTICATION_FACTOR tmp;
|
||||
len =
|
||||
bacapp_decode_authentication_factor(wp_data->
|
||||
application_data, &tmp);
|
||||
if (len > 0) {
|
||||
memcpy(&cdi_descr[object_index].present_value, &tmp,
|
||||
sizeof(BACNET_AUTHENTICATION_FACTOR));
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
}
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
if (Credential_Data_Input_Out_Of_Service(wp_data->object_instance)) {
|
||||
status =
|
||||
WPValidateArgType(&value,
|
||||
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
cdi_descr[object_index].reliability =
|
||||
value.type.Enumerated;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
case PROP_UPDATE_TIME:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testCredentialDataInput(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Credential_Data_Input_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_CREDENTIAL_DATA_INPUT;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Credential_Data_Input_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_CREDENTIAL_DATA_INPUT
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Credential Data Input", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testCredentialDataInput);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_CREDENTIAL_DATA_INPUT */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Credential Data Input Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "credential_data_input.h"
|
||||
#include "handlers.h"
|
||||
|
||||
static bool Credential_Data_Input_Initialized = false;
|
||||
|
||||
static CREDENTIAL_DATA_INPUT_DESCR cdi_descr[MAX_CREDENTIAL_DATA_INPUTS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_SUPPORTED_FORMATS,
|
||||
PROP_UPDATE_TIME,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Optional[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Credential_Data_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Credential_Data_Input_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Credential_Data_Input_Initialized) {
|
||||
Credential_Data_Input_Initialized = true;
|
||||
|
||||
for (i = 0; i < MAX_CREDENTIAL_DATA_INPUTS; i++) {
|
||||
/* there should be a meaningful setup for present value */
|
||||
cdi_descr[i].present_value.format_type =
|
||||
AUTHENTICATION_FACTOR_UNDEFINED;
|
||||
cdi_descr[i].present_value.format_class = 0;
|
||||
octetstring_init(&cdi_descr[i].present_value.value, NULL, 0);
|
||||
cdi_descr[i].reliability = RELIABILITY_NO_FAULT_DETECTED;
|
||||
cdi_descr[i].out_of_service = false;
|
||||
/* set supported formats */
|
||||
cdi_descr[i].supported_formats_count = 0;
|
||||
/* timestamp uninitialized */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Credential_Data_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Credential_Data_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_CREDENTIAL_DATA_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Credential_Data_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Credential_Data_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_CREDENTIAL_DATA_INPUTS;
|
||||
|
||||
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Credential_Data_Input_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_CREDENTIAL_DATA_INPUTS) {
|
||||
sprintf(text_string, "CREDENTIAL DATA INPUT %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Credential_Data_Input_Out_Of_Service(
|
||||
uint32_t instance)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool oos_flag = false;
|
||||
|
||||
index = Credential_Data_Input_Instance_To_Index(instance);
|
||||
if (index < MAX_CREDENTIAL_DATA_INPUTS) {
|
||||
oos_flag = cdi_descr[index].out_of_service;
|
||||
}
|
||||
|
||||
return oos_flag;
|
||||
}
|
||||
|
||||
void Credential_Data_Input_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
index = Credential_Data_Input_Instance_To_Index(instance);
|
||||
if (index < MAX_CREDENTIAL_DATA_INPUTS) {
|
||||
cdi_descr[index].out_of_service = oos_flag;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int Credential_Data_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
object_index =
|
||||
Credential_Data_Input_Instance_To_Index(rpdata->object_instance);
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_CREDENTIAL_DATA_INPUT, rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Credential_Data_Input_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_CREDENTIAL_DATA_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
bacapp_encode_authentication_factor(&apdu[apdu_len],
|
||||
&cdi_descr[object_index].present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
state =
|
||||
Credential_Data_Input_Out_Of_Service(rpdata->object_instance);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
cdi_descr[object_index].reliability);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state =
|
||||
Credential_Data_Input_Out_Of_Service(rpdata->object_instance);
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
if (rpdata->array_index == 0) {
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
cdi_descr[object_index].supported_formats_count);
|
||||
} else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 0; i < cdi_descr[object_index].supported_formats_count;
|
||||
i++) {
|
||||
len =
|
||||
bacapp_encode_authentication_factor_format(&apdu[0],
|
||||
&cdi_descr[object_index].supported_formats[i]);
|
||||
if (apdu_len + len < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rpdata->array_index <=
|
||||
cdi_descr[object_index].supported_formats_count) {
|
||||
apdu_len =
|
||||
bacapp_encode_authentication_factor_format(&apdu[0],
|
||||
&cdi_descr[object_index].
|
||||
supported_formats[rpdata->array_index - 1]);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PROP_UPDATE_TIME:
|
||||
apdu_len =
|
||||
bacapp_encode_timestamp(&apdu[0],
|
||||
&cdi_descr[object_index].timestamp);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_SUPPORTED_FORMATS)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Credential_Data_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
unsigned object_index = 0;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((wp_data->object_property != PROP_SUPPORTED_FORMATS) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index = Credential_Data_Input_Instance_To_Index(wp_data->object_instance);
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (Credential_Data_Input_Out_Of_Service(wp_data->object_instance)) {
|
||||
BACNET_AUTHENTICATION_FACTOR tmp;
|
||||
len =
|
||||
bacapp_decode_authentication_factor(wp_data->
|
||||
application_data, &tmp);
|
||||
if (len > 0) {
|
||||
memcpy(&cdi_descr[object_index].present_value, &tmp,
|
||||
sizeof(BACNET_AUTHENTICATION_FACTOR));
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
}
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
if (Credential_Data_Input_Out_Of_Service(wp_data->object_instance)) {
|
||||
status =
|
||||
WPValidateArgType(&value,
|
||||
BACNET_APPLICATION_TAG_ENUMERATED, &wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
if (status) {
|
||||
cdi_descr[object_index].reliability =
|
||||
value.type.Enumerated;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_SUPPORTED_FORMATS:
|
||||
case PROP_UPDATE_TIME:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(
|
||||
BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testCredentialDataInput(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
|
||||
Credential_Data_Input_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_CREDENTIAL_DATA_INPUT;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Credential_Data_Input_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_CREDENTIAL_DATA_INPUT
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Credential Data Input", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testCredentialDataInput);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_CREDENTIAL_DATA_INPUT */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,116 +1,116 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef CREDENTIAL_DATA_INPUT_H
|
||||
#define CREDENTIAL_DATA_INPUT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "timestamp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "authentication_factor.h"
|
||||
#include "authentication_factor_format.h"
|
||||
#include "timestamp.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_CREDENTIAL_DATA_INPUTS
|
||||
#define MAX_CREDENTIAL_DATA_INPUTS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT
|
||||
#define MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
BACNET_AUTHENTICATION_FACTOR present_value;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool out_of_service;
|
||||
uint32_t supported_formats_count;
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT
|
||||
supported_formats[MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT];
|
||||
BACNET_TIMESTAMP timestamp;
|
||||
} CREDENTIAL_DATA_INPUT_DESCR;
|
||||
|
||||
void Credential_Data_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Credential_Data_Input_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Credential_Data_Input_Count(
|
||||
void);
|
||||
uint32_t Credential_Data_Input_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Credential_Data_Input_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Credential_Data_Input_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
|
||||
bool Credential_Data_Input_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Credential_Data_Input_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
|
||||
bool Credential_Data_Input_Out_Of_Service(
|
||||
uint32_t instance);
|
||||
void Credential_Data_Input_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
int Credential_Data_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Credential_Data_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Credential_Data_Input_Create(
|
||||
uint32_t object_instance);
|
||||
bool Credential_Data_Input_Delete(
|
||||
uint32_t object_instance);
|
||||
void Credential_Data_Input_Cleanup(
|
||||
void);
|
||||
void Credential_Data_Input_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testCredentialDataInput(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef CREDENTIAL_DATA_INPUT_H
|
||||
#define CREDENTIAL_DATA_INPUT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "timestamp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "authentication_factor.h"
|
||||
#include "authentication_factor_format.h"
|
||||
#include "timestamp.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
|
||||
#ifndef MAX_CREDENTIAL_DATA_INPUTS
|
||||
#define MAX_CREDENTIAL_DATA_INPUTS 4
|
||||
#endif
|
||||
|
||||
#ifndef MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT
|
||||
#define MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct {
|
||||
BACNET_AUTHENTICATION_FACTOR present_value;
|
||||
BACNET_RELIABILITY reliability;
|
||||
bool out_of_service;
|
||||
uint32_t supported_formats_count;
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT
|
||||
supported_formats[MAX_AUTHENTICATION_FACTOR_FORMAT_COUNT];
|
||||
BACNET_TIMESTAMP timestamp;
|
||||
} CREDENTIAL_DATA_INPUT_DESCR;
|
||||
|
||||
void Credential_Data_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Credential_Data_Input_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Credential_Data_Input_Count(
|
||||
void);
|
||||
uint32_t Credential_Data_Input_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Credential_Data_Input_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Credential_Data_Input_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
|
||||
bool Credential_Data_Input_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Credential_Data_Input_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
|
||||
bool Credential_Data_Input_Out_Of_Service(
|
||||
uint32_t instance);
|
||||
void Credential_Data_Input_Out_Of_Service_Set(
|
||||
uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
int Credential_Data_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Credential_Data_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool Credential_Data_Input_Create(
|
||||
uint32_t object_instance);
|
||||
bool Credential_Data_Input_Delete(
|
||||
uint32_t object_instance);
|
||||
void Credential_Data_Input_Cleanup(
|
||||
void);
|
||||
void Credential_Data_Input_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testCredentialDataInput(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_CREDENTIAL_DATA_INPUT
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = credential_data_input.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(SRC_DIR)/authentication_factor.c \
|
||||
$(SRC_DIR)/authentication_factor_format.c \
|
||||
$(SRC_DIR)/timestamp.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = credential_data_input
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_CREDENTIAL_DATA_INPUT
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = credential_data_input.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(SRC_DIR)/authentication_factor.c \
|
||||
$(SRC_DIR)/authentication_factor_format.c \
|
||||
$(SRC_DIR)/timestamp.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = credential_data_input
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
+438
-438
@@ -1,438 +1,438 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* OctetString Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "osv.h"
|
||||
|
||||
|
||||
#ifndef MAX_OCTETSTRING_VALUES
|
||||
#define MAX_OCTETSTRING_VALUES 4
|
||||
#endif
|
||||
|
||||
OCTETSTRING_VALUE_DESCR AV_Descr[MAX_OCTETSTRING_VALUES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int OctetString_Value_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int OctetString_Value_Properties_Optional[] = {
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int OctetString_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void OctetString_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = OctetString_Value_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = OctetString_Value_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = OctetString_Value_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void OctetString_Value_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_OCTETSTRING_VALUES; i++) {
|
||||
memset(&AV_Descr[i], 0x00, sizeof(OCTETSTRING_VALUE_DESCR));
|
||||
octetstring_init(&AV_Descr[i].Present_Value, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool OctetString_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_OCTETSTRING_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned OctetString_Value_Count(void)
|
||||
{
|
||||
return MAX_OCTETSTRING_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t OctetString_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_OCTETSTRING_VALUES;
|
||||
|
||||
if (object_instance < MAX_OCTETSTRING_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given object instance-number, sets the present-value at a given
|
||||
* priority 1..16.
|
||||
*
|
||||
* @param object_instance - object-instance number of the object
|
||||
* @param value - octetstring value
|
||||
* @param priority - priority 1..16
|
||||
*
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
|
||||
BACNET_OCTET_STRING * value,
|
||||
uint8_t priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
|
||||
index = OctetString_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_OCTETSTRING_VALUES) {
|
||||
octetstring_copy(&AV_Descr[index].Present_Value, value);
|
||||
status = true;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
BACNET_OCTET_STRING *value = NULL;
|
||||
unsigned index = 0;
|
||||
|
||||
index = OctetString_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_OCTETSTRING_VALUES) {
|
||||
value = &AV_Descr[index].Present_Value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool OctetString_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_OCTETSTRING_VALUES) {
|
||||
sprintf(text_string, "OCTETSTRING VALUE %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_OCTET_STRING *real_value = NULL;
|
||||
unsigned object_index = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
OCTETSTRING_VALUE_DESCR *CurrentAV;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
|
||||
object_index =
|
||||
OctetString_Value_Instance_To_Index(rpdata->object_instance);
|
||||
if (object_index < MAX_OCTETSTRING_VALUES)
|
||||
CurrentAV = &AV_Descr[object_index];
|
||||
else
|
||||
return BACNET_STATUS_ERROR;
|
||||
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_OCTETSTRING_VALUE, rpdata->object_instance);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
OctetString_Value_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_OCTETSTRING_VALUE);
|
||||
break;
|
||||
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value =
|
||||
OctetString_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_octet_string(&apdu[0], real_value);
|
||||
break;
|
||||
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
CurrentAV->Out_Of_Service);
|
||||
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = CurrentAV->Out_Of_Service;
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
OCTETSTRING_VALUE_DESCR *CurrentAV;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index =
|
||||
OctetString_Value_Instance_To_Index(wp_data->object_instance);
|
||||
if (object_index < MAX_OCTETSTRING_VALUES)
|
||||
CurrentAV = &AV_Descr[object_index];
|
||||
else
|
||||
return false;
|
||||
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OCTET_STRING) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (OctetString_Value_Present_Value_Set(wp_data->
|
||||
object_instance, &value.type.Octet_String,
|
||||
wp_data->priority)) {
|
||||
status = true;
|
||||
} else if (wp_data->priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
CurrentAV->Out_Of_Service = value.type.Boolean;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_DESCRIPTION:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testOctetString_Value(Test * pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
|
||||
OctetString_Value_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_OCTETSTRING_VALUE;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = OctetString_Value_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_OCTETSTRING_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet OctetString Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testOctetString_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_OCTETSTRING_VALUE */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* OctetString Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "osv.h"
|
||||
|
||||
|
||||
#ifndef MAX_OCTETSTRING_VALUES
|
||||
#define MAX_OCTETSTRING_VALUES 4
|
||||
#endif
|
||||
|
||||
OCTETSTRING_VALUE_DESCR AV_Descr[MAX_OCTETSTRING_VALUES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int OctetString_Value_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int OctetString_Value_Properties_Optional[] = {
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int OctetString_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void OctetString_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = OctetString_Value_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = OctetString_Value_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = OctetString_Value_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void OctetString_Value_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_OCTETSTRING_VALUES; i++) {
|
||||
memset(&AV_Descr[i], 0x00, sizeof(OCTETSTRING_VALUE_DESCR));
|
||||
octetstring_init(&AV_Descr[i].Present_Value, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool OctetString_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_OCTETSTRING_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned OctetString_Value_Count(void)
|
||||
{
|
||||
return MAX_OCTETSTRING_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t OctetString_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_OCTETSTRING_VALUES;
|
||||
|
||||
if (object_instance < MAX_OCTETSTRING_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given object instance-number, sets the present-value at a given
|
||||
* priority 1..16.
|
||||
*
|
||||
* @param object_instance - object-instance number of the object
|
||||
* @param value - octetstring value
|
||||
* @param priority - priority 1..16
|
||||
*
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
|
||||
BACNET_OCTET_STRING * value,
|
||||
uint8_t priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
|
||||
index = OctetString_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_OCTETSTRING_VALUES) {
|
||||
octetstring_copy(&AV_Descr[index].Present_Value, value);
|
||||
status = true;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
BACNET_OCTET_STRING *value = NULL;
|
||||
unsigned index = 0;
|
||||
|
||||
index = OctetString_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_OCTETSTRING_VALUES) {
|
||||
value = &AV_Descr[index].Present_Value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool OctetString_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_OCTETSTRING_VALUES) {
|
||||
sprintf(text_string, "OCTETSTRING VALUE %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_OCTET_STRING *real_value = NULL;
|
||||
unsigned object_index = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
OCTETSTRING_VALUE_DESCR *CurrentAV;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
|
||||
object_index =
|
||||
OctetString_Value_Instance_To_Index(rpdata->object_instance);
|
||||
if (object_index < MAX_OCTETSTRING_VALUES)
|
||||
CurrentAV = &AV_Descr[object_index];
|
||||
else
|
||||
return BACNET_STATUS_ERROR;
|
||||
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_OCTETSTRING_VALUE, rpdata->object_instance);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
OctetString_Value_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_OCTETSTRING_VALUE);
|
||||
break;
|
||||
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value =
|
||||
OctetString_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_octet_string(&apdu[0], real_value);
|
||||
break;
|
||||
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
CurrentAV->Out_Of_Service);
|
||||
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = CurrentAV->Out_Of_Service;
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
OCTETSTRING_VALUE_DESCR *CurrentAV;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index =
|
||||
OctetString_Value_Instance_To_Index(wp_data->object_instance);
|
||||
if (object_index < MAX_OCTETSTRING_VALUES)
|
||||
CurrentAV = &AV_Descr[object_index];
|
||||
else
|
||||
return false;
|
||||
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OCTET_STRING) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (OctetString_Value_Present_Value_Set(wp_data->
|
||||
object_instance, &value.type.Octet_String,
|
||||
wp_data->priority)) {
|
||||
status = true;
|
||||
} else if (wp_data->priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
CurrentAV->Out_Of_Service = value.type.Boolean;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_DESCRIPTION:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testOctetString_Value(Test * pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
|
||||
OctetString_Value_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_OCTETSTRING_VALUE;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = OctetString_Value_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_OCTETSTRING_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet OctetString Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testOctetString_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_OCTETSTRING_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef OSV_H
|
||||
#define OSV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct octetstring_value_descr {
|
||||
unsigned Event_State:3;
|
||||
bool Out_Of_Service;
|
||||
BACNET_OCTET_STRING Present_Value;
|
||||
} OCTETSTRING_VALUE_DESCR;
|
||||
|
||||
|
||||
void OctetString_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool OctetString_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned OctetString_Value_Count(void);
|
||||
uint32_t OctetString_Value_Index_To_Instance(unsigned index);
|
||||
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance);
|
||||
|
||||
bool OctetString_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
|
||||
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
|
||||
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *
|
||||
wp_data);
|
||||
|
||||
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
|
||||
BACNET_OCTET_STRING * value,
|
||||
uint8_t priority);
|
||||
BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t
|
||||
object_instance);
|
||||
|
||||
bool OctetString_Value_Change_Of_Value(uint32_t instance);
|
||||
void OctetString_Value_Change_Of_Value_Clear(uint32_t instance);
|
||||
bool OctetString_Value_Encode_Value_List(uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list);
|
||||
|
||||
char *OctetString_Value_Description(uint32_t instance);
|
||||
bool OctetString_Value_Description_Set(uint32_t instance,
|
||||
char *new_name);
|
||||
|
||||
bool OctetString_Value_Out_Of_Service(uint32_t instance);
|
||||
void OctetString_Value_Out_Of_Service_Set(uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
/* note: header of Intrinsic_Reporting function is required
|
||||
even when INTRINSIC_REPORTING is not defined */
|
||||
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance);
|
||||
|
||||
void OctetString_Value_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testOctetString_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef OSV_H
|
||||
#define OSV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct octetstring_value_descr {
|
||||
unsigned Event_State:3;
|
||||
bool Out_Of_Service;
|
||||
BACNET_OCTET_STRING Present_Value;
|
||||
} OCTETSTRING_VALUE_DESCR;
|
||||
|
||||
|
||||
void OctetString_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool OctetString_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned OctetString_Value_Count(void);
|
||||
uint32_t OctetString_Value_Index_To_Instance(unsigned index);
|
||||
unsigned OctetString_Value_Instance_To_Index(uint32_t object_instance);
|
||||
|
||||
bool OctetString_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
|
||||
int OctetString_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
|
||||
bool OctetString_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *
|
||||
wp_data);
|
||||
|
||||
bool OctetString_Value_Present_Value_Set(uint32_t object_instance,
|
||||
BACNET_OCTET_STRING * value,
|
||||
uint8_t priority);
|
||||
BACNET_OCTET_STRING *OctetString_Value_Present_Value(uint32_t
|
||||
object_instance);
|
||||
|
||||
bool OctetString_Value_Change_Of_Value(uint32_t instance);
|
||||
void OctetString_Value_Change_Of_Value_Clear(uint32_t instance);
|
||||
bool OctetString_Value_Encode_Value_List(uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list);
|
||||
|
||||
char *OctetString_Value_Description(uint32_t instance);
|
||||
bool OctetString_Value_Description_Set(uint32_t instance,
|
||||
char *new_name);
|
||||
|
||||
bool OctetString_Value_Out_Of_Service(uint32_t instance);
|
||||
void OctetString_Value_Out_Of_Service_Set(uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
/* note: header of Intrinsic_Reporting function is required
|
||||
even when INTRINSIC_REPORTING is not defined */
|
||||
void OctetString_Value_Intrinsic_Reporting(uint32_t object_instance);
|
||||
|
||||
void OctetString_Value_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testOctetString_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DBACNET_PROPERTY_LISTS -DTEST_OCTETSTRING_VALUE
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = osv.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/proplist.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = octetstring_value
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DBACNET_PROPERTY_LISTS -DTEST_OCTETSTRING_VALUE
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = osv.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/proplist.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = octetstring_value
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
+442
-442
@@ -1,442 +1,442 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Positiveinteger Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "piv.h"
|
||||
|
||||
|
||||
#ifndef MAX_POSITIVEINTEGER_VALUES
|
||||
#define MAX_POSITIVEINTEGER_VALUES 4
|
||||
#endif
|
||||
|
||||
POSITIVEINTEGER_VALUE_DESCR PIV_Descr[MAX_POSITIVEINTEGER_VALUES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int PositiveInteger_Value_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_UNITS,
|
||||
- 1
|
||||
};
|
||||
|
||||
static const int PositiveInteger_Value_Properties_Optional[] = {
|
||||
PROP_OUT_OF_SERVICE,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int PositiveInteger_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void PositiveInteger_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = PositiveInteger_Value_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = PositiveInteger_Value_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = PositiveInteger_Value_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void PositiveInteger_Value_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_POSITIVEINTEGER_VALUES; i++) {
|
||||
memset(&PIV_Descr[i], 0x00, sizeof(POSITIVEINTEGER_VALUE_DESCR));
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_POSITIVEINTEGER_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned PositiveInteger_Value_Count(void)
|
||||
{
|
||||
return MAX_POSITIVEINTEGER_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_POSITIVEINTEGER_VALUES;
|
||||
|
||||
if (object_instance < MAX_POSITIVEINTEGER_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given object instance-number, sets the present-value at a given
|
||||
* priority 1..16.
|
||||
*
|
||||
* @param object_instance - object-instance number of the object
|
||||
* @param value - positiveinteger value
|
||||
* @param priority - priority 1..16
|
||||
*
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
|
||||
uint32_t value,
|
||||
uint8_t priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
|
||||
index = PositiveInteger_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_POSITIVEINTEGER_VALUES) {
|
||||
PIV_Descr[index].Present_Value = value;
|
||||
status = true;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
index = PositiveInteger_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_POSITIVEINTEGER_VALUES) {
|
||||
value = PIV_Descr[index].Present_Value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_POSITIVEINTEGER_VALUES) {
|
||||
sprintf(text_string, "POSITIVEINTEGER VALUE %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
|
||||
object_index =
|
||||
PositiveInteger_Value_Instance_To_Index(rpdata->object_instance);
|
||||
if (object_index < MAX_POSITIVEINTEGER_VALUES)
|
||||
CurrentAV = &PIV_Descr[object_index];
|
||||
else
|
||||
return BACNET_STATUS_ERROR;
|
||||
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_POSITIVE_INTEGER_VALUE, rpdata->object_instance);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_NAME:
|
||||
PositiveInteger_Value_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_POSITIVE_INTEGER_VALUE);
|
||||
break;
|
||||
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
PositiveInteger_Value_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
CurrentAV->Out_Of_Service);
|
||||
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
|
||||
case PROP_UNITS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], CurrentAV->Units);
|
||||
break;
|
||||
/* BACnet Testing Observed Incident oi00109
|
||||
Positive Integer Value / Units returned wrong datatype - missing break.
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00031
|
||||
BC 135.1: 9.20.1.7
|
||||
BC 135.1: 9.20.1.9
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes have been reviewed
|
||||
by all interested parties. Say 6 months -> September 2016 */
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = CurrentAV->Out_Of_Service;
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index =
|
||||
PositiveInteger_Value_Instance_To_Index(wp_data->object_instance);
|
||||
if (object_index < MAX_POSITIVEINTEGER_VALUES)
|
||||
CurrentAV = &PIV_Descr[object_index];
|
||||
else
|
||||
return false;
|
||||
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (PositiveInteger_Value_Present_Value_Set(wp_data->
|
||||
object_instance, value.type.Unsigned_Int,
|
||||
wp_data->priority)) {
|
||||
status = true;
|
||||
} else if (wp_data->priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
CurrentAV->Out_Of_Service = value.type.Boolean;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_UNITS:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testPositiveInteger_Value(Test * pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
|
||||
PositiveInteger_Value_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_POSITIVE_INTEGER_VALUE;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = PositiveInteger_Value_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_POSITIVEINTEGER_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet PositiveInteger Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testPositiveInteger_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_POSITIVEINTEGER_VALUE */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Positiveinteger Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "piv.h"
|
||||
|
||||
|
||||
#ifndef MAX_POSITIVEINTEGER_VALUES
|
||||
#define MAX_POSITIVEINTEGER_VALUES 4
|
||||
#endif
|
||||
|
||||
POSITIVEINTEGER_VALUE_DESCR PIV_Descr[MAX_POSITIVEINTEGER_VALUES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int PositiveInteger_Value_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_UNITS,
|
||||
- 1
|
||||
};
|
||||
|
||||
static const int PositiveInteger_Value_Properties_Optional[] = {
|
||||
PROP_OUT_OF_SERVICE,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int PositiveInteger_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void PositiveInteger_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = PositiveInteger_Value_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = PositiveInteger_Value_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = PositiveInteger_Value_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void PositiveInteger_Value_Init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_POSITIVEINTEGER_VALUES; i++) {
|
||||
memset(&PIV_Descr[i], 0x00, sizeof(POSITIVEINTEGER_VALUE_DESCR));
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_POSITIVEINTEGER_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned PositiveInteger_Value_Count(void)
|
||||
{
|
||||
return MAX_POSITIVEINTEGER_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_POSITIVEINTEGER_VALUES;
|
||||
|
||||
if (object_instance < MAX_POSITIVEINTEGER_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given object instance-number, sets the present-value at a given
|
||||
* priority 1..16.
|
||||
*
|
||||
* @param object_instance - object-instance number of the object
|
||||
* @param value - positiveinteger value
|
||||
* @param priority - priority 1..16
|
||||
*
|
||||
* @return true if values are within range and present-value is set.
|
||||
*/
|
||||
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
|
||||
uint32_t value,
|
||||
uint8_t priority)
|
||||
{
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
|
||||
index = PositiveInteger_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_POSITIVEINTEGER_VALUES) {
|
||||
PIV_Descr[index].Present_Value = value;
|
||||
status = true;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
uint32_t value = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
index = PositiveInteger_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_POSITIVEINTEGER_VALUES) {
|
||||
value = PIV_Descr[index].Present_Value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_POSITIVEINTEGER_VALUES) {
|
||||
sprintf(text_string, "POSITIVEINTEGER VALUE %lu",
|
||||
(unsigned long) object_instance);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or BACNET_STATUS_ERROR on error */
|
||||
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
|
||||
object_index =
|
||||
PositiveInteger_Value_Instance_To_Index(rpdata->object_instance);
|
||||
if (object_index < MAX_POSITIVEINTEGER_VALUES)
|
||||
CurrentAV = &PIV_Descr[object_index];
|
||||
else
|
||||
return BACNET_STATUS_ERROR;
|
||||
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0],
|
||||
OBJECT_POSITIVE_INTEGER_VALUE, rpdata->object_instance);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_NAME:
|
||||
PositiveInteger_Value_Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
OBJECT_POSITIVE_INTEGER_VALUE);
|
||||
break;
|
||||
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
PositiveInteger_Value_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE,
|
||||
CurrentAV->Out_Of_Service);
|
||||
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
|
||||
case PROP_UNITS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], CurrentAV->Units);
|
||||
break;
|
||||
/* BACnet Testing Observed Incident oi00109
|
||||
Positive Integer Value / Units returned wrong datatype - missing break.
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00031
|
||||
BC 135.1: 9.20.1.7
|
||||
BC 135.1: 9.20.1.9
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes have been reviewed
|
||||
by all interested parties. Say 6 months -> September 2016 */
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
state = CurrentAV->Out_Of_Service;
|
||||
apdu_len = encode_application_boolean(&apdu[0], state);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
POSITIVEINTEGER_VALUE_DESCR *CurrentAV;
|
||||
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
object_index =
|
||||
PositiveInteger_Value_Instance_To_Index(wp_data->object_instance);
|
||||
if (object_index < MAX_POSITIVEINTEGER_VALUES)
|
||||
CurrentAV = &PIV_Descr[object_index];
|
||||
else
|
||||
return false;
|
||||
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (PositiveInteger_Value_Present_Value_Set(wp_data->
|
||||
object_instance, value.type.Unsigned_Int,
|
||||
wp_data->priority)) {
|
||||
status = true;
|
||||
} else if (wp_data->priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
CurrentAV->Out_Of_Service = value.type.Boolean;
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_UNITS:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
bool WPValidateArgType(BACNET_APPLICATION_DATA_VALUE * pValue,
|
||||
uint8_t ucExpectedTag,
|
||||
BACNET_ERROR_CLASS * pErrorClass,
|
||||
BACNET_ERROR_CODE * pErrorCode)
|
||||
{
|
||||
pValue = pValue;
|
||||
ucExpectedTag = ucExpectedTag;
|
||||
pErrorClass = pErrorClass;
|
||||
pErrorCode = pErrorCode;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void testPositiveInteger_Value(Test * pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
|
||||
PositiveInteger_Value_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_POSITIVE_INTEGER_VALUE;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = PositiveInteger_Value_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_POSITIVEINTEGER_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet PositiveInteger Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testPositiveInteger_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_POSITIVEINTEGER_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef PIV_H
|
||||
#define PIV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct positiveinteger_value_descr {
|
||||
bool Out_Of_Service:1;
|
||||
uint32_t Present_Value;
|
||||
uint16_t Units;
|
||||
} POSITIVEINTEGER_VALUE_DESCR;
|
||||
|
||||
|
||||
void PositiveInteger_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned PositiveInteger_Value_Count(void);
|
||||
uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index);
|
||||
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance);
|
||||
|
||||
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
|
||||
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *
|
||||
rpdata);
|
||||
|
||||
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *
|
||||
wp_data);
|
||||
|
||||
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
|
||||
uint32_t value,
|
||||
uint8_t priority);
|
||||
uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance);
|
||||
|
||||
bool PositiveInteger_Value_Change_Of_Value(uint32_t instance);
|
||||
void PositiveInteger_Value_Change_Of_Value_Clear(uint32_t instance);
|
||||
bool PositiveInteger_Value_Encode_Value_List(uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list);
|
||||
|
||||
char *PositiveInteger_Value_Description(uint32_t instance);
|
||||
bool PositiveInteger_Value_Description_Set(uint32_t instance,
|
||||
char *new_name);
|
||||
|
||||
bool PositiveInteger_Value_Out_Of_Service(uint32_t instance);
|
||||
void PositiveInteger_Value_Out_Of_Service_Set(uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
/* note: header of Intrinsic_Reporting function is required
|
||||
even when INTRINSIC_REPORTING is not defined */
|
||||
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance);
|
||||
|
||||
void PositiveInteger_Value_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testPositiveInteger_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef PIV_H
|
||||
#define PIV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct positiveinteger_value_descr {
|
||||
bool Out_Of_Service:1;
|
||||
uint32_t Present_Value;
|
||||
uint16_t Units;
|
||||
} POSITIVEINTEGER_VALUE_DESCR;
|
||||
|
||||
|
||||
void PositiveInteger_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool PositiveInteger_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned PositiveInteger_Value_Count(void);
|
||||
uint32_t PositiveInteger_Value_Index_To_Instance(unsigned index);
|
||||
unsigned PositiveInteger_Value_Instance_To_Index(uint32_t object_instance);
|
||||
|
||||
bool PositiveInteger_Value_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
|
||||
int PositiveInteger_Value_Read_Property(BACNET_READ_PROPERTY_DATA *
|
||||
rpdata);
|
||||
|
||||
bool PositiveInteger_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA *
|
||||
wp_data);
|
||||
|
||||
bool PositiveInteger_Value_Present_Value_Set(uint32_t object_instance,
|
||||
uint32_t value,
|
||||
uint8_t priority);
|
||||
uint32_t PositiveInteger_Value_Present_Value(uint32_t object_instance);
|
||||
|
||||
bool PositiveInteger_Value_Change_Of_Value(uint32_t instance);
|
||||
void PositiveInteger_Value_Change_Of_Value_Clear(uint32_t instance);
|
||||
bool PositiveInteger_Value_Encode_Value_List(uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list);
|
||||
|
||||
char *PositiveInteger_Value_Description(uint32_t instance);
|
||||
bool PositiveInteger_Value_Description_Set(uint32_t instance,
|
||||
char *new_name);
|
||||
|
||||
bool PositiveInteger_Value_Out_Of_Service(uint32_t instance);
|
||||
void PositiveInteger_Value_Out_Of_Service_Set(uint32_t instance,
|
||||
bool oos_flag);
|
||||
|
||||
/* note: header of Intrinsic_Reporting function is required
|
||||
even when INTRINSIC_REPORTING is not defined */
|
||||
void PositiveInteger_Value_Intrinsic_Reporting(uint32_t object_instance);
|
||||
|
||||
void PositiveInteger_Value_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testPositiveInteger_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_POSITIVEINTEGER_VALUE
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = piv.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = positiveinteger_value
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_POSITIVEINTEGER_VALUE
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = piv.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = positiveinteger_value
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
+492
-492
@@ -1,492 +1,492 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h"
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "proplist.h"
|
||||
#include "timestamp.h"
|
||||
#include "schedule.h"
|
||||
|
||||
#ifndef MAX_SCHEDULES
|
||||
#define MAX_SCHEDULES 4
|
||||
#endif
|
||||
|
||||
SCHEDULE_DESCR Schedule_Descr[MAX_SCHEDULES];
|
||||
|
||||
static const int Schedule_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_EFFECTIVE_PERIOD,
|
||||
PROP_SCHEDULE_DEFAULT,
|
||||
PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES,
|
||||
PROP_PRIORITY_FOR_WRITING,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Schedule_Properties_Optional[] = {
|
||||
PROP_WEEKLY_SCHEDULE,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Schedule_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Schedule_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Schedule_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Schedule_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Schedule_Properties_Proprietary;
|
||||
}
|
||||
|
||||
void Schedule_Init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
for (i = 0; i < MAX_SCHEDULES; i++) {
|
||||
/* whole year, change as neccessary */
|
||||
Schedule_Descr[i].Start_Date.year = 0xFF;
|
||||
Schedule_Descr[i].Start_Date.month = 1;
|
||||
Schedule_Descr[i].Start_Date.day = 1;
|
||||
Schedule_Descr[i].Start_Date.wday = 0xFF;
|
||||
Schedule_Descr[i].End_Date.year = 0xFF;
|
||||
Schedule_Descr[i].End_Date.month = 12;
|
||||
Schedule_Descr[i].End_Date.day = 31;
|
||||
Schedule_Descr[i].End_Date.wday = 0xFF;
|
||||
for (j = 0; j < 7; j++) {
|
||||
Schedule_Descr[i].Weekly_Schedule[j].TV_Count = 0;
|
||||
}
|
||||
Schedule_Descr[i].Present_Value = &Schedule_Descr[i].Schedule_Default;
|
||||
Schedule_Descr[i].Schedule_Default.context_specific = false;
|
||||
Schedule_Descr[i].Schedule_Default.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
Schedule_Descr[i].Schedule_Default.type.Real = 21.0; /* 21 C, room temperature */
|
||||
Schedule_Descr[i].obj_prop_ref_cnt = 0; /* no references, add as needed */
|
||||
Schedule_Descr[i].Priority_For_Writing = 16; /* lowest priority */
|
||||
Schedule_Descr[i].Out_Of_Service = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Schedule_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned int index = Schedule_Instance_To_Index(object_instance);
|
||||
if (index < MAX_SCHEDULES)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned Schedule_Count(void)
|
||||
{
|
||||
return MAX_SCHEDULES;
|
||||
}
|
||||
|
||||
uint32_t Schedule_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned Schedule_Instance_To_Index(uint32_t instance)
|
||||
{
|
||||
unsigned index = MAX_SCHEDULES;
|
||||
|
||||
if (instance < MAX_SCHEDULES)
|
||||
index = instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool Schedule_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
unsigned int index;
|
||||
bool status = false;
|
||||
|
||||
index = Schedule_Instance_To_Index(object_instance);
|
||||
if (index < MAX_SCHEDULES) {
|
||||
sprintf(text_string, "SCHEDULE %lu", (unsigned long) index);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
void Schedule_Out_Of_Service_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
index = Schedule_Instance_To_Index(object_instance);
|
||||
if (index < MAX_SCHEDULES) {
|
||||
Schedule_Descr[index].Out_Of_Service = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0;
|
||||
unsigned object_index = 0;
|
||||
SCHEDULE_DESCR *CurrentSC;
|
||||
uint8_t *apdu = NULL;
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
int i;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
object_index = Schedule_Instance_To_Index(rpdata->object_instance);
|
||||
if (object_index < MAX_SCHEDULES)
|
||||
CurrentSC = &Schedule_Descr[object_index];
|
||||
else
|
||||
return BACNET_STATUS_ERROR;
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
switch ((int) rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_SCHEDULE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Schedule_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_SCHEDULE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len = bacapp_encode_data(&apdu[0], CurrentSC->Present_Value);
|
||||
break;
|
||||
case PROP_EFFECTIVE_PERIOD:
|
||||
/* BACnet Testing Observed Incident oi00110
|
||||
Effective Period of Schedule object not correctly formatted
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00031
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
apdu_len = encode_application_date(&apdu[0], &CurrentSC->Start_Date);
|
||||
apdu_len +=
|
||||
encode_application_date(&apdu[apdu_len], &CurrentSC->End_Date);
|
||||
break;
|
||||
case PROP_WEEKLY_SCHEDULE:
|
||||
if (rpdata->array_index == 0) /* count, always 7 */
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 7);
|
||||
else if (rpdata->array_index == BACNET_ARRAY_ALL) { /* full array */
|
||||
int day;
|
||||
for (day = 0; day < 7; day++) {
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count;
|
||||
i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_time_value(&apdu[apdu_len],
|
||||
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
|
||||
}
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
}
|
||||
} else if (rpdata->array_index <= 7) { /* some array element */
|
||||
int day = rpdata->array_index - 1;
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count; i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_time_value(&apdu[apdu_len],
|
||||
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
|
||||
}
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
} else { /* out of bounds */
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
break;
|
||||
case PROP_SCHEDULE_DEFAULT:
|
||||
apdu_len =
|
||||
bacapp_encode_data(&apdu[0], &CurrentSC->Schedule_Default);
|
||||
break;
|
||||
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
|
||||
for (i = 0; i < CurrentSC->obj_prop_ref_cnt; i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_device_obj_property_ref(&apdu[apdu_len],
|
||||
&CurrentSC->Object_Property_References[i]);
|
||||
}
|
||||
break;
|
||||
case PROP_PRIORITY_FOR_WRITING:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
CurrentSC->Priority_For_Writing);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
RELIABILITY_NO_FAULT_DETECTED);
|
||||
break;
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
apdu_len = encode_application_boolean(&apdu[0],
|
||||
CurrentSC->Out_Of_Service );
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_WEEKLY_SCHEDULE)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
/* Ed->Steve, I know that initializing stack values used to be 'safer', but warnings in latest compilers indicate when
|
||||
uninitialized values are being used, and I think that the warnings are more useful to reveal bad code flow than the
|
||||
"safety: of pre-intializing variables. Please give this some thought let me know if you agree we should start to
|
||||
remove initializations */
|
||||
unsigned object_index ;
|
||||
bool status = false; /* return value */
|
||||
int len ;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
object_index = Schedule_Instance_To_Index(wp_data->object_instance);
|
||||
if (object_index >= MAX_SCHEDULES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ((int) wp_data->object_property) {
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Schedule_Out_Of_Service_Set(
|
||||
wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_PRESENT_VALUE:
|
||||
case PROP_EFFECTIVE_PERIOD:
|
||||
case PROP_WEEKLY_SCHEDULE:
|
||||
case PROP_SCHEDULE_DEFAULT:
|
||||
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
|
||||
case PROP_PRIORITY_FOR_WRITING:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_RELIABILITY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
|
||||
BACNET_DATE * date)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
if (desc && date) {
|
||||
if (datetime_wildcard_compare_date(&desc->Start_Date, date) <= 0 &&
|
||||
datetime_wildcard_compare_date(&desc->End_Date, date) >= 0)
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
|
||||
BACNET_WEEKDAY wday,
|
||||
BACNET_TIME * time)
|
||||
{
|
||||
int i;
|
||||
desc->Present_Value = NULL;
|
||||
|
||||
/* for future development, here should be the loop for Exception Schedule */
|
||||
|
||||
/* Just a note to developers: We have a paying customer who has asked us to fully implement the Schedule Object.
|
||||
In good spirit, they have agreed to allow us to release the code we develop back to the Open Source community after a 6-12 month waiting period.
|
||||
However, if you are about to work on this yourself, please ping us at info@connect-ex.com, we may be able to broker an early release on a
|
||||
case-by-case basis. */
|
||||
|
||||
|
||||
for (i = 0;
|
||||
i < desc->Weekly_Schedule[wday - 1].TV_Count &&
|
||||
desc->Present_Value == NULL; i++) {
|
||||
int diff = datetime_wildcard_compare_time(time,
|
||||
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Time);
|
||||
if (diff >= 0 &&
|
||||
desc->Weekly_Schedule[wday - 1].Time_Values[i].Value.tag !=
|
||||
BACNET_APPLICATION_TAG_NULL) {
|
||||
desc->Present_Value =
|
||||
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc->Present_Value == NULL)
|
||||
desc->Present_Value = &desc->Schedule_Default;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
|
||||
void testSchedule(Test * pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
|
||||
Schedule_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_SCHEDULE;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Schedule_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST_SCHEDULE
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Schedule", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testSchedule);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TEST_SCHEDULE */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h"
|
||||
#include "device.h"
|
||||
#include "handlers.h"
|
||||
#include "proplist.h"
|
||||
#include "timestamp.h"
|
||||
#include "schedule.h"
|
||||
|
||||
#ifndef MAX_SCHEDULES
|
||||
#define MAX_SCHEDULES 4
|
||||
#endif
|
||||
|
||||
SCHEDULE_DESCR Schedule_Descr[MAX_SCHEDULES];
|
||||
|
||||
static const int Schedule_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_EFFECTIVE_PERIOD,
|
||||
PROP_SCHEDULE_DEFAULT,
|
||||
PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES,
|
||||
PROP_PRIORITY_FOR_WRITING,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_RELIABILITY,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Schedule_Properties_Optional[] = {
|
||||
PROP_WEEKLY_SCHEDULE,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Schedule_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Schedule_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Schedule_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Schedule_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Schedule_Properties_Proprietary;
|
||||
}
|
||||
|
||||
void Schedule_Init(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
for (i = 0; i < MAX_SCHEDULES; i++) {
|
||||
/* whole year, change as neccessary */
|
||||
Schedule_Descr[i].Start_Date.year = 0xFF;
|
||||
Schedule_Descr[i].Start_Date.month = 1;
|
||||
Schedule_Descr[i].Start_Date.day = 1;
|
||||
Schedule_Descr[i].Start_Date.wday = 0xFF;
|
||||
Schedule_Descr[i].End_Date.year = 0xFF;
|
||||
Schedule_Descr[i].End_Date.month = 12;
|
||||
Schedule_Descr[i].End_Date.day = 31;
|
||||
Schedule_Descr[i].End_Date.wday = 0xFF;
|
||||
for (j = 0; j < 7; j++) {
|
||||
Schedule_Descr[i].Weekly_Schedule[j].TV_Count = 0;
|
||||
}
|
||||
Schedule_Descr[i].Present_Value = &Schedule_Descr[i].Schedule_Default;
|
||||
Schedule_Descr[i].Schedule_Default.context_specific = false;
|
||||
Schedule_Descr[i].Schedule_Default.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
Schedule_Descr[i].Schedule_Default.type.Real = 21.0; /* 21 C, room temperature */
|
||||
Schedule_Descr[i].obj_prop_ref_cnt = 0; /* no references, add as needed */
|
||||
Schedule_Descr[i].Priority_For_Writing = 16; /* lowest priority */
|
||||
Schedule_Descr[i].Out_Of_Service = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Schedule_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
unsigned int index = Schedule_Instance_To_Index(object_instance);
|
||||
if (index < MAX_SCHEDULES)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned Schedule_Count(void)
|
||||
{
|
||||
return MAX_SCHEDULES;
|
||||
}
|
||||
|
||||
uint32_t Schedule_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned Schedule_Instance_To_Index(uint32_t instance)
|
||||
{
|
||||
unsigned index = MAX_SCHEDULES;
|
||||
|
||||
if (instance < MAX_SCHEDULES)
|
||||
index = instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool Schedule_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
unsigned int index;
|
||||
bool status = false;
|
||||
|
||||
index = Schedule_Instance_To_Index(object_instance);
|
||||
if (index < MAX_SCHEDULES) {
|
||||
sprintf(text_string, "SCHEDULE %lu", (unsigned long) index);
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
void Schedule_Out_Of_Service_Set(
|
||||
uint32_t object_instance,
|
||||
bool value)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
index = Schedule_Instance_To_Index(object_instance);
|
||||
if (index < MAX_SCHEDULES) {
|
||||
Schedule_Descr[index].Out_Of_Service = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0;
|
||||
unsigned object_index = 0;
|
||||
SCHEDULE_DESCR *CurrentSC;
|
||||
uint8_t *apdu = NULL;
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
int i;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
object_index = Schedule_Instance_To_Index(rpdata->object_instance);
|
||||
if (object_index < MAX_SCHEDULES)
|
||||
CurrentSC = &Schedule_Descr[object_index];
|
||||
else
|
||||
return BACNET_STATUS_ERROR;
|
||||
|
||||
apdu = rpdata->application_data;
|
||||
switch ((int) rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_SCHEDULE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
Schedule_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_SCHEDULE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len = bacapp_encode_data(&apdu[0], CurrentSC->Present_Value);
|
||||
break;
|
||||
case PROP_EFFECTIVE_PERIOD:
|
||||
/* BACnet Testing Observed Incident oi00110
|
||||
Effective Period of Schedule object not correctly formatted
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00031
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
apdu_len = encode_application_date(&apdu[0], &CurrentSC->Start_Date);
|
||||
apdu_len +=
|
||||
encode_application_date(&apdu[apdu_len], &CurrentSC->End_Date);
|
||||
break;
|
||||
case PROP_WEEKLY_SCHEDULE:
|
||||
if (rpdata->array_index == 0) /* count, always 7 */
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 7);
|
||||
else if (rpdata->array_index == BACNET_ARRAY_ALL) { /* full array */
|
||||
int day;
|
||||
for (day = 0; day < 7; day++) {
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count;
|
||||
i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_time_value(&apdu[apdu_len],
|
||||
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
|
||||
}
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
}
|
||||
} else if (rpdata->array_index <= 7) { /* some array element */
|
||||
int day = rpdata->array_index - 1;
|
||||
apdu_len += encode_opening_tag(&apdu[apdu_len], 0);
|
||||
for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count; i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_time_value(&apdu[apdu_len],
|
||||
&CurrentSC->Weekly_Schedule[day].Time_Values[i]);
|
||||
}
|
||||
apdu_len += encode_closing_tag(&apdu[apdu_len], 0);
|
||||
} else { /* out of bounds */
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
break;
|
||||
case PROP_SCHEDULE_DEFAULT:
|
||||
apdu_len =
|
||||
bacapp_encode_data(&apdu[0], &CurrentSC->Schedule_Default);
|
||||
break;
|
||||
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
|
||||
for (i = 0; i < CurrentSC->obj_prop_ref_cnt; i++) {
|
||||
apdu_len +=
|
||||
bacapp_encode_device_obj_property_ref(&apdu[apdu_len],
|
||||
&CurrentSC->Object_Property_References[i]);
|
||||
}
|
||||
break;
|
||||
case PROP_PRIORITY_FOR_WRITING:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
CurrentSC->Priority_For_Writing);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_RELIABILITY:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
RELIABILITY_NO_FAULT_DETECTED);
|
||||
break;
|
||||
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
apdu_len = encode_application_boolean(&apdu[0],
|
||||
CurrentSC->Out_Of_Service );
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((apdu_len >= 0) && (rpdata->object_property != PROP_WEEKLY_SCHEDULE)
|
||||
&& (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
/* Ed->Steve, I know that initializing stack values used to be 'safer', but warnings in latest compilers indicate when
|
||||
uninitialized values are being used, and I think that the warnings are more useful to reveal bad code flow than the
|
||||
"safety: of pre-intializing variables. Please give this some thought let me know if you agree we should start to
|
||||
remove initializations */
|
||||
unsigned object_index ;
|
||||
bool status = false; /* return value */
|
||||
int len ;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
object_index = Schedule_Instance_To_Index(wp_data->object_instance);
|
||||
if (object_index >= MAX_SCHEDULES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ((int) wp_data->object_property) {
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
/* BACnet Testing Observed Incident oi00106
|
||||
Out of service was not supported by Schedule object
|
||||
Revealed by BACnet Test Client v1.8.16 ( www.bac-test.com/bacnet-test-client-download )
|
||||
BITS: BIT00032
|
||||
Any discussions can be directed to edward@bac-test.com
|
||||
Please feel free to remove this comment when my changes accepted after suitable time for
|
||||
review by all interested parties. Say 6 months -> September 2016 */
|
||||
status =
|
||||
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
|
||||
&wp_data->error_class, &wp_data->error_code);
|
||||
if (status) {
|
||||
Schedule_Out_Of_Service_Set(
|
||||
wp_data->object_instance,
|
||||
value.type.Boolean);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_PRESENT_VALUE:
|
||||
case PROP_EFFECTIVE_PERIOD:
|
||||
case PROP_WEEKLY_SCHEDULE:
|
||||
case PROP_SCHEDULE_DEFAULT:
|
||||
case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES:
|
||||
case PROP_PRIORITY_FOR_WRITING:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_RELIABILITY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
|
||||
BACNET_DATE * date)
|
||||
{
|
||||
bool res = false;
|
||||
|
||||
if (desc && date) {
|
||||
if (datetime_wildcard_compare_date(&desc->Start_Date, date) <= 0 &&
|
||||
datetime_wildcard_compare_date(&desc->End_Date, date) >= 0)
|
||||
res = true;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
|
||||
BACNET_WEEKDAY wday,
|
||||
BACNET_TIME * time)
|
||||
{
|
||||
int i;
|
||||
desc->Present_Value = NULL;
|
||||
|
||||
/* for future development, here should be the loop for Exception Schedule */
|
||||
|
||||
/* Just a note to developers: We have a paying customer who has asked us to fully implement the Schedule Object.
|
||||
In good spirit, they have agreed to allow us to release the code we develop back to the Open Source community after a 6-12 month waiting period.
|
||||
However, if you are about to work on this yourself, please ping us at info@connect-ex.com, we may be able to broker an early release on a
|
||||
case-by-case basis. */
|
||||
|
||||
|
||||
for (i = 0;
|
||||
i < desc->Weekly_Schedule[wday - 1].TV_Count &&
|
||||
desc->Present_Value == NULL; i++) {
|
||||
int diff = datetime_wildcard_compare_time(time,
|
||||
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Time);
|
||||
if (diff >= 0 &&
|
||||
desc->Weekly_Schedule[wday - 1].Time_Values[i].Value.tag !=
|
||||
BACNET_APPLICATION_TAG_NULL) {
|
||||
desc->Present_Value =
|
||||
&desc->Weekly_Schedule[wday - 1].Time_Values[i].Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (desc->Present_Value == NULL)
|
||||
desc->Present_Value = &desc->Schedule_Default;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
|
||||
void testSchedule(Test * pTest)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA rpdata;
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint16_t decoded_type = 0;
|
||||
uint32_t decoded_instance = 0;
|
||||
|
||||
Schedule_Init();
|
||||
rpdata.application_data = &apdu[0];
|
||||
rpdata.application_data_len = sizeof(apdu);
|
||||
rpdata.object_type = OBJECT_SCHEDULE;
|
||||
rpdata.object_instance = 1;
|
||||
rpdata.object_property = PROP_OBJECT_IDENTIFIER;
|
||||
rpdata.array_index = BACNET_ARRAY_ALL;
|
||||
len = Schedule_Read_Property(&rpdata);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len = decode_object_id(&apdu[len], &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == rpdata.object_type);
|
||||
ct_test(pTest, decoded_instance == rpdata.object_instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST_SCHEDULE
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Schedule", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testSchedule);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* TEST_SCHEDULE */
|
||||
#endif /* TEST */
|
||||
|
||||
+101
-101
@@ -1,101 +1,101 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SCHEDULE_H
|
||||
#define SCHEDULE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "datetime.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "bactimevalue.h"
|
||||
|
||||
#ifndef BACNET_WEEKLY_SCHEDULE_SIZE
|
||||
#define BACNET_WEEKLY_SCHEDULE_SIZE 8 /* maximum number of data points for each day */
|
||||
#endif
|
||||
|
||||
#ifndef BACNET_SCHEDULE_OBJ_PROP_REF_SIZE
|
||||
#define BACNET_SCHEDULE_OBJ_PROP_REF_SIZE 4 /* maximum number of obj prop references */
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct bacnet_daily_schedule {
|
||||
BACNET_TIME_VALUE Time_Values[BACNET_WEEKLY_SCHEDULE_SIZE];
|
||||
uint16_t TV_Count; /* the number of time values actually used */
|
||||
} BACNET_DAILY_SCHEDULE;
|
||||
|
||||
typedef struct schedule {
|
||||
/* Effective Period: Start and End Date */
|
||||
BACNET_DATE Start_Date;
|
||||
BACNET_DATE End_Date;
|
||||
/* Properties concerning Present Value */
|
||||
BACNET_DAILY_SCHEDULE Weekly_Schedule[7];
|
||||
BACNET_APPLICATION_DATA_VALUE Schedule_Default;
|
||||
BACNET_APPLICATION_DATA_VALUE *Present_Value; /* must be set to a valid value
|
||||
* default is Schedule_Default */
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE
|
||||
Object_Property_References[BACNET_SCHEDULE_OBJ_PROP_REF_SIZE];
|
||||
uint8_t obj_prop_ref_cnt; /* actual number of obj_prop references */
|
||||
uint8_t Priority_For_Writing; /* (1..16) */
|
||||
bool Out_Of_Service;
|
||||
} SCHEDULE_DESCR;
|
||||
|
||||
void Schedule_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
|
||||
bool Schedule_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Schedule_Count(void);
|
||||
uint32_t Schedule_Index_To_Instance(unsigned index);
|
||||
unsigned Schedule_Instance_To_Index(uint32_t instance);
|
||||
void Schedule_Init(void);
|
||||
|
||||
bool Schedule_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
|
||||
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
/* utility functions for calculating current Present Value
|
||||
* if Exception Schedule is to be added, these functions must take that into account */
|
||||
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
|
||||
BACNET_DATE * date);
|
||||
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
|
||||
BACNET_WEEKDAY wday,
|
||||
BACNET_TIME * time);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef SCHEDULE_H
|
||||
#define SCHEDULE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "datetime.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
#include "bactimevalue.h"
|
||||
|
||||
#ifndef BACNET_WEEKLY_SCHEDULE_SIZE
|
||||
#define BACNET_WEEKLY_SCHEDULE_SIZE 8 /* maximum number of data points for each day */
|
||||
#endif
|
||||
|
||||
#ifndef BACNET_SCHEDULE_OBJ_PROP_REF_SIZE
|
||||
#define BACNET_SCHEDULE_OBJ_PROP_REF_SIZE 4 /* maximum number of obj prop references */
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct bacnet_daily_schedule {
|
||||
BACNET_TIME_VALUE Time_Values[BACNET_WEEKLY_SCHEDULE_SIZE];
|
||||
uint16_t TV_Count; /* the number of time values actually used */
|
||||
} BACNET_DAILY_SCHEDULE;
|
||||
|
||||
typedef struct schedule {
|
||||
/* Effective Period: Start and End Date */
|
||||
BACNET_DATE Start_Date;
|
||||
BACNET_DATE End_Date;
|
||||
/* Properties concerning Present Value */
|
||||
BACNET_DAILY_SCHEDULE Weekly_Schedule[7];
|
||||
BACNET_APPLICATION_DATA_VALUE Schedule_Default;
|
||||
BACNET_APPLICATION_DATA_VALUE *Present_Value; /* must be set to a valid value
|
||||
* default is Schedule_Default */
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE
|
||||
Object_Property_References[BACNET_SCHEDULE_OBJ_PROP_REF_SIZE];
|
||||
uint8_t obj_prop_ref_cnt; /* actual number of obj_prop references */
|
||||
uint8_t Priority_For_Writing; /* (1..16) */
|
||||
bool Out_Of_Service;
|
||||
} SCHEDULE_DESCR;
|
||||
|
||||
void Schedule_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
|
||||
bool Schedule_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Schedule_Count(void);
|
||||
uint32_t Schedule_Index_To_Instance(unsigned index);
|
||||
unsigned Schedule_Instance_To_Index(uint32_t instance);
|
||||
void Schedule_Init(void);
|
||||
|
||||
bool Schedule_Object_Name(uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
|
||||
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Schedule_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
/* utility functions for calculating current Present Value
|
||||
* if Exception Schedule is to be added, these functions must take that into account */
|
||||
bool Schedule_In_Effective_Period(SCHEDULE_DESCR * desc,
|
||||
BACNET_DATE * date);
|
||||
void Schedule_Recalculate_PV(SCHEDULE_DESCR * desc,
|
||||
BACNET_WEEKDAY wday,
|
||||
BACNET_TIME * time);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_SCHEDULE
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = schedule.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactimevalue.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = schedule
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
#Makefile to build test case
|
||||
CC = gcc
|
||||
SRC_DIR = ../../src
|
||||
TEST_DIR = ../../test
|
||||
INCLUDES = -I../../include -I$(TEST_DIR) -I.
|
||||
DEFINES = -DBIG_ENDIAN=0 -DTEST -DBACAPP_ALL -DTEST_SCHEDULE
|
||||
|
||||
CFLAGS = -Wall $(INCLUDES) $(DEFINES) -g
|
||||
|
||||
SRCS = schedule.c \
|
||||
$(SRC_DIR)/bacdcode.c \
|
||||
$(SRC_DIR)/bacint.c \
|
||||
$(SRC_DIR)/bacstr.c \
|
||||
$(SRC_DIR)/bacreal.c \
|
||||
$(SRC_DIR)/bacdevobjpropref.c \
|
||||
$(SRC_DIR)/bactimevalue.c \
|
||||
$(SRC_DIR)/datetime.c \
|
||||
$(SRC_DIR)/lighting.c \
|
||||
$(SRC_DIR)/bacapp.c \
|
||||
$(SRC_DIR)/bactext.c \
|
||||
$(SRC_DIR)/indtext.c \
|
||||
$(TEST_DIR)/ctest.c
|
||||
|
||||
TARGET = schedule
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
${TARGET}: ${OBJS}
|
||||
${CC} -o $@ ${OBJS}
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET} $(OBJS)
|
||||
|
||||
include: .depend
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
#Makefile to build BACnet Application using GCC compiler
|
||||
|
||||
# tools - only if you need them.
|
||||
# Most platforms have this already defined
|
||||
# CC = gcc
|
||||
# AR = ar
|
||||
# MAKE = make
|
||||
# SIZE = size
|
||||
#
|
||||
# Assumes rm and cp are available
|
||||
|
||||
# Executable file name
|
||||
TARGET = bacrr
|
||||
|
||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||
|
||||
SRCS = main.c \
|
||||
../object/device-client.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
all: ${BACNET_LIB_TARGET} Makefile ${TARGET_BIN}
|
||||
|
||||
${TARGET_BIN}: ${OBJS} Makefile ${BACNET_LIB_TARGET}
|
||||
${CC} ${PFLAGS} ${OBJS} ${LFLAGS} -o $@
|
||||
size $@
|
||||
cp $@ ../../bin
|
||||
|
||||
lib: ${BACNET_LIB_TARGET}
|
||||
|
||||
${BACNET_LIB_TARGET}:
|
||||
( cd ${BACNET_LIB_DIR} ; $(MAKE) clean ; $(MAKE) )
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET_BIN} ${OBJS} ${BACNET_LIB_TARGET}
|
||||
|
||||
include: .depend
|
||||
#Makefile to build BACnet Application using GCC compiler
|
||||
|
||||
# tools - only if you need them.
|
||||
# Most platforms have this already defined
|
||||
# CC = gcc
|
||||
# AR = ar
|
||||
# MAKE = make
|
||||
# SIZE = size
|
||||
#
|
||||
# Assumes rm and cp are available
|
||||
|
||||
# Executable file name
|
||||
TARGET = bacrr
|
||||
|
||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||
|
||||
SRCS = main.c \
|
||||
../object/device-client.c
|
||||
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
all: ${BACNET_LIB_TARGET} Makefile ${TARGET_BIN}
|
||||
|
||||
${TARGET_BIN}: ${OBJS} Makefile ${BACNET_LIB_TARGET}
|
||||
${CC} ${PFLAGS} ${OBJS} ${LFLAGS} -o $@
|
||||
size $@
|
||||
cp $@ ../../bin
|
||||
|
||||
lib: ${BACNET_LIB_TARGET}
|
||||
|
||||
${BACNET_LIB_TARGET}:
|
||||
( cd ${BACNET_LIB_DIR} ; $(MAKE) clean ; $(MAKE) )
|
||||
|
||||
.c.o:
|
||||
${CC} -c ${CFLAGS} $*.c -o $@
|
||||
|
||||
depend:
|
||||
rm -f .depend
|
||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||
|
||||
clean:
|
||||
rm -rf core ${TARGET_BIN} ${OBJS} ${BACNET_LIB_TARGET}
|
||||
|
||||
include: .depend
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef ACCESS_RULE_H
|
||||
#define ACCESS_RULE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
|
||||
typedef enum {
|
||||
TIME_RANGE_SPECIFIER_SPECIFIED = 0,
|
||||
TIME_RANGE_SPECIFIER_ALWAYS = 1
|
||||
} BACNET_ACCESS_RULE_TIME_RANGE_SPECIFIER;
|
||||
|
||||
typedef enum {
|
||||
LOCATION_SPECIFIER_SPECIFIED = 0,
|
||||
LOCATION_SPECIFIER_ALL = 1
|
||||
} BACNET_ACCESS_RULE_LOCATION_SPECIFIER;
|
||||
|
||||
typedef struct {
|
||||
BACNET_ACCESS_RULE_TIME_RANGE_SPECIFIER time_range_specifier;
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE time_range;
|
||||
BACNET_ACCESS_RULE_LOCATION_SPECIFIER location_specifier;
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE location;
|
||||
bool enable;
|
||||
} BACNET_ACCESS_RULE;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_access_rule(
|
||||
uint8_t * apdu,
|
||||
BACNET_ACCESS_RULE * rule);
|
||||
int bacapp_encode_context_access_rule(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_ACCESS_RULE * rule);
|
||||
int bacapp_decode_access_rule(
|
||||
uint8_t * apdu,
|
||||
BACNET_ACCESS_RULE * rule);
|
||||
int bacapp_decode_context_access_rule(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_ACCESS_RULE * rule);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef ACCESS_RULE_H
|
||||
#define ACCESS_RULE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
|
||||
typedef enum {
|
||||
TIME_RANGE_SPECIFIER_SPECIFIED = 0,
|
||||
TIME_RANGE_SPECIFIER_ALWAYS = 1
|
||||
} BACNET_ACCESS_RULE_TIME_RANGE_SPECIFIER;
|
||||
|
||||
typedef enum {
|
||||
LOCATION_SPECIFIER_SPECIFIED = 0,
|
||||
LOCATION_SPECIFIER_ALL = 1
|
||||
} BACNET_ACCESS_RULE_LOCATION_SPECIFIER;
|
||||
|
||||
typedef struct {
|
||||
BACNET_ACCESS_RULE_TIME_RANGE_SPECIFIER time_range_specifier;
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE time_range;
|
||||
BACNET_ACCESS_RULE_LOCATION_SPECIFIER location_specifier;
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE location;
|
||||
bool enable;
|
||||
} BACNET_ACCESS_RULE;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_access_rule(
|
||||
uint8_t * apdu,
|
||||
BACNET_ACCESS_RULE * rule);
|
||||
int bacapp_encode_context_access_rule(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_ACCESS_RULE * rule);
|
||||
int bacapp_decode_access_rule(
|
||||
uint8_t * apdu,
|
||||
BACNET_ACCESS_RULE * rule);
|
||||
int bacapp_decode_context_access_rule(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_ACCESS_RULE * rule);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,62 +1,62 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BACNET_ASSIGNED_ACCESS_RIGHTS_H
|
||||
#define BACNET_ASSIGNED_ACCESS_RIGHTS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_DEVICE_OBJECT_REFERENCE assigned_access_rights;
|
||||
bool enable;
|
||||
} BACNET_ASSIGNED_ACCESS_RIGHTS;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_assigned_access_rights(
|
||||
uint8_t * apdu,
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
|
||||
int bacapp_encode_context_assigned_access_rights(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
|
||||
int bacapp_decode_assigned_access_rights(
|
||||
uint8_t * apdu,
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
|
||||
int bacapp_decode_context_assigned_access_rights(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BACNET_ASSIGNED_ACCESS_RIGHTS_H
|
||||
#define BACNET_ASSIGNED_ACCESS_RIGHTS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "bacdevobjpropref.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_DEVICE_OBJECT_REFERENCE assigned_access_rights;
|
||||
bool enable;
|
||||
} BACNET_ASSIGNED_ACCESS_RIGHTS;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_assigned_access_rights(
|
||||
uint8_t * apdu,
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
|
||||
int bacapp_encode_context_assigned_access_rights(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
|
||||
int bacapp_decode_assigned_access_rights(
|
||||
uint8_t * apdu,
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
|
||||
int bacapp_decode_context_assigned_access_rights(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_ASSIGNED_ACCESS_RIGHTS * aar);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BACNET_AUTHENTICATION_FACTOR_H
|
||||
#define BACNET_AUTHENTICATION_FACTOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_AUTHENTICATION_FACTOR_TYPE format_type;
|
||||
uint32_t format_class;
|
||||
BACNET_OCTET_STRING value;
|
||||
} BACNET_AUTHENTICATION_FACTOR;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
BACNET_AUTHENTICATION_FACTOR * af);
|
||||
int bacapp_encode_context_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_AUTHENTICATION_FACTOR * af);
|
||||
int bacapp_decode_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
BACNET_AUTHENTICATION_FACTOR * af);
|
||||
int bacapp_decode_context_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_AUTHENTICATION_FACTOR * af);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BACNET_AUTHENTICATION_FACTOR_H
|
||||
#define BACNET_AUTHENTICATION_FACTOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_AUTHENTICATION_FACTOR_TYPE format_type;
|
||||
uint32_t format_class;
|
||||
BACNET_OCTET_STRING value;
|
||||
} BACNET_AUTHENTICATION_FACTOR;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
BACNET_AUTHENTICATION_FACTOR * af);
|
||||
int bacapp_encode_context_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_AUTHENTICATION_FACTOR * af);
|
||||
int bacapp_decode_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
BACNET_AUTHENTICATION_FACTOR * af);
|
||||
int bacapp_decode_context_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_AUTHENTICATION_FACTOR * af);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,60 +1,60 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BACNET_AUTHENTICATION_FACTOR_FORMAT_H
|
||||
#define BACNET_AUTHENTICATION_FACTOR_FORMAT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_AUTHENTICATION_FACTOR_TYPE format_type;
|
||||
uint32_t vendor_id, vendor_format;
|
||||
} BACNET_AUTHENTICATION_FACTOR_FORMAT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_authentication_factor_format(
|
||||
uint8_t * apdu,
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
|
||||
int bacapp_encode_context_authentication_factor_format(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
|
||||
int bacapp_decode_authentication_factor_format(
|
||||
uint8_t * apdu,
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
|
||||
int bacapp_decode_context_authentication_factor_format(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BACNET_AUTHENTICATION_FACTOR_FORMAT_H
|
||||
#define BACNET_AUTHENTICATION_FACTOR_FORMAT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_AUTHENTICATION_FACTOR_TYPE format_type;
|
||||
uint32_t vendor_id, vendor_format;
|
||||
} BACNET_AUTHENTICATION_FACTOR_FORMAT;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_authentication_factor_format(
|
||||
uint8_t * apdu,
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
|
||||
int bacapp_encode_context_authentication_factor_format(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
|
||||
int bacapp_decode_authentication_factor_format(
|
||||
uint8_t * apdu,
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
|
||||
int bacapp_decode_context_authentication_factor_format(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_AUTHENTICATION_FACTOR_FORMAT * aff);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,62 +1,62 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef _BAC_TIME_VALUE_H_
|
||||
#define _BAC_TIME_VALUE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_TIME Time;
|
||||
BACNET_APPLICATION_DATA_VALUE Value;
|
||||
} BACNET_TIME_VALUE;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_time_value(uint8_t * apdu,
|
||||
BACNET_TIME_VALUE * value);
|
||||
|
||||
int bacapp_encode_context_time_value(uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_TIME_VALUE * value);
|
||||
|
||||
int bacapp_decode_time_value(uint8_t * apdu,
|
||||
BACNET_TIME_VALUE * value);
|
||||
|
||||
int bacapp_decode_context_time_value(uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_TIME_VALUE * value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef _BAC_TIME_VALUE_H_
|
||||
#define _BAC_TIME_VALUE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_TIME Time;
|
||||
BACNET_APPLICATION_DATA_VALUE Value;
|
||||
} BACNET_TIME_VALUE;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_time_value(uint8_t * apdu,
|
||||
BACNET_TIME_VALUE * value);
|
||||
|
||||
int bacapp_encode_context_time_value(uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_TIME_VALUE * value);
|
||||
|
||||
int bacapp_decode_time_value(uint8_t * apdu,
|
||||
BACNET_TIME_VALUE * value);
|
||||
|
||||
int bacapp_decode_context_time_value(uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_TIME_VALUE * value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BACNET_CREDENTIAL_AUTHENTICATION_FACTOR_H
|
||||
#define BACNET_CREDENTIAL_AUTHENTICATION_FACTOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "authentication_factor.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_ACCESS_AUTHENTICATION_FACTOR_DISABLE disable;
|
||||
BACNET_AUTHENTICATION_FACTOR authentication_factor;
|
||||
} BACNET_CREDENTIAL_AUTHENTICATION_FACTOR;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_credential_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
|
||||
int bacapp_encode_context_credential_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
|
||||
int bacapp_decode_credential_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
|
||||
int bacapp_decode_context_credential_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Nikola Jelic <nikola.jelic@euroicc.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef BACNET_CREDENTIAL_AUTHENTICATION_FACTOR_H
|
||||
#define BACNET_CREDENTIAL_AUTHENTICATION_FACTOR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacapp.h"
|
||||
#include "authentication_factor.h"
|
||||
|
||||
typedef struct {
|
||||
BACNET_ACCESS_AUTHENTICATION_FACTOR_DISABLE disable;
|
||||
BACNET_AUTHENTICATION_FACTOR authentication_factor;
|
||||
} BACNET_CREDENTIAL_AUTHENTICATION_FACTOR;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int bacapp_encode_credential_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
|
||||
int bacapp_encode_context_credential_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
|
||||
int bacapp_decode_credential_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
|
||||
int bacapp_decode_context_credential_authentication_factor(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag,
|
||||
BACNET_CREDENTIAL_AUTHENTICATION_FACTOR * caf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,82 +1,82 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*********************************************************************/
|
||||
#ifndef LIGHTING_H
|
||||
#define LIGHTING_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacenum.h"
|
||||
|
||||
/* BACnetLightingCommand ::= SEQUENCE {
|
||||
operation [0] BACnetLightingOperation,
|
||||
target-level [1] REAL (0.0..100.0) OPTIONAL,
|
||||
ramp-rate [2] REAL (0.1..100.0) OPTIONAL,
|
||||
step-increment [3] REAL (0.1..100.0) OPTIONAL,
|
||||
fade-time [4] Unsigned (100.. 86400000) OPTIONAL,
|
||||
priority [5] Unsigned (1..16) OPTIONAL
|
||||
}
|
||||
-- Note that the combination of level, ramp-rate, step-increment, and fade-time fields is
|
||||
-- dependent on the specific lighting operation. See Table 12-67.
|
||||
*/
|
||||
typedef struct BACnetLightingCommand {
|
||||
BACNET_LIGHTING_OPERATION operation;
|
||||
/* fields are optional */
|
||||
bool use_target_level:1;
|
||||
bool use_ramp_rate:1;
|
||||
bool use_step_increment:1;
|
||||
bool use_fade_time:1;
|
||||
bool use_priority:1;
|
||||
float target_level;
|
||||
float ramp_rate;
|
||||
float step_increment;
|
||||
uint32_t fade_time;
|
||||
uint8_t priority;
|
||||
} BACNET_LIGHTING_COMMAND;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int lighting_command_encode(
|
||||
uint8_t * apdu,
|
||||
BACNET_LIGHTING_COMMAND * data);
|
||||
int lighting_command_encode_context(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_LIGHTING_COMMAND * value);
|
||||
int lighting_command_decode(
|
||||
uint8_t * apdu,
|
||||
unsigned apdu_max_len,
|
||||
BACNET_LIGHTING_COMMAND * data);
|
||||
bool lighting_command_copy(
|
||||
BACNET_LIGHTING_COMMAND * dst,
|
||||
BACNET_LIGHTING_COMMAND * src);
|
||||
bool lighting_command_same(
|
||||
BACNET_LIGHTING_COMMAND * dst,
|
||||
BACNET_LIGHTING_COMMAND * src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*********************************************************************/
|
||||
#ifndef LIGHTING_H
|
||||
#define LIGHTING_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacenum.h"
|
||||
|
||||
/* BACnetLightingCommand ::= SEQUENCE {
|
||||
operation [0] BACnetLightingOperation,
|
||||
target-level [1] REAL (0.0..100.0) OPTIONAL,
|
||||
ramp-rate [2] REAL (0.1..100.0) OPTIONAL,
|
||||
step-increment [3] REAL (0.1..100.0) OPTIONAL,
|
||||
fade-time [4] Unsigned (100.. 86400000) OPTIONAL,
|
||||
priority [5] Unsigned (1..16) OPTIONAL
|
||||
}
|
||||
-- Note that the combination of level, ramp-rate, step-increment, and fade-time fields is
|
||||
-- dependent on the specific lighting operation. See Table 12-67.
|
||||
*/
|
||||
typedef struct BACnetLightingCommand {
|
||||
BACNET_LIGHTING_OPERATION operation;
|
||||
/* fields are optional */
|
||||
bool use_target_level:1;
|
||||
bool use_ramp_rate:1;
|
||||
bool use_step_increment:1;
|
||||
bool use_fade_time:1;
|
||||
bool use_priority:1;
|
||||
float target_level;
|
||||
float ramp_rate;
|
||||
float step_increment;
|
||||
uint32_t fade_time;
|
||||
uint8_t priority;
|
||||
} BACNET_LIGHTING_COMMAND;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int lighting_command_encode(
|
||||
uint8_t * apdu,
|
||||
BACNET_LIGHTING_COMMAND * data);
|
||||
int lighting_command_encode_context(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_LIGHTING_COMMAND * value);
|
||||
int lighting_command_decode(
|
||||
uint8_t * apdu,
|
||||
unsigned apdu_max_len,
|
||||
BACNET_LIGHTING_COMMAND * data);
|
||||
bool lighting_command_copy(
|
||||
BACNET_LIGHTING_COMMAND * dst,
|
||||
BACNET_LIGHTING_COMMAND * src);
|
||||
bool lighting_command_same(
|
||||
BACNET_LIGHTING_COMMAND * dst,
|
||||
BACNET_LIGHTING_COMMAND * src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
+41
-41
@@ -1,41 +1,41 @@
|
||||
rem Indent the C and H files with specific coding standard
|
||||
rem requires 'indent.exe' from MSYS (MinGW).
|
||||
rem See http://www.gnu.org/software/indent/manual/indent.pdf
|
||||
set OPTIONS=-kr -nut -nlp -ip4 -cli4 -bfda -nbc -nbbo -c0 -cd0 -cp0 -di0 -l79 -nhnl
|
||||
rem -kr The Kernighan & Ritchie style, corresponds to the following options:
|
||||
rem -nbad -bap -bbo -nbc -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0
|
||||
rem -cp33 -cs -d0 -di1 -nfc1 -nfca -hnl -i4 -ip0 -l75 -lp -npcs
|
||||
rem -nprs -npsl -saf -sai -saw -nsc -nsob -nss
|
||||
rem -nut Use spaces instead of tabs.
|
||||
rem -nlp Do not line up parentheses.
|
||||
rem -ip4 Indent parameter types in old-style function definitions by n spaces.
|
||||
rem -cli4 Case label indent of n spaces.
|
||||
rem -bfda Break the line before all arguments in a declaration.
|
||||
rem -nbc Do not force newlines after commas in declarations.
|
||||
rem -nbbo Do not prefer to break long lines before boolean operators.
|
||||
rem -c0 Put comments to the right of code in column n.
|
||||
rem -cd0 Put comments to the right of the declarations in column n.
|
||||
rem -cp0 Put comments to the right of #else and #endif statements in column n.
|
||||
rem -di0 Put variables in column n.
|
||||
rem -l79 Set maximum line length for non-comment lines to n.
|
||||
rem -nhnl Do not prefer to break long lines at the position of newlines in the input.
|
||||
|
||||
call :treeProcess
|
||||
goto :eof
|
||||
|
||||
:treeProcess
|
||||
rem perform the indent on all the files of this subdirectory:
|
||||
for %%f in (*.c) do (
|
||||
indent.exe "%%f" -o "%%f" %OPTIONS%
|
||||
)
|
||||
for %%f in (*.h) do (
|
||||
indent.exe "%%f" -o "%%f" %OPTIONS%
|
||||
)
|
||||
rem loop over all directories and sub directories
|
||||
for /D %%d in (*) do (
|
||||
cd %%d
|
||||
call :treeProcess
|
||||
cd ..
|
||||
)
|
||||
exit /b
|
||||
|
||||
rem Indent the C and H files with specific coding standard
|
||||
rem requires 'indent.exe' from MSYS (MinGW).
|
||||
rem See http://www.gnu.org/software/indent/manual/indent.pdf
|
||||
set OPTIONS=-kr -nut -nlp -ip4 -cli4 -bfda -nbc -nbbo -c0 -cd0 -cp0 -di0 -l79 -nhnl
|
||||
rem -kr The Kernighan & Ritchie style, corresponds to the following options:
|
||||
rem -nbad -bap -bbo -nbc -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0
|
||||
rem -cp33 -cs -d0 -di1 -nfc1 -nfca -hnl -i4 -ip0 -l75 -lp -npcs
|
||||
rem -nprs -npsl -saf -sai -saw -nsc -nsob -nss
|
||||
rem -nut Use spaces instead of tabs.
|
||||
rem -nlp Do not line up parentheses.
|
||||
rem -ip4 Indent parameter types in old-style function definitions by n spaces.
|
||||
rem -cli4 Case label indent of n spaces.
|
||||
rem -bfda Break the line before all arguments in a declaration.
|
||||
rem -nbc Do not force newlines after commas in declarations.
|
||||
rem -nbbo Do not prefer to break long lines before boolean operators.
|
||||
rem -c0 Put comments to the right of code in column n.
|
||||
rem -cd0 Put comments to the right of the declarations in column n.
|
||||
rem -cp0 Put comments to the right of #else and #endif statements in column n.
|
||||
rem -di0 Put variables in column n.
|
||||
rem -l79 Set maximum line length for non-comment lines to n.
|
||||
rem -nhnl Do not prefer to break long lines at the position of newlines in the input.
|
||||
|
||||
call :treeProcess
|
||||
goto :eof
|
||||
|
||||
:treeProcess
|
||||
rem perform the indent on all the files of this subdirectory:
|
||||
for %%f in (*.c) do (
|
||||
indent.exe "%%f" -o "%%f" %OPTIONS%
|
||||
)
|
||||
for %%f in (*.h) do (
|
||||
indent.exe "%%f" -o "%%f" %OPTIONS%
|
||||
)
|
||||
rem loop over all directories and sub directories
|
||||
for /D %%d in (*) do (
|
||||
cd %%d
|
||||
call :treeProcess
|
||||
cd ..
|
||||
)
|
||||
exit /b
|
||||
|
||||
|
||||
@@ -1,144 +1,144 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "apdu.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "handlers.h"
|
||||
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (service_supported == SERVICE_SUPPORTED_READ_PROPERTY) {
|
||||
status = true;
|
||||
}
|
||||
if (service_supported == SERVICE_SUPPORTED_WHO_IS) {
|
||||
status = true;
|
||||
}
|
||||
#ifdef WRITE_PROPERTY
|
||||
if (service_supported == SERVICE_SUPPORTED_WRITE_PROPERTY) {
|
||||
status = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, /* APDU data */
|
||||
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request, service_request_len,
|
||||
src, &service_data);
|
||||
}
|
||||
#ifdef WRITE_PROPERTY
|
||||
else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "apdu.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "handlers.h"
|
||||
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (service_supported == SERVICE_SUPPORTED_READ_PROPERTY) {
|
||||
status = true;
|
||||
}
|
||||
if (service_supported == SERVICE_SUPPORTED_WHO_IS) {
|
||||
status = true;
|
||||
}
|
||||
#ifdef WRITE_PROPERTY
|
||||
if (service_supported == SERVICE_SUPPORTED_WRITE_PROPERTY) {
|
||||
status = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, /* APDU data */
|
||||
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request, service_request_len,
|
||||
src, &service_data);
|
||||
}
|
||||
#ifdef WRITE_PROPERTY
|
||||
else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
+254
-254
@@ -1,254 +1,254 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "av.h"
|
||||
|
||||
#if (MAX_ANALOG_VALUES > 10)
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
float AV_Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(void)
|
||||
{
|
||||
return MAX_ANALOG_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
return object_instance;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "AV-"; /* okay for single thread */
|
||||
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
|
||||
return text_string;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index;
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(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_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0],
|
||||
AV_Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
AV_Present_Value[object_index] = value.type.Real;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalog_Value(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_VALUE;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
len =
|
||||
Analog_Value_Encode_Property_APDU(&apdu[0], instance,
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len =
|
||||
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_ANALOG_VALUE);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Analog Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAnalog_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "av.h"
|
||||
|
||||
#if (MAX_ANALOG_VALUES > 10)
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
float AV_Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(void)
|
||||
{
|
||||
return MAX_ANALOG_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
return object_instance;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "AV-"; /* okay for single thread */
|
||||
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
|
||||
return text_string;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index;
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(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_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0],
|
||||
AV_Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
AV_Present_Value[object_index] = value.type.Real;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalog_Value(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_VALUE;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
len =
|
||||
Analog_Value_Encode_Property_APDU(&apdu[0], instance,
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len =
|
||||
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_ANALOG_VALUE);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Analog Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAnalog_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,75 +1,75 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef AV_H
|
||||
#define AV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifndef MAX_ANALOG_VALUES
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
void Analog_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Analog_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Analog_Value_Count(void);
|
||||
uint32_t Analog_Value_Index_To_Instance(unsigned index);
|
||||
char *Analog_Value_Name(uint32_t object_instance);
|
||||
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Analog_Value_Present_Value_Set(uint32_t object_instance,
|
||||
float value,
|
||||
uint8_t priority);
|
||||
float Analog_Value_Present_Value(uint32_t object_instance);
|
||||
|
||||
void Analog_Value_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAnalog_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef AV_H
|
||||
#define AV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifndef MAX_ANALOG_VALUES
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
void Analog_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Analog_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Analog_Value_Count(void);
|
||||
uint32_t Analog_Value_Index_To_Instance(unsigned index);
|
||||
char *Analog_Value_Name(uint32_t object_instance);
|
||||
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Analog_Value_Present_Value_Set(uint32_t object_instance,
|
||||
float value,
|
||||
uint8_t priority);
|
||||
float Analog_Value_Present_Value(uint32_t object_instance);
|
||||
|
||||
void Analog_Value_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAnalog_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,166 +1,166 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdio.h>
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
//#include "net.h"
|
||||
|
||||
/** @file linux/bip-init.c Initializes BACnet/IP interface (Linux). */
|
||||
|
||||
bool BIP_Debug = false;
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
a name that is a domain name
|
||||
returns 0 if not found, or
|
||||
an IP address in network byte order */
|
||||
long bip_getaddrbyname(const char *host_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* Eg, for Linux, ifname is eth0, ath0, arc0, and others.
|
||||
*/
|
||||
void bip_set_interface(char *ifname)
|
||||
{
|
||||
|
||||
uint8_t local_address[] = { 0, 0, 0, 0 };
|
||||
uint8_t broadcast_address[] = { 0, 0, 0, 0 };
|
||||
uint8_t netmask[] = { 0, 0, 0, 0 };
|
||||
uint8_t invertedNetmask[] = { 0, 0, 0, 0 };
|
||||
|
||||
getIPAddress_func(CW5100Class_new(), local_address);
|
||||
bip_set_addr(local_address);
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "Interface: %s\n", ifname);
|
||||
fprintf(stderr, "IP Address: %d.%d.%d.%d\n", local_address[0],
|
||||
local_address[1], local_address[2], local_address[3]);
|
||||
}
|
||||
|
||||
/* setup local broadcast address */
|
||||
getSubnetMask_func(CW5100Class_new(), netmask);
|
||||
for (int i = 0; i < 4; i++) { //FIXME: IPv4 ?
|
||||
invertedNetmask[i] = ~netmask[i];
|
||||
broadcast_address[i] = (local_address[i] | invertedNetmask[i]);
|
||||
}
|
||||
|
||||
bip_set_broadcast_addr(broadcast_address);
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "IP Broadcast Address: %d.%d.%d.%d\n",
|
||||
broadcast_address[0], broadcast_address[1], broadcast_address[2],
|
||||
broadcast_address[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize the BACnet/IP services at the given interface.
|
||||
* @ingroup DLBIP
|
||||
* -# Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
* -# Opens a UDP socket
|
||||
* -# Configures the socket for sending and receiving
|
||||
* -# Configures the socket so it can send broadcasts
|
||||
* -# Binds the socket to the local IP address at the specified port for
|
||||
* BACnet/IP (by default, 0xBAC0 = 47808).
|
||||
*
|
||||
* @note For Linux, ifname is eth0, ath0, arc0, and others.
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* If NULL, the "eth0" interface is assigned.
|
||||
* @return True if the socket is successfully opened for BACnet/IP,
|
||||
* else False if the socket functions fail.
|
||||
*/
|
||||
bool bip_init(char *ifname)
|
||||
{
|
||||
uint8_t sock_fd = 0;
|
||||
bool isOpen = false;
|
||||
|
||||
if (ifname)
|
||||
bip_set_interface(ifname);
|
||||
else
|
||||
bip_set_interface("eth0");
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
for (sock_fd = 0; sock_fd < MAX_SOCK_NUM; sock_fd++) {
|
||||
if (readSnSR_func(CW5100Class_new(), sock_fd) == SnSR_CLOSED()) {
|
||||
socket_func(sock_fd, SnMR_UDP(), (uint16_t) 47808, 0);
|
||||
listen_func(sock_fd);
|
||||
isOpen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOpen) {
|
||||
bip_set_socket(MAX_SOCK_NUM);
|
||||
return false;
|
||||
} else {
|
||||
bip_set_socket(sock_fd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Cleanup and close out the BACnet/IP services by closing the socket.
|
||||
* @ingroup DLBIP
|
||||
*/
|
||||
void bip_cleanup(void)
|
||||
{
|
||||
int sock_fd = 0;
|
||||
|
||||
if (bip_valid()) {
|
||||
sock_fd = bip_socket();
|
||||
close_func(sock_fd);
|
||||
}
|
||||
bip_set_socket(MAX_SOCK_NUM);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Get the netmask of the BACnet/IP's interface via an ioctl() call.
|
||||
* @param netmask [out] The netmask, in host order.
|
||||
* @return 0 on success, else the error from the ioctl() call.
|
||||
*/
|
||||
int bip_get_local_netmask(uint8_t * netmask)
|
||||
{
|
||||
getSubnetMask_func(CW5100Class_new(), netmask);
|
||||
return 0;
|
||||
}
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdio.h>
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
//#include "net.h"
|
||||
|
||||
/** @file linux/bip-init.c Initializes BACnet/IP interface (Linux). */
|
||||
|
||||
bool BIP_Debug = false;
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
a name that is a domain name
|
||||
returns 0 if not found, or
|
||||
an IP address in network byte order */
|
||||
long bip_getaddrbyname(const char *host_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* Eg, for Linux, ifname is eth0, ath0, arc0, and others.
|
||||
*/
|
||||
void bip_set_interface(char *ifname)
|
||||
{
|
||||
|
||||
uint8_t local_address[] = { 0, 0, 0, 0 };
|
||||
uint8_t broadcast_address[] = { 0, 0, 0, 0 };
|
||||
uint8_t netmask[] = { 0, 0, 0, 0 };
|
||||
uint8_t invertedNetmask[] = { 0, 0, 0, 0 };
|
||||
|
||||
getIPAddress_func(CW5100Class_new(), local_address);
|
||||
bip_set_addr(local_address);
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "Interface: %s\n", ifname);
|
||||
fprintf(stderr, "IP Address: %d.%d.%d.%d\n", local_address[0],
|
||||
local_address[1], local_address[2], local_address[3]);
|
||||
}
|
||||
|
||||
/* setup local broadcast address */
|
||||
getSubnetMask_func(CW5100Class_new(), netmask);
|
||||
for (int i = 0; i < 4; i++) { //FIXME: IPv4 ?
|
||||
invertedNetmask[i] = ~netmask[i];
|
||||
broadcast_address[i] = (local_address[i] | invertedNetmask[i]);
|
||||
}
|
||||
|
||||
bip_set_broadcast_addr(broadcast_address);
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "IP Broadcast Address: %d.%d.%d.%d\n",
|
||||
broadcast_address[0], broadcast_address[1], broadcast_address[2],
|
||||
broadcast_address[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize the BACnet/IP services at the given interface.
|
||||
* @ingroup DLBIP
|
||||
* -# Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
* -# Opens a UDP socket
|
||||
* -# Configures the socket for sending and receiving
|
||||
* -# Configures the socket so it can send broadcasts
|
||||
* -# Binds the socket to the local IP address at the specified port for
|
||||
* BACnet/IP (by default, 0xBAC0 = 47808).
|
||||
*
|
||||
* @note For Linux, ifname is eth0, ath0, arc0, and others.
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* If NULL, the "eth0" interface is assigned.
|
||||
* @return True if the socket is successfully opened for BACnet/IP,
|
||||
* else False if the socket functions fail.
|
||||
*/
|
||||
bool bip_init(char *ifname)
|
||||
{
|
||||
uint8_t sock_fd = 0;
|
||||
bool isOpen = false;
|
||||
|
||||
if (ifname)
|
||||
bip_set_interface(ifname);
|
||||
else
|
||||
bip_set_interface("eth0");
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
for (sock_fd = 0; sock_fd < MAX_SOCK_NUM; sock_fd++) {
|
||||
if (readSnSR_func(CW5100Class_new(), sock_fd) == SnSR_CLOSED()) {
|
||||
socket_func(sock_fd, SnMR_UDP(), (uint16_t) 47808, 0);
|
||||
listen_func(sock_fd);
|
||||
isOpen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOpen) {
|
||||
bip_set_socket(MAX_SOCK_NUM);
|
||||
return false;
|
||||
} else {
|
||||
bip_set_socket(sock_fd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Cleanup and close out the BACnet/IP services by closing the socket.
|
||||
* @ingroup DLBIP
|
||||
*/
|
||||
void bip_cleanup(void)
|
||||
{
|
||||
int sock_fd = 0;
|
||||
|
||||
if (bip_valid()) {
|
||||
sock_fd = bip_socket();
|
||||
close_func(sock_fd);
|
||||
}
|
||||
bip_set_socket(MAX_SOCK_NUM);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Get the netmask of the BACnet/IP's interface via an ioctl() call.
|
||||
* @param netmask [out] The netmask, in host order.
|
||||
* @return 0 on success, else the error from the ioctl() call.
|
||||
*/
|
||||
int bip_get_local_netmask(uint8_t * netmask)
|
||||
{
|
||||
getSubnetMask_func(CW5100Class_new(), netmask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,413 +1,413 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <string.h>
|
||||
#include "bacdcode.h"
|
||||
#include "bacint.h"
|
||||
#include "bip.h"
|
||||
#include "bvlc-arduino.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
|
||||
|
||||
#if PRINT_ENABLED | DEBUG
|
||||
#include <stdio.h> /* for standard i/o, like printing */
|
||||
#endif
|
||||
|
||||
/** @file bip.c Configuration and Operations for BACnet/IP */
|
||||
|
||||
static uint8_t BIP_Socket = MAX_SOCK_NUM;
|
||||
/* port to use - stored in network byte order */
|
||||
static uint16_t BIP_Port = 0; /* this will force initialization in demos */
|
||||
/* IP Address - stored in network byte order */
|
||||
//static struct in_addr BIP_Address;
|
||||
static uint8_t BIP_Address[4] = { 0, 0, 0, 0 };
|
||||
/* Broadcast Address - stored in network byte order */
|
||||
//static struct in_addr BIP_Broadcast_Address;
|
||||
static uint8_t BIP_Broadcast_Address[4] = { 0, 0, 0, 0 };
|
||||
|
||||
/** Converter from uint8_t[4] type address to uint32_t
|
||||
*
|
||||
*/
|
||||
uint32_t convertBIP_Address2uint32(uint8_t * bip_address)
|
||||
{
|
||||
return (uint32_t) ((bip_address[0] * 2 ^ 24) + (bip_address[1] * 2 ^ 16) +
|
||||
(bip_address[2] * 2 ^ 8) + bip_address[3]);
|
||||
}
|
||||
|
||||
/** Convert from uint32_t IPv4 address to uint8_t[4] address
|
||||
*
|
||||
*/
|
||||
void convertUint32Address_2_uint8Address(uint32_t ip,
|
||||
uint8_t * address)
|
||||
{
|
||||
address[0] = (uint8_t) (ip >> 24);
|
||||
address[1] = (uint8_t) (ip >> 16);
|
||||
address[2] = (uint8_t) (ip >> 8);
|
||||
address[3] = (uint8_t) (ip >> 0);
|
||||
}
|
||||
|
||||
/** Setter for the BACnet/IP socket handle.
|
||||
*
|
||||
* @param sock_fd [in] Handle for the BACnet/IP socket.
|
||||
*/
|
||||
void bip_set_socket(uint8_t sock_fd)
|
||||
{
|
||||
BIP_Socket = sock_fd;
|
||||
}
|
||||
|
||||
/** Getter for the BACnet/IP socket handle.
|
||||
*
|
||||
* @return The handle to the BACnet/IP socket.
|
||||
*/
|
||||
uint8_t bip_socket(void)
|
||||
{
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket < MAX_SOCK_NUM);
|
||||
}
|
||||
|
||||
void bip_set_addr(uint8_t * net_address)
|
||||
{ /* in network byte order */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
BIP_Address[i] = net_address[i];
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint8_t *bip_get_addr(void)
|
||||
{
|
||||
return BIP_Address;
|
||||
}
|
||||
|
||||
void bip_set_broadcast_addr(uint8_t * net_address)
|
||||
{ /* in network byte order */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
BIP_Broadcast_Address[i] = net_address[i];
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint8_t *bip_get_broadcast_addr(void)
|
||||
{
|
||||
return BIP_Broadcast_Address;
|
||||
}
|
||||
|
||||
|
||||
void bip_set_port(uint16_t port)
|
||||
{ /* in network byte order */
|
||||
BIP_Port = port;
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return BIP_Port;
|
||||
}
|
||||
|
||||
static int bip_decode_bip_address(BACNET_ADDRESS * bac_addr,
|
||||
uint8_t * address, /* in network format */
|
||||
|
||||
uint16_t * port)
|
||||
{ /* in network format */
|
||||
int len = 0;
|
||||
|
||||
if (bac_addr) {
|
||||
memcpy(address, &bac_addr->mac[0], 4);
|
||||
memcpy(port, &bac_addr->mac[4], 2);
|
||||
len = 6;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Function to send a packet out the BACnet/IP socket (Annex J).
|
||||
* @ingroup DLBIP
|
||||
*
|
||||
* @param dest [in] Destination address (may encode an IP address and port #).
|
||||
* @param npdu_data [in] The NPDU header (Network) information (not used).
|
||||
* @param pdu [in] Buffer of data to be sent - may be null (why?).
|
||||
* @param pdu_len [in] Number of bytes in the pdu buffer.
|
||||
* @return Number of bytes sent on success, negative number on failure.
|
||||
*/
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
/* addr and port in host format */
|
||||
uint8_t address[] = { 0, 0, 0, 0 };
|
||||
uint16_t port = 0;
|
||||
|
||||
(void) npdu_data;
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0) {
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
if ((dest->net == BACNET_BROADCAST_NETWORK) || ((dest->net > 0) &&
|
||||
(dest->len == 0)) || (dest->mac_len == 0)) {
|
||||
/* broadcast */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
address[i] = BIP_Broadcast_Address[i];
|
||||
port = BIP_Port;
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Send Broadcast NPDU to %d.%d.%d.%d:%d\n", address[0],
|
||||
address[1]
|
||||
, address[2], address[3], port);
|
||||
#endif
|
||||
} else if (dest->mac_len == 6) {
|
||||
bip_decode_bip_address(dest, address, &port);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Send Unicast NPDU to %d.%d.%d.%d:%d\n", address[0],
|
||||
address[1]
|
||||
, address[2], address[3], port);
|
||||
#endif
|
||||
} else {
|
||||
/* invalid address */
|
||||
return -1;
|
||||
}
|
||||
|
||||
mtu_len = 2;
|
||||
mtu_len +=
|
||||
encode_unsigned16(&mtu[mtu_len],
|
||||
(uint16_t) (pdu_len + 4 /*inclusive */ ));
|
||||
memcpy(&mtu[mtu_len], pdu, pdu_len);
|
||||
mtu_len += pdu_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "MTU size %d\n", mtu_len);
|
||||
#endif
|
||||
|
||||
/* Send the packet */
|
||||
bytes_sent =
|
||||
sendto_func(BIP_Socket, mtu, (uint16_t) mtu_len, address, port);
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/** Implementation of the receive() function for BACnet/IP; receives one
|
||||
* packet, verifies its BVLC header, and removes the BVLC header from
|
||||
* the PDU data before returning.
|
||||
*
|
||||
* @param src [out] Source of the packet - who should receive any response.
|
||||
* @param pdu [out] A buffer to hold the PDU portion of the received packet,
|
||||
* after the BVLC portion has been stripped off.
|
||||
* @param max_pdu [in] Size of the pdu[] buffer.
|
||||
* @param timeout [in] The number of milliseconds to wait for a packet.
|
||||
* @return The number of octets (remaining) in the PDU, or zero on failure.
|
||||
*/
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, /* source address */
|
||||
|
||||
uint8_t * pdu, /* PDU data */
|
||||
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
|
||||
unsigned timeout)
|
||||
{
|
||||
int received_bytes = 0;
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t src_addr[] = { 0, 0, 0, 0 };
|
||||
uint16_t src_port = 0;
|
||||
uint16_t i = 0;
|
||||
int function = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (BIP_Socket < 0)
|
||||
return 0;
|
||||
|
||||
if (getRXReceivedSize_func(CW5100Class_new(), BIP_Socket)) {
|
||||
memcpy(&src_addr, &src->mac[0], 4);
|
||||
memcpy(&src_port, &src->mac[4], 2);
|
||||
received_bytes =
|
||||
(int) recvfrom_func(BIP_Socket, &pdu[0], max_pdu, src_addr,
|
||||
&src_port);
|
||||
}
|
||||
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0)
|
||||
return 0;
|
||||
|
||||
/* the signature of a BACnet/IP packet */
|
||||
if (pdu[0] != BVLL_TYPE_BACNET_IP)
|
||||
return 0;
|
||||
|
||||
if (bvlc_for_non_bbmd(src_addr, &src_port, pdu, received_bytes) > 0) {
|
||||
/* Handled, usually with a NACK. */
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "BIP: BVLC discarded!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
function = bvlc_get_function_code(); /* aka, pdu[1] */
|
||||
if ((function == BVLC_ORIGINAL_UNICAST_NPDU) ||
|
||||
(function == BVLC_ORIGINAL_BROADCAST_NPDU)) {
|
||||
/* ignore messages from me */
|
||||
if ((convertBIP_Address2uint32(src_addr) ==
|
||||
convertBIP_Address2uint32(BIP_Address)) &&
|
||||
(src_port == BIP_Port)) {
|
||||
pdu_len = 0;
|
||||
#if 0
|
||||
fprintf(stderr, "BIP: src is me. Discarded!\n");
|
||||
#endif
|
||||
} else {
|
||||
/* data in src->mac[] is in network format */
|
||||
src->mac_len = 6;
|
||||
memcpy(&src->mac[0], &src_addr, 4);
|
||||
memcpy(&src->mac[4], &src_port, 2);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "BIP receive from %d.%d.%d.%d\n", src->mac[0],
|
||||
src->mac[1], src->mac[2], src->mac[3]);
|
||||
#endif
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void) decode_unsigned16(&pdu[2], &pdu_len);
|
||||
/* subtract off the BVLC header */
|
||||
pdu_len -= 4;
|
||||
if (pdu_len < max_pdu) {
|
||||
#if 0
|
||||
fprintf(stderr, "BIP: NPDU[%hu]:", pdu_len);
|
||||
#endif
|
||||
/* shift the buffer to return a valid PDU */
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
pdu[i] = pdu[4 + i];
|
||||
#if 0
|
||||
fprintf(stderr, "%02X ", pdu[i]);
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
}
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
else {
|
||||
pdu_len = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "BIP: PDU too large. Discarded!.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (function == BVLC_FORWARDED_NPDU) {
|
||||
memcpy(&src_addr, &pdu[4], 4);
|
||||
memcpy(&src_port, &pdu[8], 2);
|
||||
if ((convertBIP_Address2uint32(src_addr) ==
|
||||
convertBIP_Address2uint32(BIP_Address)) &&
|
||||
(src_port == BIP_Port)) {
|
||||
/* ignore messages from me */
|
||||
pdu_len = 0;
|
||||
} else {
|
||||
/* data in src->mac[] is in network format */
|
||||
src->mac_len = 6;
|
||||
memcpy(&src->mac[0], &src_addr, 4);
|
||||
memcpy(&src->mac[4], &src_port, 2);
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void) decode_unsigned16(&pdu[2], &pdu_len);
|
||||
/* subtract off the BVLC header */
|
||||
pdu_len -= 10;
|
||||
if (pdu_len < max_pdu) {
|
||||
/* shift the buffer to return a valid PDU */
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
pdu[i] = pdu[4 + 6 + i];
|
||||
}
|
||||
} else {
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
pdu_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (my_address) {
|
||||
my_address->mac_len = 6;
|
||||
memcpy(&my_address->mac[0], &BIP_Address, 4);
|
||||
memcpy(&my_address->mac[4], &BIP_Port, 2);
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
memcpy(&dest->mac[0], &BIP_Broadcast_Address, 4);
|
||||
memcpy(&dest->mac[4], &BIP_Port, 2);
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <string.h>
|
||||
#include "bacdcode.h"
|
||||
#include "bacint.h"
|
||||
#include "bip.h"
|
||||
#include "bvlc-arduino.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
|
||||
|
||||
#if PRINT_ENABLED | DEBUG
|
||||
#include <stdio.h> /* for standard i/o, like printing */
|
||||
#endif
|
||||
|
||||
/** @file bip.c Configuration and Operations for BACnet/IP */
|
||||
|
||||
static uint8_t BIP_Socket = MAX_SOCK_NUM;
|
||||
/* port to use - stored in network byte order */
|
||||
static uint16_t BIP_Port = 0; /* this will force initialization in demos */
|
||||
/* IP Address - stored in network byte order */
|
||||
//static struct in_addr BIP_Address;
|
||||
static uint8_t BIP_Address[4] = { 0, 0, 0, 0 };
|
||||
/* Broadcast Address - stored in network byte order */
|
||||
//static struct in_addr BIP_Broadcast_Address;
|
||||
static uint8_t BIP_Broadcast_Address[4] = { 0, 0, 0, 0 };
|
||||
|
||||
/** Converter from uint8_t[4] type address to uint32_t
|
||||
*
|
||||
*/
|
||||
uint32_t convertBIP_Address2uint32(uint8_t * bip_address)
|
||||
{
|
||||
return (uint32_t) ((bip_address[0] * 2 ^ 24) + (bip_address[1] * 2 ^ 16) +
|
||||
(bip_address[2] * 2 ^ 8) + bip_address[3]);
|
||||
}
|
||||
|
||||
/** Convert from uint32_t IPv4 address to uint8_t[4] address
|
||||
*
|
||||
*/
|
||||
void convertUint32Address_2_uint8Address(uint32_t ip,
|
||||
uint8_t * address)
|
||||
{
|
||||
address[0] = (uint8_t) (ip >> 24);
|
||||
address[1] = (uint8_t) (ip >> 16);
|
||||
address[2] = (uint8_t) (ip >> 8);
|
||||
address[3] = (uint8_t) (ip >> 0);
|
||||
}
|
||||
|
||||
/** Setter for the BACnet/IP socket handle.
|
||||
*
|
||||
* @param sock_fd [in] Handle for the BACnet/IP socket.
|
||||
*/
|
||||
void bip_set_socket(uint8_t sock_fd)
|
||||
{
|
||||
BIP_Socket = sock_fd;
|
||||
}
|
||||
|
||||
/** Getter for the BACnet/IP socket handle.
|
||||
*
|
||||
* @return The handle to the BACnet/IP socket.
|
||||
*/
|
||||
uint8_t bip_socket(void)
|
||||
{
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket < MAX_SOCK_NUM);
|
||||
}
|
||||
|
||||
void bip_set_addr(uint8_t * net_address)
|
||||
{ /* in network byte order */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
BIP_Address[i] = net_address[i];
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint8_t *bip_get_addr(void)
|
||||
{
|
||||
return BIP_Address;
|
||||
}
|
||||
|
||||
void bip_set_broadcast_addr(uint8_t * net_address)
|
||||
{ /* in network byte order */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
BIP_Broadcast_Address[i] = net_address[i];
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint8_t *bip_get_broadcast_addr(void)
|
||||
{
|
||||
return BIP_Broadcast_Address;
|
||||
}
|
||||
|
||||
|
||||
void bip_set_port(uint16_t port)
|
||||
{ /* in network byte order */
|
||||
BIP_Port = port;
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return BIP_Port;
|
||||
}
|
||||
|
||||
static int bip_decode_bip_address(BACNET_ADDRESS * bac_addr,
|
||||
uint8_t * address, /* in network format */
|
||||
|
||||
uint16_t * port)
|
||||
{ /* in network format */
|
||||
int len = 0;
|
||||
|
||||
if (bac_addr) {
|
||||
memcpy(address, &bac_addr->mac[0], 4);
|
||||
memcpy(port, &bac_addr->mac[4], 2);
|
||||
len = 6;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Function to send a packet out the BACnet/IP socket (Annex J).
|
||||
* @ingroup DLBIP
|
||||
*
|
||||
* @param dest [in] Destination address (may encode an IP address and port #).
|
||||
* @param npdu_data [in] The NPDU header (Network) information (not used).
|
||||
* @param pdu [in] Buffer of data to be sent - may be null (why?).
|
||||
* @param pdu_len [in] Number of bytes in the pdu buffer.
|
||||
* @return Number of bytes sent on success, negative number on failure.
|
||||
*/
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
/* addr and port in host format */
|
||||
uint8_t address[] = { 0, 0, 0, 0 };
|
||||
uint16_t port = 0;
|
||||
|
||||
(void) npdu_data;
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0) {
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
if ((dest->net == BACNET_BROADCAST_NETWORK) || ((dest->net > 0) &&
|
||||
(dest->len == 0)) || (dest->mac_len == 0)) {
|
||||
/* broadcast */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
address[i] = BIP_Broadcast_Address[i];
|
||||
port = BIP_Port;
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Send Broadcast NPDU to %d.%d.%d.%d:%d\n", address[0],
|
||||
address[1]
|
||||
, address[2], address[3], port);
|
||||
#endif
|
||||
} else if (dest->mac_len == 6) {
|
||||
bip_decode_bip_address(dest, address, &port);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Send Unicast NPDU to %d.%d.%d.%d:%d\n", address[0],
|
||||
address[1]
|
||||
, address[2], address[3], port);
|
||||
#endif
|
||||
} else {
|
||||
/* invalid address */
|
||||
return -1;
|
||||
}
|
||||
|
||||
mtu_len = 2;
|
||||
mtu_len +=
|
||||
encode_unsigned16(&mtu[mtu_len],
|
||||
(uint16_t) (pdu_len + 4 /*inclusive */ ));
|
||||
memcpy(&mtu[mtu_len], pdu, pdu_len);
|
||||
mtu_len += pdu_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "MTU size %d\n", mtu_len);
|
||||
#endif
|
||||
|
||||
/* Send the packet */
|
||||
bytes_sent =
|
||||
sendto_func(BIP_Socket, mtu, (uint16_t) mtu_len, address, port);
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/** Implementation of the receive() function for BACnet/IP; receives one
|
||||
* packet, verifies its BVLC header, and removes the BVLC header from
|
||||
* the PDU data before returning.
|
||||
*
|
||||
* @param src [out] Source of the packet - who should receive any response.
|
||||
* @param pdu [out] A buffer to hold the PDU portion of the received packet,
|
||||
* after the BVLC portion has been stripped off.
|
||||
* @param max_pdu [in] Size of the pdu[] buffer.
|
||||
* @param timeout [in] The number of milliseconds to wait for a packet.
|
||||
* @return The number of octets (remaining) in the PDU, or zero on failure.
|
||||
*/
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, /* source address */
|
||||
|
||||
uint8_t * pdu, /* PDU data */
|
||||
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
|
||||
unsigned timeout)
|
||||
{
|
||||
int received_bytes = 0;
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t src_addr[] = { 0, 0, 0, 0 };
|
||||
uint16_t src_port = 0;
|
||||
uint16_t i = 0;
|
||||
int function = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (BIP_Socket < 0)
|
||||
return 0;
|
||||
|
||||
if (getRXReceivedSize_func(CW5100Class_new(), BIP_Socket)) {
|
||||
memcpy(&src_addr, &src->mac[0], 4);
|
||||
memcpy(&src_port, &src->mac[4], 2);
|
||||
received_bytes =
|
||||
(int) recvfrom_func(BIP_Socket, &pdu[0], max_pdu, src_addr,
|
||||
&src_port);
|
||||
}
|
||||
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0)
|
||||
return 0;
|
||||
|
||||
/* the signature of a BACnet/IP packet */
|
||||
if (pdu[0] != BVLL_TYPE_BACNET_IP)
|
||||
return 0;
|
||||
|
||||
if (bvlc_for_non_bbmd(src_addr, &src_port, pdu, received_bytes) > 0) {
|
||||
/* Handled, usually with a NACK. */
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "BIP: BVLC discarded!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
function = bvlc_get_function_code(); /* aka, pdu[1] */
|
||||
if ((function == BVLC_ORIGINAL_UNICAST_NPDU) ||
|
||||
(function == BVLC_ORIGINAL_BROADCAST_NPDU)) {
|
||||
/* ignore messages from me */
|
||||
if ((convertBIP_Address2uint32(src_addr) ==
|
||||
convertBIP_Address2uint32(BIP_Address)) &&
|
||||
(src_port == BIP_Port)) {
|
||||
pdu_len = 0;
|
||||
#if 0
|
||||
fprintf(stderr, "BIP: src is me. Discarded!\n");
|
||||
#endif
|
||||
} else {
|
||||
/* data in src->mac[] is in network format */
|
||||
src->mac_len = 6;
|
||||
memcpy(&src->mac[0], &src_addr, 4);
|
||||
memcpy(&src->mac[4], &src_port, 2);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "BIP receive from %d.%d.%d.%d\n", src->mac[0],
|
||||
src->mac[1], src->mac[2], src->mac[3]);
|
||||
#endif
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void) decode_unsigned16(&pdu[2], &pdu_len);
|
||||
/* subtract off the BVLC header */
|
||||
pdu_len -= 4;
|
||||
if (pdu_len < max_pdu) {
|
||||
#if 0
|
||||
fprintf(stderr, "BIP: NPDU[%hu]:", pdu_len);
|
||||
#endif
|
||||
/* shift the buffer to return a valid PDU */
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
pdu[i] = pdu[4 + i];
|
||||
#if 0
|
||||
fprintf(stderr, "%02X ", pdu[i]);
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
}
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
else {
|
||||
pdu_len = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "BIP: PDU too large. Discarded!.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (function == BVLC_FORWARDED_NPDU) {
|
||||
memcpy(&src_addr, &pdu[4], 4);
|
||||
memcpy(&src_port, &pdu[8], 2);
|
||||
if ((convertBIP_Address2uint32(src_addr) ==
|
||||
convertBIP_Address2uint32(BIP_Address)) &&
|
||||
(src_port == BIP_Port)) {
|
||||
/* ignore messages from me */
|
||||
pdu_len = 0;
|
||||
} else {
|
||||
/* data in src->mac[] is in network format */
|
||||
src->mac_len = 6;
|
||||
memcpy(&src->mac[0], &src_addr, 4);
|
||||
memcpy(&src->mac[4], &src_port, 2);
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void) decode_unsigned16(&pdu[2], &pdu_len);
|
||||
/* subtract off the BVLC header */
|
||||
pdu_len -= 10;
|
||||
if (pdu_len < max_pdu) {
|
||||
/* shift the buffer to return a valid PDU */
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
pdu[i] = pdu[4 + 6 + i];
|
||||
}
|
||||
} else {
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
pdu_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (my_address) {
|
||||
my_address->mac_len = 6;
|
||||
memcpy(&my_address->mac[0], &BIP_Address, 4);
|
||||
memcpy(&my_address->mac[4], &BIP_Port, 2);
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
memcpy(&dest->mac[0], &BIP_Broadcast_Address, 4);
|
||||
memcpy(&dest->mac[4], &BIP_Port, 2);
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+302
-302
@@ -1,302 +1,302 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "bv.h"
|
||||
|
||||
#if (MAX_BINARY_VALUES > 10)
|
||||
#error Modify the Binary_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
value = Present_Value[object_instance];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "BV-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
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_init_ansi(&char_string,
|
||||
Binary_Value_Name(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_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value = Binary_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
if ((value.type.Enumerated == BINARY_ACTIVE) ||
|
||||
(value.type.Enumerated == BINARY_INACTIVE)) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] =
|
||||
(BACNET_BINARY_PV) value.type.Enumerated;
|
||||
/* 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. */
|
||||
if (Present_Value[0] == BINARY_ACTIVE) {
|
||||
// LED_GREEN_ON();
|
||||
} else {
|
||||
// LED_GREEN_OFF();
|
||||
}
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBinary_Value(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_VALUE;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
|
||||
len =
|
||||
Binary_Value_Encode_Property_APDU(&apdu[0], instance,
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len =
|
||||
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_BINARY_VALUE);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Binary_Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testBinary_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BINARY_VALUE */
|
||||
#endif /* TEST */
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "bv.h"
|
||||
|
||||
#if (MAX_BINARY_VALUES > 10)
|
||||
#error Modify the Binary_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static BACNET_BINARY_PV Binary_Value_Present_Value(uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
value = Present_Value[object_instance];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "BV-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
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_init_ansi(&char_string,
|
||||
Binary_Value_Name(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_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value = Binary_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
if ((value.type.Enumerated == BINARY_ACTIVE) ||
|
||||
(value.type.Enumerated == BINARY_INACTIVE)) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] =
|
||||
(BACNET_BINARY_PV) value.type.Enumerated;
|
||||
/* 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. */
|
||||
if (Present_Value[0] == BINARY_ACTIVE) {
|
||||
// LED_GREEN_ON();
|
||||
} else {
|
||||
// LED_GREEN_OFF();
|
||||
}
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBinary_Value(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_VALUE;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
|
||||
len =
|
||||
Binary_Value_Encode_Property_APDU(&apdu[0], instance,
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len =
|
||||
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_BINARY_VALUE);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Binary_Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testBinary_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BINARY_VALUE */
|
||||
#endif /* TEST */
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef BV_H
|
||||
#define BV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifndef MAX_BINARY_VALUES
|
||||
#define MAX_BINARY_VALUES 10
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Binary_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Binary_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Binary_Value_Count(void);
|
||||
uint32_t Binary_Value_Index_To_Instance(unsigned index);
|
||||
char *Binary_Value_Name(uint32_t object_instance);
|
||||
|
||||
void Binary_Value_Init(void);
|
||||
|
||||
int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testBinary_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef BV_H
|
||||
#define BV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifndef MAX_BINARY_VALUES
|
||||
#define MAX_BINARY_VALUES 10
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Binary_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Binary_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Binary_Value_Count(void);
|
||||
uint32_t Binary_Value_Index_To_Instance(unsigned index);
|
||||
char *Binary_Value_Name(uint32_t object_instance);
|
||||
|
||||
void Binary_Value_Init(void);
|
||||
|
||||
int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testBinary_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,124 +1,124 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet Virtual Link Control for Wiznet on Arduino-Uno
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bvlc-arduino.h"
|
||||
#include "bip.h"
|
||||
#include "bacint.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
|
||||
/** result from a client request */
|
||||
BACNET_BVLC_RESULT BVLC_Result_Code = BVLC_RESULT_SUCCESSFUL_COMPLETION;
|
||||
/** The current BVLC Function Code being handled. */
|
||||
BACNET_BVLC_FUNCTION BVLC_Function_Code = BVLC_RESULT; /* A safe default */
|
||||
|
||||
static int bvlc_encode_bvlc_result(uint8_t * pdu,
|
||||
BACNET_BVLC_RESULT result_code)
|
||||
{
|
||||
if (pdu) {
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
pdu[1] = BVLC_RESULT;
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 6);
|
||||
encode_unsigned16(&pdu[4], (uint16_t) result_code);
|
||||
}
|
||||
|
||||
return 6;
|
||||
}
|
||||
|
||||
static int bvlc_send_mpdu(uint8_t * dest_addr, /* the destination address */
|
||||
|
||||
uint16_t * dest_port, /* the destination port */
|
||||
|
||||
uint8_t * mtu, /* the data */
|
||||
|
||||
uint16_t mtu_len)
|
||||
{ /* amount of data to send */
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (bip_valid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sendto_func(bip_socket(), mtu, mtu_len, dest_addr, *dest_port);
|
||||
}
|
||||
|
||||
static void bvlc_send_result(uint8_t * dest_addr,
|
||||
uint16_t * dest_port, /* the destination address */
|
||||
|
||||
BACNET_BVLC_RESULT result_code)
|
||||
{
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
uint16_t mtu_len = 0;
|
||||
|
||||
mtu_len = (uint16_t) bvlc_encode_bvlc_result(&mtu[0], result_code);
|
||||
bvlc_send_mpdu(dest_addr, dest_port, mtu, mtu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t bvlc_for_non_bbmd(uint8_t * addr,
|
||||
uint16_t * port,
|
||||
uint8_t * npdu,
|
||||
uint16_t received_bytes)
|
||||
{
|
||||
|
||||
uint16_t result_code = 0; /* aka, BVLC_RESULT_SUCCESSFUL_COMPLETION */
|
||||
BVLC_Function_Code = npdu[1]; /* The BVLC function */
|
||||
switch (BVLC_Function_Code) {
|
||||
case BVLC_RESULT:
|
||||
if (received_bytes >= 6) {
|
||||
/* This is the result of our foreign device registration */
|
||||
(void) decode_unsigned16(&npdu[4], &result_code);
|
||||
BVLC_Result_Code = (BACNET_BVLC_RESULT) result_code;
|
||||
fprintf(stderr, "BVLC: Result Code=%d\n", BVLC_Result_Code);
|
||||
/* But don't send any response */
|
||||
result_code = 0;
|
||||
}
|
||||
break;
|
||||
case BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE:
|
||||
result_code = BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK;
|
||||
break;
|
||||
case BVLC_READ_BROADCAST_DIST_TABLE:
|
||||
result_code = BVLC_RESULT_READ_BROADCAST_DISTRIBUTION_TABLE_NAK;
|
||||
break;
|
||||
/* case BVLC_READ_BROADCAST_DIST_TABLE_ACK: */
|
||||
case BVLC_REGISTER_FOREIGN_DEVICE:
|
||||
result_code = BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK;
|
||||
break;
|
||||
case BVLC_READ_FOREIGN_DEVICE_TABLE:
|
||||
result_code = BVLC_RESULT_READ_FOREIGN_DEVICE_TABLE_NAK;
|
||||
break;
|
||||
/* case BVLC_READ_FOREIGN_DEVICE_TABLE_ACK: */
|
||||
case BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY:
|
||||
result_code = BVLC_RESULT_DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK;
|
||||
break;
|
||||
case BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK:
|
||||
result_code = BVLC_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK;
|
||||
break;
|
||||
/* case BVLC_FORWARDED_NPDU: */
|
||||
/* case BVLC_ORIGINAL_UNICAST_NPDU: */
|
||||
/* case BVLC_ORIGINAL_BROADCAST_NPDU: */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result_code > 0) {
|
||||
bvlc_send_result(addr, port, result_code);
|
||||
fprintf(stderr, "BVLC: NAK code=%d\n", result_code);
|
||||
}
|
||||
return result_code;
|
||||
}
|
||||
|
||||
BACNET_BVLC_FUNCTION bvlc_get_function_code(void)
|
||||
{
|
||||
return BVLC_Function_Code;
|
||||
}
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet Virtual Link Control for Wiznet on Arduino-Uno
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bvlc-arduino.h"
|
||||
#include "bip.h"
|
||||
#include "bacint.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
|
||||
/** result from a client request */
|
||||
BACNET_BVLC_RESULT BVLC_Result_Code = BVLC_RESULT_SUCCESSFUL_COMPLETION;
|
||||
/** The current BVLC Function Code being handled. */
|
||||
BACNET_BVLC_FUNCTION BVLC_Function_Code = BVLC_RESULT; /* A safe default */
|
||||
|
||||
static int bvlc_encode_bvlc_result(uint8_t * pdu,
|
||||
BACNET_BVLC_RESULT result_code)
|
||||
{
|
||||
if (pdu) {
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
pdu[1] = BVLC_RESULT;
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 6);
|
||||
encode_unsigned16(&pdu[4], (uint16_t) result_code);
|
||||
}
|
||||
|
||||
return 6;
|
||||
}
|
||||
|
||||
static int bvlc_send_mpdu(uint8_t * dest_addr, /* the destination address */
|
||||
|
||||
uint16_t * dest_port, /* the destination port */
|
||||
|
||||
uint8_t * mtu, /* the data */
|
||||
|
||||
uint16_t mtu_len)
|
||||
{ /* amount of data to send */
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (bip_valid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sendto_func(bip_socket(), mtu, mtu_len, dest_addr, *dest_port);
|
||||
}
|
||||
|
||||
static void bvlc_send_result(uint8_t * dest_addr,
|
||||
uint16_t * dest_port, /* the destination address */
|
||||
|
||||
BACNET_BVLC_RESULT result_code)
|
||||
{
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
uint16_t mtu_len = 0;
|
||||
|
||||
mtu_len = (uint16_t) bvlc_encode_bvlc_result(&mtu[0], result_code);
|
||||
bvlc_send_mpdu(dest_addr, dest_port, mtu, mtu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t bvlc_for_non_bbmd(uint8_t * addr,
|
||||
uint16_t * port,
|
||||
uint8_t * npdu,
|
||||
uint16_t received_bytes)
|
||||
{
|
||||
|
||||
uint16_t result_code = 0; /* aka, BVLC_RESULT_SUCCESSFUL_COMPLETION */
|
||||
BVLC_Function_Code = npdu[1]; /* The BVLC function */
|
||||
switch (BVLC_Function_Code) {
|
||||
case BVLC_RESULT:
|
||||
if (received_bytes >= 6) {
|
||||
/* This is the result of our foreign device registration */
|
||||
(void) decode_unsigned16(&npdu[4], &result_code);
|
||||
BVLC_Result_Code = (BACNET_BVLC_RESULT) result_code;
|
||||
fprintf(stderr, "BVLC: Result Code=%d\n", BVLC_Result_Code);
|
||||
/* But don't send any response */
|
||||
result_code = 0;
|
||||
}
|
||||
break;
|
||||
case BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE:
|
||||
result_code = BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK;
|
||||
break;
|
||||
case BVLC_READ_BROADCAST_DIST_TABLE:
|
||||
result_code = BVLC_RESULT_READ_BROADCAST_DISTRIBUTION_TABLE_NAK;
|
||||
break;
|
||||
/* case BVLC_READ_BROADCAST_DIST_TABLE_ACK: */
|
||||
case BVLC_REGISTER_FOREIGN_DEVICE:
|
||||
result_code = BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK;
|
||||
break;
|
||||
case BVLC_READ_FOREIGN_DEVICE_TABLE:
|
||||
result_code = BVLC_RESULT_READ_FOREIGN_DEVICE_TABLE_NAK;
|
||||
break;
|
||||
/* case BVLC_READ_FOREIGN_DEVICE_TABLE_ACK: */
|
||||
case BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY:
|
||||
result_code = BVLC_RESULT_DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK;
|
||||
break;
|
||||
case BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK:
|
||||
result_code = BVLC_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK;
|
||||
break;
|
||||
/* case BVLC_FORWARDED_NPDU: */
|
||||
/* case BVLC_ORIGINAL_UNICAST_NPDU: */
|
||||
/* case BVLC_ORIGINAL_BROADCAST_NPDU: */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result_code > 0) {
|
||||
bvlc_send_result(addr, port, result_code);
|
||||
fprintf(stderr, "BVLC: NAK code=%d\n", result_code);
|
||||
}
|
||||
return result_code;
|
||||
}
|
||||
|
||||
BACNET_BVLC_FUNCTION bvlc_get_function_code(void)
|
||||
{
|
||||
return BVLC_Function_Code;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet Virtual Link Control for Wiznet on Arduino-Uno
|
||||
*/
|
||||
#ifndef BVLCARDUINO_H_
|
||||
#define BVLCARDUINO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint16_t bvlc_for_non_bbmd(uint8_t * addr,
|
||||
uint16_t * port,
|
||||
uint8_t * npdu,
|
||||
uint16_t received_bytes);
|
||||
|
||||
BACNET_BVLC_FUNCTION bvlc_get_function_code(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* BVLCARDUINO_H_ */
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet Virtual Link Control for Wiznet on Arduino-Uno
|
||||
*/
|
||||
#ifndef BVLCARDUINO_H_
|
||||
#define BVLCARDUINO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint16_t bvlc_for_non_bbmd(uint8_t * addr,
|
||||
uint16_t * port,
|
||||
uint8_t * npdu,
|
||||
uint16_t received_bytes);
|
||||
|
||||
BACNET_BVLC_FUNCTION bvlc_get_function_code(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* BVLCARDUINO_H_ */
|
||||
|
||||
@@ -1,136 +1,136 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*********************************************************************/
|
||||
#ifndef DATALINK_H
|
||||
#define DATALINK_H
|
||||
|
||||
#include "config.h"
|
||||
#include "bacdef.h"
|
||||
|
||||
#if defined(BACDL_ETHERNET)
|
||||
#include "ethernet.h"
|
||||
|
||||
#define datalink_init ethernet_init
|
||||
#define datalink_send_pdu ethernet_send_pdu
|
||||
#define datalink_receive ethernet_receive
|
||||
#define datalink_cleanup ethernet_cleanup
|
||||
#define datalink_get_broadcast_address ethernet_get_broadcast_address
|
||||
#define datalink_get_my_address ethernet_get_my_address
|
||||
|
||||
#elif defined(BACDL_ARCNET)
|
||||
#include "arcnet.h"
|
||||
|
||||
#define datalink_init arcnet_init
|
||||
#define datalink_send_pdu arcnet_send_pdu
|
||||
#define datalink_receive arcnet_receive
|
||||
#define datalink_cleanup arcnet_cleanup
|
||||
#define datalink_get_broadcast_address arcnet_get_broadcast_address
|
||||
#define datalink_get_my_address arcnet_get_my_address
|
||||
|
||||
#elif defined(BACDL_MSTP)
|
||||
#include "dlmstp.h"
|
||||
|
||||
#define datalink_init dlmstp_init
|
||||
#define datalink_send_pdu dlmstp_send_pdu
|
||||
#define datalink_receive dlmstp_receive
|
||||
#define datalink_cleanup dlmstp_cleanup
|
||||
#define datalink_get_broadcast_address dlmstp_get_broadcast_address
|
||||
#define datalink_get_my_address dlmstp_get_my_address
|
||||
|
||||
#elif defined(BACDL_BIP)
|
||||
#include "bip.h"
|
||||
#include "bvlc-arduino.h"
|
||||
|
||||
#define datalink_init bip_init
|
||||
//#if defined(BBMD_ENABLED) && BBMD_ENABLED
|
||||
//#define datalink_send_pdu bvlc_send_pdu
|
||||
//#define datalink_receive bvlc_receive
|
||||
//#else
|
||||
#define datalink_send_pdu bip_send_pdu
|
||||
#define datalink_receive bip_receive
|
||||
//#endif
|
||||
#define datalink_cleanup bip_cleanup
|
||||
#define datalink_get_broadcast_address bip_get_broadcast_address
|
||||
#ifdef BAC_ROUTING
|
||||
extern void routed_get_my_address(BACNET_ADDRESS * my_address);
|
||||
#define datalink_get_my_address routed_get_my_address
|
||||
#else
|
||||
#define datalink_get_my_address bip_get_my_address
|
||||
#endif
|
||||
|
||||
#else /* Ie, BACDL_ALL */
|
||||
#include "npdu.h"
|
||||
|
||||
#define MAX_HEADER (8)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest,
|
||||
BACNET_NPDU_DATA * npdu_data,
|
||||
uint8_t * pdu,
|
||||
unsigned pdu_len);
|
||||
extern uint16_t datalink_receive(BACNET_ADDRESS * src,
|
||||
uint8_t * pdu,
|
||||
uint16_t max_pdu,
|
||||
unsigned timeout);
|
||||
extern void datalink_cleanup(void);
|
||||
extern void datalink_get_broadcast_address(BACNET_ADDRESS * dest);
|
||||
extern void datalink_get_my_address(BACNET_ADDRESS * my_address);
|
||||
extern void datalink_set_interface(char *ifname);
|
||||
extern void datalink_set(char *datalink_string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/** @defgroup DataLink The BACnet Network (DataLink) Layer
|
||||
* <b>6 THE NETWORK LAYER </b><br>
|
||||
* The purpose of the BACnet network layer is to provide the means by which
|
||||
* messages can be relayed from one BACnet network to another, regardless of
|
||||
* the BACnet data link technology in use on that network. Whereas the data
|
||||
* link layer provides the capability to address messages to a single device
|
||||
* or broadcast them to all devices on the local network, the network layer
|
||||
* allows messages to be directed to a single remote device, broadcast on a
|
||||
* remote network, or broadcast globally to all devices on all networks.
|
||||
* A BACnet Device is uniquely located by a network number and a MAC address.
|
||||
*
|
||||
* Each client or server application must define exactly one of these
|
||||
* DataLink settings, which will control which parts of the code will be built:
|
||||
* - BACDL_ETHERNET -- for Clause 7 ISO 8802-3 ("Ethernet") LAN
|
||||
* - BACDL_ARCNET -- for Clause 8 ARCNET LAN
|
||||
* - BACDL_MSTP -- for Clause 9 MASTER-SLAVE/TOKEN PASSING (MS/TP) LAN
|
||||
* - BACDL_BIP -- for ANNEX J - BACnet/IP
|
||||
* - BACDL_ALL -- Unspecified for the build, so the transport can be
|
||||
* chosen at runtime from among these choices.
|
||||
* - Clause 10 POINT-TO-POINT (PTP) and Clause 11 EIA/CEA-709.1 ("LonTalk") LAN
|
||||
* are not currently supported by this project.
|
||||
*//** @defgroup DLTemplates DataLink Template Functions
|
||||
* @ingroup DataLink
|
||||
* Most of the functions in this group are function templates which are assigned
|
||||
* to a specific DataLink network layer implementation either at compile time or
|
||||
* at runtime.
|
||||
*/
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*********************************************************************/
|
||||
#ifndef DATALINK_H
|
||||
#define DATALINK_H
|
||||
|
||||
#include "config.h"
|
||||
#include "bacdef.h"
|
||||
|
||||
#if defined(BACDL_ETHERNET)
|
||||
#include "ethernet.h"
|
||||
|
||||
#define datalink_init ethernet_init
|
||||
#define datalink_send_pdu ethernet_send_pdu
|
||||
#define datalink_receive ethernet_receive
|
||||
#define datalink_cleanup ethernet_cleanup
|
||||
#define datalink_get_broadcast_address ethernet_get_broadcast_address
|
||||
#define datalink_get_my_address ethernet_get_my_address
|
||||
|
||||
#elif defined(BACDL_ARCNET)
|
||||
#include "arcnet.h"
|
||||
|
||||
#define datalink_init arcnet_init
|
||||
#define datalink_send_pdu arcnet_send_pdu
|
||||
#define datalink_receive arcnet_receive
|
||||
#define datalink_cleanup arcnet_cleanup
|
||||
#define datalink_get_broadcast_address arcnet_get_broadcast_address
|
||||
#define datalink_get_my_address arcnet_get_my_address
|
||||
|
||||
#elif defined(BACDL_MSTP)
|
||||
#include "dlmstp.h"
|
||||
|
||||
#define datalink_init dlmstp_init
|
||||
#define datalink_send_pdu dlmstp_send_pdu
|
||||
#define datalink_receive dlmstp_receive
|
||||
#define datalink_cleanup dlmstp_cleanup
|
||||
#define datalink_get_broadcast_address dlmstp_get_broadcast_address
|
||||
#define datalink_get_my_address dlmstp_get_my_address
|
||||
|
||||
#elif defined(BACDL_BIP)
|
||||
#include "bip.h"
|
||||
#include "bvlc-arduino.h"
|
||||
|
||||
#define datalink_init bip_init
|
||||
//#if defined(BBMD_ENABLED) && BBMD_ENABLED
|
||||
//#define datalink_send_pdu bvlc_send_pdu
|
||||
//#define datalink_receive bvlc_receive
|
||||
//#else
|
||||
#define datalink_send_pdu bip_send_pdu
|
||||
#define datalink_receive bip_receive
|
||||
//#endif
|
||||
#define datalink_cleanup bip_cleanup
|
||||
#define datalink_get_broadcast_address bip_get_broadcast_address
|
||||
#ifdef BAC_ROUTING
|
||||
extern void routed_get_my_address(BACNET_ADDRESS * my_address);
|
||||
#define datalink_get_my_address routed_get_my_address
|
||||
#else
|
||||
#define datalink_get_my_address bip_get_my_address
|
||||
#endif
|
||||
|
||||
#else /* Ie, BACDL_ALL */
|
||||
#include "npdu.h"
|
||||
|
||||
#define MAX_HEADER (8)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest,
|
||||
BACNET_NPDU_DATA * npdu_data,
|
||||
uint8_t * pdu,
|
||||
unsigned pdu_len);
|
||||
extern uint16_t datalink_receive(BACNET_ADDRESS * src,
|
||||
uint8_t * pdu,
|
||||
uint16_t max_pdu,
|
||||
unsigned timeout);
|
||||
extern void datalink_cleanup(void);
|
||||
extern void datalink_get_broadcast_address(BACNET_ADDRESS * dest);
|
||||
extern void datalink_get_my_address(BACNET_ADDRESS * my_address);
|
||||
extern void datalink_set_interface(char *ifname);
|
||||
extern void datalink_set(char *datalink_string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/** @defgroup DataLink The BACnet Network (DataLink) Layer
|
||||
* <b>6 THE NETWORK LAYER </b><br>
|
||||
* The purpose of the BACnet network layer is to provide the means by which
|
||||
* messages can be relayed from one BACnet network to another, regardless of
|
||||
* the BACnet data link technology in use on that network. Whereas the data
|
||||
* link layer provides the capability to address messages to a single device
|
||||
* or broadcast them to all devices on the local network, the network layer
|
||||
* allows messages to be directed to a single remote device, broadcast on a
|
||||
* remote network, or broadcast globally to all devices on all networks.
|
||||
* A BACnet Device is uniquely located by a network number and a MAC address.
|
||||
*
|
||||
* Each client or server application must define exactly one of these
|
||||
* DataLink settings, which will control which parts of the code will be built:
|
||||
* - BACDL_ETHERNET -- for Clause 7 ISO 8802-3 ("Ethernet") LAN
|
||||
* - BACDL_ARCNET -- for Clause 8 ARCNET LAN
|
||||
* - BACDL_MSTP -- for Clause 9 MASTER-SLAVE/TOKEN PASSING (MS/TP) LAN
|
||||
* - BACDL_BIP -- for ANNEX J - BACnet/IP
|
||||
* - BACDL_ALL -- Unspecified for the build, so the transport can be
|
||||
* chosen at runtime from among these choices.
|
||||
* - Clause 10 POINT-TO-POINT (PTP) and Clause 11 EIA/CEA-709.1 ("LonTalk") LAN
|
||||
* are not currently supported by this project.
|
||||
*//** @defgroup DLTemplates DataLink Template Functions
|
||||
* @ingroup DataLink
|
||||
* Most of the functions in this group are function templates which are assigned
|
||||
* to a specific DataLink network layer implementation either at compile time or
|
||||
* at runtime.
|
||||
*/
|
||||
#endif
|
||||
|
||||
@@ -1,140 +1,140 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DEVICE_H
|
||||
#define DEVICE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacenum.h"
|
||||
#include "wp.h"
|
||||
#include "readrange.h"
|
||||
|
||||
typedef unsigned (*object_count_function) (void);
|
||||
typedef uint32_t(*object_index_to_instance_function)
|
||||
(unsigned index);
|
||||
typedef char *(*object_name_function)
|
||||
(uint32_t object_instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Device_Object_Function_Set(BACNET_OBJECT_TYPE object_type,
|
||||
object_count_function count_function,
|
||||
object_index_to_instance_function index_function,
|
||||
object_name_function name_function);
|
||||
|
||||
void Device_Init(void);
|
||||
|
||||
void Device_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
|
||||
uint32_t Device_Object_Instance_Number(void);
|
||||
bool Device_Set_Object_Instance_Number(uint32_t object_id);
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id);
|
||||
unsigned Device_Object_List_Count(void);
|
||||
bool Device_Object_List_Identifier(unsigned array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance);
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(void);
|
||||
void Device_Set_System_Status(BACNET_DEVICE_STATUS status);
|
||||
|
||||
const char *Device_Vendor_Name(void);
|
||||
|
||||
uint16_t Device_Vendor_Identifier(void);
|
||||
|
||||
const char *Device_Model_Name(void);
|
||||
bool Device_Set_Model_Name(const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Firmware_Revision(void);
|
||||
|
||||
const char *Device_Application_Software_Version(void);
|
||||
bool Device_Set_Application_Software_Version(const char *name,
|
||||
size_t length);
|
||||
|
||||
bool Device_Set_Object_Name(const char *name,
|
||||
size_t length);
|
||||
const char *Device_Object_Name(void);
|
||||
|
||||
const char *Device_Description(void);
|
||||
bool Device_Set_Description(const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Location(void);
|
||||
bool Device_Set_Location(const char *name,
|
||||
size_t length);
|
||||
|
||||
/* some stack-centric constant values - no set methods */
|
||||
uint8_t Device_Protocol_Version(void);
|
||||
uint8_t Device_Protocol_Revision(void);
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void);
|
||||
|
||||
uint8_t Device_Database_Revision(void);
|
||||
void Device_Set_Database_Revision(uint8_t revision);
|
||||
|
||||
bool Device_Valid_Object_Name(const char *object_name,
|
||||
int *object_type,
|
||||
uint32_t * object_instance);
|
||||
char *Device_Valid_Object_Id(int object_type,
|
||||
uint32_t object_instance);
|
||||
|
||||
int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool DeviceGetRRInfo(uint32_t Object, /* Which particular object - obviously not important for device object */
|
||||
|
||||
BACNET_PROPERTY_ID Property, /* Which property */
|
||||
|
||||
RR_PROP_INFO * pInfo, /* Where to put the information */
|
||||
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DEVICE_H
|
||||
#define DEVICE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacenum.h"
|
||||
#include "wp.h"
|
||||
#include "readrange.h"
|
||||
|
||||
typedef unsigned (*object_count_function) (void);
|
||||
typedef uint32_t(*object_index_to_instance_function)
|
||||
(unsigned index);
|
||||
typedef char *(*object_name_function)
|
||||
(uint32_t object_instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Device_Object_Function_Set(BACNET_OBJECT_TYPE object_type,
|
||||
object_count_function count_function,
|
||||
object_index_to_instance_function index_function,
|
||||
object_name_function name_function);
|
||||
|
||||
void Device_Init(void);
|
||||
|
||||
void Device_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
|
||||
uint32_t Device_Object_Instance_Number(void);
|
||||
bool Device_Set_Object_Instance_Number(uint32_t object_id);
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id);
|
||||
unsigned Device_Object_List_Count(void);
|
||||
bool Device_Object_List_Identifier(unsigned array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance);
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(void);
|
||||
void Device_Set_System_Status(BACNET_DEVICE_STATUS status);
|
||||
|
||||
const char *Device_Vendor_Name(void);
|
||||
|
||||
uint16_t Device_Vendor_Identifier(void);
|
||||
|
||||
const char *Device_Model_Name(void);
|
||||
bool Device_Set_Model_Name(const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Firmware_Revision(void);
|
||||
|
||||
const char *Device_Application_Software_Version(void);
|
||||
bool Device_Set_Application_Software_Version(const char *name,
|
||||
size_t length);
|
||||
|
||||
bool Device_Set_Object_Name(const char *name,
|
||||
size_t length);
|
||||
const char *Device_Object_Name(void);
|
||||
|
||||
const char *Device_Description(void);
|
||||
bool Device_Set_Description(const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Location(void);
|
||||
bool Device_Set_Location(const char *name,
|
||||
size_t length);
|
||||
|
||||
/* some stack-centric constant values - no set methods */
|
||||
uint8_t Device_Protocol_Version(void);
|
||||
uint8_t Device_Protocol_Revision(void);
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void);
|
||||
|
||||
uint8_t Device_Database_Revision(void);
|
||||
void Device_Set_Database_Revision(uint8_t revision);
|
||||
|
||||
bool Device_Valid_Object_Name(const char *object_name,
|
||||
int *object_type,
|
||||
uint32_t * object_instance);
|
||||
char *Device_Valid_Object_Id(int object_type,
|
||||
uint32_t object_instance);
|
||||
|
||||
int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool DeviceGetRRInfo(uint32_t Object, /* Which particular object - obviously not important for device object */
|
||||
|
||||
BACNET_PROPERTY_ID Property, /* Which property */
|
||||
|
||||
RR_PROP_INFO * pInfo, /* Where to put the information */
|
||||
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,72 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
||||
* SPI Master library for arduino.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _SPI_H_INCLUDED
|
||||
#define _SPI_H_INCLUDED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <Arduino.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define SPI_CLOCK_DIV4 0x00
|
||||
#define SPI_CLOCK_DIV16 0x01
|
||||
#define SPI_CLOCK_DIV64 0x02
|
||||
#define SPI_CLOCK_DIV128 0x03
|
||||
#define SPI_CLOCK_DIV2 0x04
|
||||
#define SPI_CLOCK_DIV8 0x05
|
||||
#define SPI_CLOCK_DIV32 0x06
|
||||
//#define SPI_CLOCK_DIV64 0x07
|
||||
|
||||
#define SPI_MODE0 0x00
|
||||
#define SPI_MODE1 0x04
|
||||
#define SPI_MODE2 0x08
|
||||
#define SPI_MODE3 0x0C
|
||||
|
||||
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
|
||||
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
|
||||
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
|
||||
|
||||
class SPIClass {
|
||||
public:
|
||||
inline static byte transfer(byte _data);
|
||||
|
||||
// SPI Configuration methods
|
||||
|
||||
inline static void attachInterrupt();
|
||||
inline static void detachInterrupt(); // Default
|
||||
|
||||
static void begin(); // Default
|
||||
static void end();
|
||||
|
||||
static void setBitOrder(uint8_t);
|
||||
static void setDataMode(uint8_t);
|
||||
static void setClockDivider(uint8_t);
|
||||
};
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
byte SPIClass::transfer(byte _data)
|
||||
{
|
||||
SPDR = _data;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
return SPDR;
|
||||
}
|
||||
|
||||
void SPIClass::attachInterrupt()
|
||||
{
|
||||
SPCR |= _BV(SPIE);
|
||||
}
|
||||
|
||||
void SPIClass::detachInterrupt()
|
||||
{
|
||||
SPCR &= ~_BV(SPIE);
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
||||
* SPI Master library for arduino.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _SPI_H_INCLUDED
|
||||
#define _SPI_H_INCLUDED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <Arduino.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define SPI_CLOCK_DIV4 0x00
|
||||
#define SPI_CLOCK_DIV16 0x01
|
||||
#define SPI_CLOCK_DIV64 0x02
|
||||
#define SPI_CLOCK_DIV128 0x03
|
||||
#define SPI_CLOCK_DIV2 0x04
|
||||
#define SPI_CLOCK_DIV8 0x05
|
||||
#define SPI_CLOCK_DIV32 0x06
|
||||
//#define SPI_CLOCK_DIV64 0x07
|
||||
|
||||
#define SPI_MODE0 0x00
|
||||
#define SPI_MODE1 0x04
|
||||
#define SPI_MODE2 0x08
|
||||
#define SPI_MODE3 0x0C
|
||||
|
||||
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
|
||||
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
|
||||
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
|
||||
|
||||
class SPIClass {
|
||||
public:
|
||||
inline static byte transfer(byte _data);
|
||||
|
||||
// SPI Configuration methods
|
||||
|
||||
inline static void attachInterrupt();
|
||||
inline static void detachInterrupt(); // Default
|
||||
|
||||
static void begin(); // Default
|
||||
static void end();
|
||||
|
||||
static void setBitOrder(uint8_t);
|
||||
static void setDataMode(uint8_t);
|
||||
static void setClockDivider(uint8_t);
|
||||
};
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
byte SPIClass::transfer(byte _data)
|
||||
{
|
||||
SPDR = _data;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
return SPDR;
|
||||
}
|
||||
|
||||
void SPIClass::attachInterrupt()
|
||||
{
|
||||
SPCR |= _BV(SPIE);
|
||||
}
|
||||
|
||||
void SPIClass::detachInterrupt()
|
||||
{
|
||||
SPCR &= ~_BV(SPIE);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) )
|
||||
#define ntohs(x) htons(x)
|
||||
|
||||
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
|
||||
((x)<< 8 & 0x00FF0000UL) | \
|
||||
((x)>> 8 & 0x0000FF00UL) | \
|
||||
((x)>>24 & 0x000000FFUL) )
|
||||
#define ntohl(x) htonl(x)
|
||||
|
||||
#endif
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) )
|
||||
#define ntohs(x) htons(x)
|
||||
|
||||
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
|
||||
((x)<< 8 & 0x00FF0000UL) | \
|
||||
((x)>> 8 & 0x0000FF00UL) | \
|
||||
((x)>>24 & 0x000000FFUL) )
|
||||
#define ntohl(x) htonl(x)
|
||||
|
||||
#endif
|
||||
|
||||
+515
-515
File diff suppressed because it is too large
Load Diff
+139
-139
@@ -1,139 +1,139 @@
|
||||
/*
|
||||
* w5100Wrapper.h
|
||||
*
|
||||
* Created on: 26 de Mai de 2013
|
||||
* Author: mgf
|
||||
*/
|
||||
|
||||
#ifndef W5100WRAPPER_H_
|
||||
#define W5100WRAPPER_H_
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
typedef uint8_t SOCKET;
|
||||
typedef void CSnMR;
|
||||
typedef void CSnIR;
|
||||
typedef void CSnSR;
|
||||
typedef void CIPPROTO;
|
||||
typedef void CW5100Class;
|
||||
|
||||
#define MAX_SOCK_NUM 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
CSnMR *CSnMR_new();
|
||||
void CSnMR_delete(const CSnMR * obj);
|
||||
uint8_t SnMR_CLOSE();
|
||||
uint8_t SnMR_UDP();
|
||||
uint8_t SnMR_TCP();
|
||||
uint8_t SnMR_IPRAW();
|
||||
uint8_t SnMR_MACRAW();
|
||||
uint8_t SnMR_PPPOE();
|
||||
uint8_t SnMR_ND();
|
||||
uint8_t SnMR_MULTI();
|
||||
|
||||
CSnIR *CSnIR_new();
|
||||
void CSnIR_delete(const CSnIR * obj);
|
||||
uint8_t SnIR_SEND_OK();
|
||||
uint8_t SnIR_TIMEOUT();
|
||||
uint8_t SnIR_RECV();
|
||||
uint8_t SnIR_DISCON();
|
||||
uint8_t SnIR_CON();
|
||||
|
||||
|
||||
CSnSR *CSnSR_new();
|
||||
void CSnSR_delete(const CSnSR * obj);
|
||||
uint8_t SnSR_CLOSED();
|
||||
uint8_t SnSR_INIT();
|
||||
uint8_t SnSR_LISTEN();
|
||||
uint8_t SnSR_SYNSENT();
|
||||
uint8_t SnSR_SYNRECV();
|
||||
uint8_t SnSR_ESTABLISHED();
|
||||
uint8_t SnSR_FIN_WAIT();
|
||||
uint8_t SnSR_CLOSING();
|
||||
uint8_t SnSR_TIME_WAIT();
|
||||
uint8_t SnSR_CLOSE_WAIT();
|
||||
uint8_t SnSR_LAST_ACK();
|
||||
uint8_t SnSR_UDP();
|
||||
uint8_t SnSR_IPRAW();
|
||||
uint8_t SnSR_MACRAW();
|
||||
uint8_t SnSR_PPPOE();
|
||||
|
||||
CIPPROTO *CIPPROTO_new();
|
||||
void CIPPROTO_delete(const CIPPROTO * obj);
|
||||
uint8_t IPPROTO_IP();
|
||||
uint8_t IPPROTO_ICMP();
|
||||
uint8_t IPPROTO_IGMP();
|
||||
uint8_t IPPROTO_GGP();
|
||||
uint8_t IPPROTO_TCP();
|
||||
uint8_t IPPROTO_PUP();
|
||||
uint8_t IPPROTO_UDP();
|
||||
uint8_t IPPROTO_IDP();
|
||||
uint8_t IPPROTO_ND();
|
||||
uint8_t IPPROTO_RAW();
|
||||
|
||||
CW5100Class *CW5100Class_new();
|
||||
void init_func(const CW5100Class * obj);
|
||||
void CW5100Class_delete(const CW5100Class * obj);
|
||||
|
||||
void read_data_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
volatile uint8_t * src,
|
||||
volatile uint8_t * dst,
|
||||
uint16_t len);
|
||||
|
||||
void send_data_processing_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
const uint8_t * data,
|
||||
uint16_t len);
|
||||
void send_data_processing_offset_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
uint16_t data_offset,
|
||||
const uint8_t * data,
|
||||
uint16_t len);
|
||||
//FIXME: Removed defaul value of 0(zero) from the peek argument
|
||||
void recv_data_processing_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
uint8_t * data,
|
||||
uint16_t len,
|
||||
uint8_t peek);
|
||||
void setGatewayIp_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
void getGatewayIp_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
//
|
||||
void setSubnetMask_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
void getSubnetMask_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
//
|
||||
void setMACAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
void getMACAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
//
|
||||
void setIPAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
void getIPAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
//
|
||||
void setRetransmissionTime_func(const CW5100Class * obj,
|
||||
uint16_t timeout);
|
||||
void setRetransmissionCount_func(const CW5100Class * obj,
|
||||
uint8_t _retry);
|
||||
//
|
||||
|
||||
uint16_t getTXFreeSize_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
uint16_t getRXReceivedSize_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
|
||||
uint8_t readSnSR_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* W5100WRAPPER_H_ */
|
||||
/*
|
||||
* w5100Wrapper.h
|
||||
*
|
||||
* Created on: 26 de Mai de 2013
|
||||
* Author: mgf
|
||||
*/
|
||||
|
||||
#ifndef W5100WRAPPER_H_
|
||||
#define W5100WRAPPER_H_
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
typedef uint8_t SOCKET;
|
||||
typedef void CSnMR;
|
||||
typedef void CSnIR;
|
||||
typedef void CSnSR;
|
||||
typedef void CIPPROTO;
|
||||
typedef void CW5100Class;
|
||||
|
||||
#define MAX_SOCK_NUM 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
CSnMR *CSnMR_new();
|
||||
void CSnMR_delete(const CSnMR * obj);
|
||||
uint8_t SnMR_CLOSE();
|
||||
uint8_t SnMR_UDP();
|
||||
uint8_t SnMR_TCP();
|
||||
uint8_t SnMR_IPRAW();
|
||||
uint8_t SnMR_MACRAW();
|
||||
uint8_t SnMR_PPPOE();
|
||||
uint8_t SnMR_ND();
|
||||
uint8_t SnMR_MULTI();
|
||||
|
||||
CSnIR *CSnIR_new();
|
||||
void CSnIR_delete(const CSnIR * obj);
|
||||
uint8_t SnIR_SEND_OK();
|
||||
uint8_t SnIR_TIMEOUT();
|
||||
uint8_t SnIR_RECV();
|
||||
uint8_t SnIR_DISCON();
|
||||
uint8_t SnIR_CON();
|
||||
|
||||
|
||||
CSnSR *CSnSR_new();
|
||||
void CSnSR_delete(const CSnSR * obj);
|
||||
uint8_t SnSR_CLOSED();
|
||||
uint8_t SnSR_INIT();
|
||||
uint8_t SnSR_LISTEN();
|
||||
uint8_t SnSR_SYNSENT();
|
||||
uint8_t SnSR_SYNRECV();
|
||||
uint8_t SnSR_ESTABLISHED();
|
||||
uint8_t SnSR_FIN_WAIT();
|
||||
uint8_t SnSR_CLOSING();
|
||||
uint8_t SnSR_TIME_WAIT();
|
||||
uint8_t SnSR_CLOSE_WAIT();
|
||||
uint8_t SnSR_LAST_ACK();
|
||||
uint8_t SnSR_UDP();
|
||||
uint8_t SnSR_IPRAW();
|
||||
uint8_t SnSR_MACRAW();
|
||||
uint8_t SnSR_PPPOE();
|
||||
|
||||
CIPPROTO *CIPPROTO_new();
|
||||
void CIPPROTO_delete(const CIPPROTO * obj);
|
||||
uint8_t IPPROTO_IP();
|
||||
uint8_t IPPROTO_ICMP();
|
||||
uint8_t IPPROTO_IGMP();
|
||||
uint8_t IPPROTO_GGP();
|
||||
uint8_t IPPROTO_TCP();
|
||||
uint8_t IPPROTO_PUP();
|
||||
uint8_t IPPROTO_UDP();
|
||||
uint8_t IPPROTO_IDP();
|
||||
uint8_t IPPROTO_ND();
|
||||
uint8_t IPPROTO_RAW();
|
||||
|
||||
CW5100Class *CW5100Class_new();
|
||||
void init_func(const CW5100Class * obj);
|
||||
void CW5100Class_delete(const CW5100Class * obj);
|
||||
|
||||
void read_data_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
volatile uint8_t * src,
|
||||
volatile uint8_t * dst,
|
||||
uint16_t len);
|
||||
|
||||
void send_data_processing_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
const uint8_t * data,
|
||||
uint16_t len);
|
||||
void send_data_processing_offset_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
uint16_t data_offset,
|
||||
const uint8_t * data,
|
||||
uint16_t len);
|
||||
//FIXME: Removed defaul value of 0(zero) from the peek argument
|
||||
void recv_data_processing_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
uint8_t * data,
|
||||
uint16_t len,
|
||||
uint8_t peek);
|
||||
void setGatewayIp_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
void getGatewayIp_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
//
|
||||
void setSubnetMask_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
void getSubnetMask_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
//
|
||||
void setMACAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
void getMACAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
//
|
||||
void setIPAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
void getIPAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
//
|
||||
void setRetransmissionTime_func(const CW5100Class * obj,
|
||||
uint16_t timeout);
|
||||
void setRetransmissionCount_func(const CW5100Class * obj,
|
||||
uint8_t _retry);
|
||||
//
|
||||
|
||||
uint16_t getTXFreeSize_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
uint16_t getRXReceivedSize_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
|
||||
uint8_t readSnSR_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* W5100WRAPPER_H_ */
|
||||
|
||||
+235
-235
@@ -1,235 +1,235 @@
|
||||
#ifndef Arduino_h
|
||||
#define Arduino_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "binary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HIGH 0x1
|
||||
#define LOW 0x0
|
||||
|
||||
#define INPUT 0x0
|
||||
#define OUTPUT 0x1
|
||||
#define INPUT_PULLUP 0x2
|
||||
|
||||
#define true 0x1
|
||||
#define false 0x0
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#define SERIAL 0x0
|
||||
#define DISPLAY 0x1
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
#define CHANGE 1
|
||||
#define FALLING 2
|
||||
#define RISING 3
|
||||
|
||||
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
#define DEFAULT 0
|
||||
#define EXTERNAL 1
|
||||
#define INTERNAL 2
|
||||
#else
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||
#define INTERNAL1V1 2
|
||||
#define INTERNAL2V56 3
|
||||
#else
|
||||
#define INTERNAL 3
|
||||
#endif
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
#endif
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
void init(void);
|
||||
|
||||
void pinMode(uint8_t,
|
||||
uint8_t);
|
||||
void digitalWrite(uint8_t,
|
||||
uint8_t);
|
||||
int digitalRead(uint8_t);
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t,
|
||||
int);
|
||||
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
void delay(unsigned long);
|
||||
void delayMicroseconds(unsigned int us);
|
||||
unsigned long pulseIn(uint8_t pin,
|
||||
uint8_t state,
|
||||
unsigned long timeout);
|
||||
|
||||
void shiftOut(uint8_t dataPin,
|
||||
uint8_t clockPin,
|
||||
uint8_t bitOrder,
|
||||
uint8_t val);
|
||||
uint8_t shiftIn(uint8_t dataPin,
|
||||
uint8_t clockPin,
|
||||
uint8_t bitOrder);
|
||||
|
||||
void attachInterrupt(uint8_t,
|
||||
void (*)(void),
|
||||
int mode);
|
||||
void detachInterrupt(uint8_t);
|
||||
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
|
||||
#define analogInPinToBit(P) (P)
|
||||
|
||||
// On the ATmega1280, the addresses of some of the port registers are
|
||||
// greater than 255, so we can't store them in uint8_t's.
|
||||
extern const uint16_t PROGMEM port_to_mode_PGM[];
|
||||
extern const uint16_t PROGMEM port_to_input_PGM[];
|
||||
extern const uint16_t PROGMEM port_to_output_PGM[];
|
||||
|
||||
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
|
||||
// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
//
|
||||
// These perform slightly better as macros compared to inline functions
|
||||
//
|
||||
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
|
||||
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
|
||||
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
|
||||
#define analogInPinToBit(P) (P)
|
||||
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
|
||||
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
|
||||
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
|
||||
|
||||
#define NOT_A_PIN 0
|
||||
#define NOT_A_PORT 0
|
||||
|
||||
#ifdef ARDUINO_MAIN
|
||||
#define PA 1
|
||||
#define PB 2
|
||||
#define PC 3
|
||||
#define PD 4
|
||||
#define PE 5
|
||||
#define PF 6
|
||||
#define PG 7
|
||||
#define PH 8
|
||||
#define PJ 10
|
||||
#define PK 11
|
||||
#define PL 12
|
||||
#endif
|
||||
|
||||
#define NOT_ON_TIMER 0
|
||||
#define TIMER0A 1
|
||||
#define TIMER0B 2
|
||||
#define TIMER1A 3
|
||||
#define TIMER1B 4
|
||||
#define TIMER2 5
|
||||
#define TIMER2A 6
|
||||
#define TIMER2B 7
|
||||
|
||||
#define TIMER3A 8
|
||||
#define TIMER3B 9
|
||||
#define TIMER3C 10
|
||||
#define TIMER4A 11
|
||||
#define TIMER4B 12
|
||||
#define TIMER4C 13
|
||||
#define TIMER4D 14
|
||||
#define TIMER5A 15
|
||||
#define TIMER5B 16
|
||||
#define TIMER5C 17
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
#include "WCharacter.h"
|
||||
#include "WString.h"
|
||||
#include "HardwareSerial.h"
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(byte h,
|
||||
byte l);
|
||||
|
||||
#define word(...) makeWord(__VA_ARGS__)
|
||||
|
||||
unsigned long pulseIn(uint8_t pin,
|
||||
uint8_t state,
|
||||
unsigned long timeout = 1000000L);
|
||||
|
||||
void tone(uint8_t _pin,
|
||||
unsigned int frequency,
|
||||
unsigned long duration = 0);
|
||||
void noTone(uint8_t _pin);
|
||||
|
||||
// WMath prototypes
|
||||
long random(long);
|
||||
long random(long,
|
||||
long);
|
||||
void randomSeed(unsigned int);
|
||||
long map(long,
|
||||
long,
|
||||
long,
|
||||
long,
|
||||
long);
|
||||
|
||||
#endif
|
||||
|
||||
#include "pins_arduino.h"
|
||||
|
||||
#endif
|
||||
#ifndef Arduino_h
|
||||
#define Arduino_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "binary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HIGH 0x1
|
||||
#define LOW 0x0
|
||||
|
||||
#define INPUT 0x0
|
||||
#define OUTPUT 0x1
|
||||
#define INPUT_PULLUP 0x2
|
||||
|
||||
#define true 0x1
|
||||
#define false 0x0
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#define SERIAL 0x0
|
||||
#define DISPLAY 0x1
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
#define CHANGE 1
|
||||
#define FALLING 2
|
||||
#define RISING 3
|
||||
|
||||
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
#define DEFAULT 0
|
||||
#define EXTERNAL 1
|
||||
#define INTERNAL 2
|
||||
#else
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||
#define INTERNAL1V1 2
|
||||
#define INTERNAL2V56 3
|
||||
#else
|
||||
#define INTERNAL 3
|
||||
#endif
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
#endif
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
void init(void);
|
||||
|
||||
void pinMode(uint8_t,
|
||||
uint8_t);
|
||||
void digitalWrite(uint8_t,
|
||||
uint8_t);
|
||||
int digitalRead(uint8_t);
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t,
|
||||
int);
|
||||
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
void delay(unsigned long);
|
||||
void delayMicroseconds(unsigned int us);
|
||||
unsigned long pulseIn(uint8_t pin,
|
||||
uint8_t state,
|
||||
unsigned long timeout);
|
||||
|
||||
void shiftOut(uint8_t dataPin,
|
||||
uint8_t clockPin,
|
||||
uint8_t bitOrder,
|
||||
uint8_t val);
|
||||
uint8_t shiftIn(uint8_t dataPin,
|
||||
uint8_t clockPin,
|
||||
uint8_t bitOrder);
|
||||
|
||||
void attachInterrupt(uint8_t,
|
||||
void (*)(void),
|
||||
int mode);
|
||||
void detachInterrupt(uint8_t);
|
||||
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
|
||||
#define analogInPinToBit(P) (P)
|
||||
|
||||
// On the ATmega1280, the addresses of some of the port registers are
|
||||
// greater than 255, so we can't store them in uint8_t's.
|
||||
extern const uint16_t PROGMEM port_to_mode_PGM[];
|
||||
extern const uint16_t PROGMEM port_to_input_PGM[];
|
||||
extern const uint16_t PROGMEM port_to_output_PGM[];
|
||||
|
||||
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
|
||||
// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
//
|
||||
// These perform slightly better as macros compared to inline functions
|
||||
//
|
||||
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
|
||||
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
|
||||
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
|
||||
#define analogInPinToBit(P) (P)
|
||||
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
|
||||
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
|
||||
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
|
||||
|
||||
#define NOT_A_PIN 0
|
||||
#define NOT_A_PORT 0
|
||||
|
||||
#ifdef ARDUINO_MAIN
|
||||
#define PA 1
|
||||
#define PB 2
|
||||
#define PC 3
|
||||
#define PD 4
|
||||
#define PE 5
|
||||
#define PF 6
|
||||
#define PG 7
|
||||
#define PH 8
|
||||
#define PJ 10
|
||||
#define PK 11
|
||||
#define PL 12
|
||||
#endif
|
||||
|
||||
#define NOT_ON_TIMER 0
|
||||
#define TIMER0A 1
|
||||
#define TIMER0B 2
|
||||
#define TIMER1A 3
|
||||
#define TIMER1B 4
|
||||
#define TIMER2 5
|
||||
#define TIMER2A 6
|
||||
#define TIMER2B 7
|
||||
|
||||
#define TIMER3A 8
|
||||
#define TIMER3B 9
|
||||
#define TIMER3C 10
|
||||
#define TIMER4A 11
|
||||
#define TIMER4B 12
|
||||
#define TIMER4C 13
|
||||
#define TIMER4D 14
|
||||
#define TIMER5A 15
|
||||
#define TIMER5B 16
|
||||
#define TIMER5C 17
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
#include "WCharacter.h"
|
||||
#include "WString.h"
|
||||
#include "HardwareSerial.h"
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(byte h,
|
||||
byte l);
|
||||
|
||||
#define word(...) makeWord(__VA_ARGS__)
|
||||
|
||||
unsigned long pulseIn(uint8_t pin,
|
||||
uint8_t state,
|
||||
unsigned long timeout = 1000000L);
|
||||
|
||||
void tone(uint8_t _pin,
|
||||
unsigned int frequency,
|
||||
unsigned long duration = 0);
|
||||
void noTone(uint8_t _pin);
|
||||
|
||||
// WMath prototypes
|
||||
long random(long);
|
||||
long random(long,
|
||||
long);
|
||||
void randomSeed(unsigned int);
|
||||
long map(long,
|
||||
long,
|
||||
long,
|
||||
long,
|
||||
long);
|
||||
|
||||
#endif
|
||||
|
||||
#include "pins_arduino.h"
|
||||
|
||||
#endif
|
||||
|
||||
+130
-130
@@ -1,130 +1,130 @@
|
||||
/*
|
||||
HardwareSerial.h - Hardware serial library for Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
Modified 14 August 2012 by Alarus
|
||||
*/
|
||||
|
||||
#ifndef HardwareSerial_h
|
||||
#define HardwareSerial_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
struct ring_buffer;
|
||||
|
||||
class HardwareSerial:public Stream {
|
||||
private:
|
||||
ring_buffer * _rx_buffer;
|
||||
ring_buffer *_tx_buffer;
|
||||
volatile uint8_t *_ubrrh;
|
||||
volatile uint8_t *_ubrrl;
|
||||
volatile uint8_t *_ucsra;
|
||||
volatile uint8_t *_ucsrb;
|
||||
volatile uint8_t *_ucsrc;
|
||||
volatile uint8_t *_udr;
|
||||
uint8_t _rxen;
|
||||
uint8_t _txen;
|
||||
uint8_t _rxcie;
|
||||
uint8_t _udrie;
|
||||
uint8_t _u2x;
|
||||
bool transmitting;
|
||||
public:
|
||||
HardwareSerial(ring_buffer * rx_buffer,
|
||||
ring_buffer * tx_buffer,
|
||||
volatile uint8_t * ubrrh,
|
||||
volatile uint8_t * ubrrl,
|
||||
volatile uint8_t * ucsra,
|
||||
volatile uint8_t * ucsrb,
|
||||
volatile uint8_t * ucsrc,
|
||||
volatile uint8_t * udr,
|
||||
uint8_t rxen,
|
||||
uint8_t txen,
|
||||
uint8_t rxcie,
|
||||
uint8_t udrie,
|
||||
uint8_t u2x);
|
||||
void begin(unsigned long);
|
||||
void begin(unsigned long,
|
||||
uint8_t);
|
||||
void end();
|
||||
virtual int available(void);
|
||||
virtual int peek(void);
|
||||
virtual int read(void);
|
||||
virtual void flush(void);
|
||||
virtual size_t write(uint8_t);
|
||||
inline size_t write(unsigned long n) {
|
||||
return write((uint8_t) n);
|
||||
} inline size_t write(long n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
operator bool();
|
||||
};
|
||||
|
||||
// Define config for Serial.begin(baud, config);
|
||||
#define SERIAL_5N1 0x00
|
||||
#define SERIAL_6N1 0x02
|
||||
#define SERIAL_7N1 0x04
|
||||
#define SERIAL_8N1 0x06
|
||||
#define SERIAL_5N2 0x08
|
||||
#define SERIAL_6N2 0x0A
|
||||
#define SERIAL_7N2 0x0C
|
||||
#define SERIAL_8N2 0x0E
|
||||
#define SERIAL_5E1 0x20
|
||||
#define SERIAL_6E1 0x22
|
||||
#define SERIAL_7E1 0x24
|
||||
#define SERIAL_8E1 0x26
|
||||
#define SERIAL_5E2 0x28
|
||||
#define SERIAL_6E2 0x2A
|
||||
#define SERIAL_7E2 0x2C
|
||||
#define SERIAL_8E2 0x2E
|
||||
#define SERIAL_5O1 0x30
|
||||
#define SERIAL_6O1 0x32
|
||||
#define SERIAL_7O1 0x34
|
||||
#define SERIAL_8O1 0x36
|
||||
#define SERIAL_5O2 0x38
|
||||
#define SERIAL_6O2 0x3A
|
||||
#define SERIAL_7O2 0x3C
|
||||
#define SERIAL_8O2 0x3E
|
||||
|
||||
#if defined(UBRRH) || defined(UBRR0H)
|
||||
extern HardwareSerial Serial;
|
||||
#elif defined(USBCON)
|
||||
#include "USBAPI.h"
|
||||
// extern HardwareSerial Serial_;
|
||||
#endif
|
||||
#if defined(UBRR1H)
|
||||
extern HardwareSerial Serial1;
|
||||
#endif
|
||||
#if defined(UBRR2H)
|
||||
extern HardwareSerial Serial2;
|
||||
#endif
|
||||
#if defined(UBRR3H)
|
||||
extern HardwareSerial Serial3;
|
||||
#endif
|
||||
|
||||
extern void serialEventRun(void) __attribute__ ((weak));
|
||||
|
||||
#endif
|
||||
/*
|
||||
HardwareSerial.h - Hardware serial library for Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
Modified 14 August 2012 by Alarus
|
||||
*/
|
||||
|
||||
#ifndef HardwareSerial_h
|
||||
#define HardwareSerial_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
struct ring_buffer;
|
||||
|
||||
class HardwareSerial:public Stream {
|
||||
private:
|
||||
ring_buffer * _rx_buffer;
|
||||
ring_buffer *_tx_buffer;
|
||||
volatile uint8_t *_ubrrh;
|
||||
volatile uint8_t *_ubrrl;
|
||||
volatile uint8_t *_ucsra;
|
||||
volatile uint8_t *_ucsrb;
|
||||
volatile uint8_t *_ucsrc;
|
||||
volatile uint8_t *_udr;
|
||||
uint8_t _rxen;
|
||||
uint8_t _txen;
|
||||
uint8_t _rxcie;
|
||||
uint8_t _udrie;
|
||||
uint8_t _u2x;
|
||||
bool transmitting;
|
||||
public:
|
||||
HardwareSerial(ring_buffer * rx_buffer,
|
||||
ring_buffer * tx_buffer,
|
||||
volatile uint8_t * ubrrh,
|
||||
volatile uint8_t * ubrrl,
|
||||
volatile uint8_t * ucsra,
|
||||
volatile uint8_t * ucsrb,
|
||||
volatile uint8_t * ucsrc,
|
||||
volatile uint8_t * udr,
|
||||
uint8_t rxen,
|
||||
uint8_t txen,
|
||||
uint8_t rxcie,
|
||||
uint8_t udrie,
|
||||
uint8_t u2x);
|
||||
void begin(unsigned long);
|
||||
void begin(unsigned long,
|
||||
uint8_t);
|
||||
void end();
|
||||
virtual int available(void);
|
||||
virtual int peek(void);
|
||||
virtual int read(void);
|
||||
virtual void flush(void);
|
||||
virtual size_t write(uint8_t);
|
||||
inline size_t write(unsigned long n) {
|
||||
return write((uint8_t) n);
|
||||
} inline size_t write(long n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
operator bool();
|
||||
};
|
||||
|
||||
// Define config for Serial.begin(baud, config);
|
||||
#define SERIAL_5N1 0x00
|
||||
#define SERIAL_6N1 0x02
|
||||
#define SERIAL_7N1 0x04
|
||||
#define SERIAL_8N1 0x06
|
||||
#define SERIAL_5N2 0x08
|
||||
#define SERIAL_6N2 0x0A
|
||||
#define SERIAL_7N2 0x0C
|
||||
#define SERIAL_8N2 0x0E
|
||||
#define SERIAL_5E1 0x20
|
||||
#define SERIAL_6E1 0x22
|
||||
#define SERIAL_7E1 0x24
|
||||
#define SERIAL_8E1 0x26
|
||||
#define SERIAL_5E2 0x28
|
||||
#define SERIAL_6E2 0x2A
|
||||
#define SERIAL_7E2 0x2C
|
||||
#define SERIAL_8E2 0x2E
|
||||
#define SERIAL_5O1 0x30
|
||||
#define SERIAL_6O1 0x32
|
||||
#define SERIAL_7O1 0x34
|
||||
#define SERIAL_8O1 0x36
|
||||
#define SERIAL_5O2 0x38
|
||||
#define SERIAL_6O2 0x3A
|
||||
#define SERIAL_7O2 0x3C
|
||||
#define SERIAL_8O2 0x3E
|
||||
|
||||
#if defined(UBRRH) || defined(UBRR0H)
|
||||
extern HardwareSerial Serial;
|
||||
#elif defined(USBCON)
|
||||
#include "USBAPI.h"
|
||||
// extern HardwareSerial Serial_;
|
||||
#endif
|
||||
#if defined(UBRR1H)
|
||||
extern HardwareSerial Serial1;
|
||||
#endif
|
||||
#if defined(UBRR2H)
|
||||
extern HardwareSerial Serial2;
|
||||
#endif
|
||||
#if defined(UBRR3H)
|
||||
extern HardwareSerial Serial3;
|
||||
#endif
|
||||
|
||||
extern void serialEventRun(void) __attribute__ ((weak));
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef server_h
|
||||
#define server_h
|
||||
|
||||
class Server:public Print {
|
||||
public:
|
||||
virtual void begin() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifndef server_h
|
||||
#define server_h
|
||||
|
||||
class Server:public Print {
|
||||
public:
|
||||
virtual void begin() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+202
-202
@@ -1,202 +1,202 @@
|
||||
|
||||
|
||||
#ifndef __USBAPI__
|
||||
#define __USBAPI__
|
||||
|
||||
#if defined(USBCON)
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// USB
|
||||
|
||||
class USBDevice_ {
|
||||
public:
|
||||
USBDevice_();
|
||||
bool configured();
|
||||
|
||||
void attach();
|
||||
void detach(); // Serial port goes down too...
|
||||
void poll();
|
||||
};
|
||||
extern USBDevice_ USBDevice;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Serial over CDC (Serial1 is the physical port)
|
||||
|
||||
class Serial_:public Stream {
|
||||
private:
|
||||
ring_buffer * _cdc_rx_buffer;
|
||||
public:
|
||||
void begin(uint16_t baud_count);
|
||||
void end(void);
|
||||
|
||||
virtual int available(void);
|
||||
virtual void accept(void);
|
||||
virtual int peek(void);
|
||||
virtual int read(void);
|
||||
virtual void flush(void);
|
||||
virtual size_t write(uint8_t);
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
operator bool();
|
||||
};
|
||||
extern Serial_ Serial;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Mouse
|
||||
|
||||
#define MOUSE_LEFT 1
|
||||
#define MOUSE_RIGHT 2
|
||||
#define MOUSE_MIDDLE 4
|
||||
#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)
|
||||
|
||||
class Mouse_ {
|
||||
private:
|
||||
uint8_t _buttons;
|
||||
void buttons(uint8_t b);
|
||||
public:
|
||||
Mouse_(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
void click(uint8_t b = MOUSE_LEFT);
|
||||
void move(signed char x,
|
||||
signed char y,
|
||||
signed char wheel = 0);
|
||||
void press(uint8_t b = MOUSE_LEFT); // press LEFT by default
|
||||
void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
|
||||
bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default
|
||||
};
|
||||
extern Mouse_ Mouse;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Keyboard
|
||||
|
||||
#define KEY_LEFT_CTRL 0x80
|
||||
#define KEY_LEFT_SHIFT 0x81
|
||||
#define KEY_LEFT_ALT 0x82
|
||||
#define KEY_LEFT_GUI 0x83
|
||||
#define KEY_RIGHT_CTRL 0x84
|
||||
#define KEY_RIGHT_SHIFT 0x85
|
||||
#define KEY_RIGHT_ALT 0x86
|
||||
#define KEY_RIGHT_GUI 0x87
|
||||
|
||||
#define KEY_UP_ARROW 0xDA
|
||||
#define KEY_DOWN_ARROW 0xD9
|
||||
#define KEY_LEFT_ARROW 0xD8
|
||||
#define KEY_RIGHT_ARROW 0xD7
|
||||
#define KEY_BACKSPACE 0xB2
|
||||
#define KEY_TAB 0xB3
|
||||
#define KEY_RETURN 0xB0
|
||||
#define KEY_ESC 0xB1
|
||||
#define KEY_INSERT 0xD1
|
||||
#define KEY_DELETE 0xD4
|
||||
#define KEY_PAGE_UP 0xD3
|
||||
#define KEY_PAGE_DOWN 0xD6
|
||||
#define KEY_HOME 0xD2
|
||||
#define KEY_END 0xD5
|
||||
#define KEY_CAPS_LOCK 0xC1
|
||||
#define KEY_F1 0xC2
|
||||
#define KEY_F2 0xC3
|
||||
#define KEY_F3 0xC4
|
||||
#define KEY_F4 0xC5
|
||||
#define KEY_F5 0xC6
|
||||
#define KEY_F6 0xC7
|
||||
#define KEY_F7 0xC8
|
||||
#define KEY_F8 0xC9
|
||||
#define KEY_F9 0xCA
|
||||
#define KEY_F10 0xCB
|
||||
#define KEY_F11 0xCC
|
||||
#define KEY_F12 0xCD
|
||||
|
||||
// Low level key report: up to 6 keys and shift, ctrl etc at once
|
||||
typedef struct {
|
||||
uint8_t modifiers;
|
||||
uint8_t reserved;
|
||||
uint8_t keys[6];
|
||||
} KeyReport;
|
||||
|
||||
class Keyboard_:public Print {
|
||||
private:
|
||||
KeyReport _keyReport;
|
||||
void sendReport(KeyReport * keys);
|
||||
public:
|
||||
Keyboard_(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
virtual size_t write(uint8_t k);
|
||||
virtual size_t press(uint8_t k);
|
||||
virtual size_t release(uint8_t k);
|
||||
virtual void releaseAll(void);
|
||||
};
|
||||
extern Keyboard_ Keyboard;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Low level API
|
||||
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint8_t wValueL;
|
||||
uint8_t wValueH;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} Setup;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// HID 'Driver'
|
||||
|
||||
int HID_GetInterface(uint8_t * interfaceNum);
|
||||
int HID_GetDescriptor(int i);
|
||||
bool HID_Setup(Setup & setup);
|
||||
void HID_SendReport(uint8_t id,
|
||||
const void *data,
|
||||
int len);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// MSC 'Driver'
|
||||
|
||||
int MSC_GetInterface(uint8_t * interfaceNum);
|
||||
int MSC_GetDescriptor(int i);
|
||||
bool MSC_Setup(Setup & setup);
|
||||
bool MSC_Data(uint8_t rx,
|
||||
uint8_t tx);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// CSC 'Driver'
|
||||
|
||||
int CDC_GetInterface(uint8_t * interfaceNum);
|
||||
int CDC_GetDescriptor(int i);
|
||||
bool CDC_Setup(Setup & setup);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
|
||||
#define TRANSFER_PGM 0x80
|
||||
#define TRANSFER_RELEASE 0x40
|
||||
#define TRANSFER_ZERO 0x20
|
||||
|
||||
int USB_SendControl(uint8_t flags,
|
||||
const void *d,
|
||||
int len);
|
||||
int USB_RecvControl(void *d,
|
||||
int len);
|
||||
|
||||
uint8_t USB_Available(uint8_t ep);
|
||||
int USB_Send(uint8_t ep,
|
||||
const void *data,
|
||||
int len); // blocking
|
||||
int USB_Recv(uint8_t ep,
|
||||
void *data,
|
||||
int len); // non-blocking
|
||||
int USB_Recv(uint8_t ep); // non-blocking
|
||||
void USB_Flush(uint8_t ep);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* if defined(USBCON) */
|
||||
|
||||
|
||||
#ifndef __USBAPI__
|
||||
#define __USBAPI__
|
||||
|
||||
#if defined(USBCON)
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// USB
|
||||
|
||||
class USBDevice_ {
|
||||
public:
|
||||
USBDevice_();
|
||||
bool configured();
|
||||
|
||||
void attach();
|
||||
void detach(); // Serial port goes down too...
|
||||
void poll();
|
||||
};
|
||||
extern USBDevice_ USBDevice;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Serial over CDC (Serial1 is the physical port)
|
||||
|
||||
class Serial_:public Stream {
|
||||
private:
|
||||
ring_buffer * _cdc_rx_buffer;
|
||||
public:
|
||||
void begin(uint16_t baud_count);
|
||||
void end(void);
|
||||
|
||||
virtual int available(void);
|
||||
virtual void accept(void);
|
||||
virtual int peek(void);
|
||||
virtual int read(void);
|
||||
virtual void flush(void);
|
||||
virtual size_t write(uint8_t);
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
operator bool();
|
||||
};
|
||||
extern Serial_ Serial;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Mouse
|
||||
|
||||
#define MOUSE_LEFT 1
|
||||
#define MOUSE_RIGHT 2
|
||||
#define MOUSE_MIDDLE 4
|
||||
#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)
|
||||
|
||||
class Mouse_ {
|
||||
private:
|
||||
uint8_t _buttons;
|
||||
void buttons(uint8_t b);
|
||||
public:
|
||||
Mouse_(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
void click(uint8_t b = MOUSE_LEFT);
|
||||
void move(signed char x,
|
||||
signed char y,
|
||||
signed char wheel = 0);
|
||||
void press(uint8_t b = MOUSE_LEFT); // press LEFT by default
|
||||
void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
|
||||
bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default
|
||||
};
|
||||
extern Mouse_ Mouse;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Keyboard
|
||||
|
||||
#define KEY_LEFT_CTRL 0x80
|
||||
#define KEY_LEFT_SHIFT 0x81
|
||||
#define KEY_LEFT_ALT 0x82
|
||||
#define KEY_LEFT_GUI 0x83
|
||||
#define KEY_RIGHT_CTRL 0x84
|
||||
#define KEY_RIGHT_SHIFT 0x85
|
||||
#define KEY_RIGHT_ALT 0x86
|
||||
#define KEY_RIGHT_GUI 0x87
|
||||
|
||||
#define KEY_UP_ARROW 0xDA
|
||||
#define KEY_DOWN_ARROW 0xD9
|
||||
#define KEY_LEFT_ARROW 0xD8
|
||||
#define KEY_RIGHT_ARROW 0xD7
|
||||
#define KEY_BACKSPACE 0xB2
|
||||
#define KEY_TAB 0xB3
|
||||
#define KEY_RETURN 0xB0
|
||||
#define KEY_ESC 0xB1
|
||||
#define KEY_INSERT 0xD1
|
||||
#define KEY_DELETE 0xD4
|
||||
#define KEY_PAGE_UP 0xD3
|
||||
#define KEY_PAGE_DOWN 0xD6
|
||||
#define KEY_HOME 0xD2
|
||||
#define KEY_END 0xD5
|
||||
#define KEY_CAPS_LOCK 0xC1
|
||||
#define KEY_F1 0xC2
|
||||
#define KEY_F2 0xC3
|
||||
#define KEY_F3 0xC4
|
||||
#define KEY_F4 0xC5
|
||||
#define KEY_F5 0xC6
|
||||
#define KEY_F6 0xC7
|
||||
#define KEY_F7 0xC8
|
||||
#define KEY_F8 0xC9
|
||||
#define KEY_F9 0xCA
|
||||
#define KEY_F10 0xCB
|
||||
#define KEY_F11 0xCC
|
||||
#define KEY_F12 0xCD
|
||||
|
||||
// Low level key report: up to 6 keys and shift, ctrl etc at once
|
||||
typedef struct {
|
||||
uint8_t modifiers;
|
||||
uint8_t reserved;
|
||||
uint8_t keys[6];
|
||||
} KeyReport;
|
||||
|
||||
class Keyboard_:public Print {
|
||||
private:
|
||||
KeyReport _keyReport;
|
||||
void sendReport(KeyReport * keys);
|
||||
public:
|
||||
Keyboard_(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
virtual size_t write(uint8_t k);
|
||||
virtual size_t press(uint8_t k);
|
||||
virtual size_t release(uint8_t k);
|
||||
virtual void releaseAll(void);
|
||||
};
|
||||
extern Keyboard_ Keyboard;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Low level API
|
||||
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint8_t wValueL;
|
||||
uint8_t wValueH;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} Setup;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// HID 'Driver'
|
||||
|
||||
int HID_GetInterface(uint8_t * interfaceNum);
|
||||
int HID_GetDescriptor(int i);
|
||||
bool HID_Setup(Setup & setup);
|
||||
void HID_SendReport(uint8_t id,
|
||||
const void *data,
|
||||
int len);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// MSC 'Driver'
|
||||
|
||||
int MSC_GetInterface(uint8_t * interfaceNum);
|
||||
int MSC_GetDescriptor(int i);
|
||||
bool MSC_Setup(Setup & setup);
|
||||
bool MSC_Data(uint8_t rx,
|
||||
uint8_t tx);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// CSC 'Driver'
|
||||
|
||||
int CDC_GetInterface(uint8_t * interfaceNum);
|
||||
int CDC_GetDescriptor(int i);
|
||||
bool CDC_Setup(Setup & setup);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
|
||||
#define TRANSFER_PGM 0x80
|
||||
#define TRANSFER_RELEASE 0x40
|
||||
#define TRANSFER_ZERO 0x20
|
||||
|
||||
int USB_SendControl(uint8_t flags,
|
||||
const void *d,
|
||||
int len);
|
||||
int USB_RecvControl(void *d,
|
||||
int len);
|
||||
|
||||
uint8_t USB_Available(uint8_t ep);
|
||||
int USB_Send(uint8_t ep,
|
||||
const void *data,
|
||||
int len); // blocking
|
||||
int USB_Recv(uint8_t ep,
|
||||
void *data,
|
||||
int len); // non-blocking
|
||||
int USB_Recv(uint8_t ep); // non-blocking
|
||||
void USB_Flush(uint8_t ep);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* if defined(USBCON) */
|
||||
|
||||
+292
-292
@@ -1,292 +1,292 @@
|
||||
|
||||
// Copyright (c) 2010, Peter Barrett
|
||||
/*
|
||||
** Permission to use, copy, modify, and/or distribute this software for
|
||||
** any purpose with or without fee is hereby granted, provided that the
|
||||
** above copyright notice and this permission notice appear in all copies.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
** SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __USBCORE_H__
|
||||
#define __USBCORE_H__
|
||||
|
||||
// Standard requests
|
||||
#define GET_STATUS 0
|
||||
#define CLEAR_FEATURE 1
|
||||
#define SET_FEATURE 3
|
||||
#define SET_ADDRESS 5
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_DESCRIPTOR 7
|
||||
#define GET_CONFIGURATION 8
|
||||
#define SET_CONFIGURATION 9
|
||||
#define GET_INTERFACE 10
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
|
||||
// bmRequestType
|
||||
#define REQUEST_HOSTTODEVICE 0x00
|
||||
#define REQUEST_DEVICETOHOST 0x80
|
||||
#define REQUEST_DIRECTION 0x80
|
||||
|
||||
#define REQUEST_STANDARD 0x00
|
||||
#define REQUEST_CLASS 0x20
|
||||
#define REQUEST_VENDOR 0x40
|
||||
#define REQUEST_TYPE 0x60
|
||||
|
||||
#define REQUEST_DEVICE 0x00
|
||||
#define REQUEST_INTERFACE 0x01
|
||||
#define REQUEST_ENDPOINT 0x02
|
||||
#define REQUEST_OTHER 0x03
|
||||
#define REQUEST_RECIPIENT 0x03
|
||||
|
||||
#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST + REQUEST_CLASS + REQUEST_INTERFACE)
|
||||
#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE + REQUEST_CLASS + REQUEST_INTERFACE)
|
||||
|
||||
// Class requests
|
||||
|
||||
#define CDC_SET_LINE_CODING 0x20
|
||||
#define CDC_GET_LINE_CODING 0x21
|
||||
#define CDC_SET_CONTROL_LINE_STATE 0x22
|
||||
|
||||
#define MSC_RESET 0xFF
|
||||
#define MSC_GET_MAX_LUN 0xFE
|
||||
|
||||
#define HID_GET_REPORT 0x01
|
||||
#define HID_GET_IDLE 0x02
|
||||
#define HID_GET_PROTOCOL 0x03
|
||||
#define HID_SET_REPORT 0x09
|
||||
#define HID_SET_IDLE 0x0A
|
||||
#define HID_SET_PROTOCOL 0x0B
|
||||
|
||||
// Descriptors
|
||||
|
||||
#define USB_DEVICE_DESC_SIZE 18
|
||||
#define USB_CONFIGUARTION_DESC_SIZE 9
|
||||
#define USB_INTERFACE_DESC_SIZE 9
|
||||
#define USB_ENDPOINT_DESC_SIZE 7
|
||||
|
||||
#define USB_DEVICE_DESCRIPTOR_TYPE 1
|
||||
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2
|
||||
#define USB_STRING_DESCRIPTOR_TYPE 3
|
||||
#define USB_INTERFACE_DESCRIPTOR_TYPE 4
|
||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE 5
|
||||
|
||||
#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
|
||||
#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
|
||||
#define USB_DEVICE_CLASS_STORAGE 0x08
|
||||
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
|
||||
|
||||
#define USB_CONFIG_POWERED_MASK 0x40
|
||||
#define USB_CONFIG_BUS_POWERED 0x80
|
||||
#define USB_CONFIG_SELF_POWERED 0xC0
|
||||
#define USB_CONFIG_REMOTE_WAKEUP 0x20
|
||||
|
||||
// bMaxPower in Configuration Descriptor
|
||||
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
|
||||
|
||||
// bEndpointAddress in Endpoint Descriptor
|
||||
#define USB_ENDPOINT_DIRECTION_MASK 0x80
|
||||
#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00)
|
||||
#define USB_ENDPOINT_IN(addr) ((addr) | 0x80)
|
||||
|
||||
#define USB_ENDPOINT_TYPE_MASK 0x03
|
||||
#define USB_ENDPOINT_TYPE_CONTROL 0x00
|
||||
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
|
||||
#define USB_ENDPOINT_TYPE_BULK 0x02
|
||||
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF)
|
||||
|
||||
#define CDC_V1_10 0x0110
|
||||
#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02
|
||||
|
||||
#define CDC_CALL_MANAGEMENT 0x01
|
||||
#define CDC_ABSTRACT_CONTROL_MODEL 0x02
|
||||
#define CDC_HEADER 0x00
|
||||
#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02
|
||||
#define CDC_UNION 0x06
|
||||
#define CDC_CS_INTERFACE 0x24
|
||||
#define CDC_CS_ENDPOINT 0x25
|
||||
#define CDC_DATA_INTERFACE_CLASS 0x0A
|
||||
|
||||
#define MSC_SUBCLASS_SCSI 0x06
|
||||
#define MSC_PROTOCOL_BULK_ONLY 0x50
|
||||
|
||||
#define HID_HID_DESCRIPTOR_TYPE 0x21
|
||||
#define HID_REPORT_DESCRIPTOR_TYPE 0x22
|
||||
#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
|
||||
|
||||
|
||||
// Device
|
||||
typedef struct {
|
||||
u8 len; // 18
|
||||
u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE
|
||||
u16 usbVersion; // 0x200
|
||||
u8 deviceClass;
|
||||
u8 deviceSubClass;
|
||||
u8 deviceProtocol;
|
||||
u8 packetSize0; // Packet 0
|
||||
u16 idVendor;
|
||||
u16 idProduct;
|
||||
u16 deviceVersion; // 0x100
|
||||
u8 iManufacturer;
|
||||
u8 iProduct;
|
||||
u8 iSerialNumber;
|
||||
u8 bNumConfigurations;
|
||||
} DeviceDescriptor;
|
||||
|
||||
// Config
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 2
|
||||
u16 clen; // total length
|
||||
u8 numInterfaces;
|
||||
u8 config;
|
||||
u8 iconfig;
|
||||
u8 attributes;
|
||||
u8 maxPower;
|
||||
} ConfigDescriptor;
|
||||
|
||||
// String
|
||||
|
||||
// Interface
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 4
|
||||
u8 number;
|
||||
u8 alternate;
|
||||
u8 numEndpoints;
|
||||
u8 interfaceClass;
|
||||
u8 interfaceSubClass;
|
||||
u8 protocol;
|
||||
u8 iInterface;
|
||||
} InterfaceDescriptor;
|
||||
|
||||
// Endpoint
|
||||
typedef struct {
|
||||
u8 len; // 7
|
||||
u8 dtype; // 5
|
||||
u8 addr;
|
||||
u8 attr;
|
||||
u16 packetSize;
|
||||
u8 interval;
|
||||
} EndpointDescriptor;
|
||||
|
||||
// Interface Association Descriptor
|
||||
// Used to bind 2 interfaces together in CDC compostite device
|
||||
typedef struct {
|
||||
u8 len; // 8
|
||||
u8 dtype; // 11
|
||||
u8 firstInterface;
|
||||
u8 interfaceCount;
|
||||
u8 functionClass;
|
||||
u8 funtionSubClass;
|
||||
u8 functionProtocol;
|
||||
u8 iInterface;
|
||||
} IADDescriptor;
|
||||
|
||||
// CDC CS interface descriptor
|
||||
typedef struct {
|
||||
u8 len; // 5
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype;
|
||||
u8 d0;
|
||||
u8 d1;
|
||||
} CDCCSInterfaceDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len; // 4
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype;
|
||||
u8 d0;
|
||||
} CDCCSInterfaceDescriptor4;
|
||||
|
||||
typedef struct {
|
||||
u8 len;
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype; // 1
|
||||
u8 bmCapabilities;
|
||||
u8 bDataInterface;
|
||||
} CMFunctionalDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len;
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype; // 1
|
||||
u8 bmCapabilities;
|
||||
} ACMFunctionalDescriptor;
|
||||
|
||||
typedef struct {
|
||||
// IAD
|
||||
IADDescriptor iad; // Only needed on compound device
|
||||
|
||||
// Control
|
||||
InterfaceDescriptor cif; //
|
||||
CDCCSInterfaceDescriptor header;
|
||||
CMFunctionalDescriptor callManagement; // Call Management
|
||||
ACMFunctionalDescriptor controlManagement; // ACM
|
||||
CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION
|
||||
EndpointDescriptor cifin;
|
||||
|
||||
// Data
|
||||
InterfaceDescriptor dif;
|
||||
EndpointDescriptor in;
|
||||
EndpointDescriptor out;
|
||||
} CDCDescriptor;
|
||||
|
||||
typedef struct {
|
||||
InterfaceDescriptor msc;
|
||||
EndpointDescriptor in;
|
||||
EndpointDescriptor out;
|
||||
} MSCDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 0x21
|
||||
u8 addr;
|
||||
u8 versionL; // 0x101
|
||||
u8 versionH; // 0x101
|
||||
u8 country;
|
||||
u8 desctype; // 0x22 report
|
||||
u8 descLenL;
|
||||
u8 descLenH;
|
||||
} HIDDescDescriptor;
|
||||
|
||||
typedef struct {
|
||||
InterfaceDescriptor hid;
|
||||
HIDDescDescriptor desc;
|
||||
EndpointDescriptor in;
|
||||
} HIDDescriptor;
|
||||
|
||||
|
||||
#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \
|
||||
{ 18, 1, 0x200, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs }
|
||||
|
||||
#define D_CONFIG(_totalLength,_interfaces) \
|
||||
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED, USB_CONFIG_POWER_MA(500) }
|
||||
|
||||
#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \
|
||||
{ 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 }
|
||||
|
||||
#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \
|
||||
{ 7, 5, _addr,_attr,_packetSize, _interval }
|
||||
|
||||
#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \
|
||||
{ 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 }
|
||||
|
||||
#define D_HIDREPORT(_descriptorLength) \
|
||||
{ 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 }
|
||||
|
||||
#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 }
|
||||
#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 }
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
// Copyright (c) 2010, Peter Barrett
|
||||
/*
|
||||
** Permission to use, copy, modify, and/or distribute this software for
|
||||
** any purpose with or without fee is hereby granted, provided that the
|
||||
** above copyright notice and this permission notice appear in all copies.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
** SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __USBCORE_H__
|
||||
#define __USBCORE_H__
|
||||
|
||||
// Standard requests
|
||||
#define GET_STATUS 0
|
||||
#define CLEAR_FEATURE 1
|
||||
#define SET_FEATURE 3
|
||||
#define SET_ADDRESS 5
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_DESCRIPTOR 7
|
||||
#define GET_CONFIGURATION 8
|
||||
#define SET_CONFIGURATION 9
|
||||
#define GET_INTERFACE 10
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
|
||||
// bmRequestType
|
||||
#define REQUEST_HOSTTODEVICE 0x00
|
||||
#define REQUEST_DEVICETOHOST 0x80
|
||||
#define REQUEST_DIRECTION 0x80
|
||||
|
||||
#define REQUEST_STANDARD 0x00
|
||||
#define REQUEST_CLASS 0x20
|
||||
#define REQUEST_VENDOR 0x40
|
||||
#define REQUEST_TYPE 0x60
|
||||
|
||||
#define REQUEST_DEVICE 0x00
|
||||
#define REQUEST_INTERFACE 0x01
|
||||
#define REQUEST_ENDPOINT 0x02
|
||||
#define REQUEST_OTHER 0x03
|
||||
#define REQUEST_RECIPIENT 0x03
|
||||
|
||||
#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST + REQUEST_CLASS + REQUEST_INTERFACE)
|
||||
#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE + REQUEST_CLASS + REQUEST_INTERFACE)
|
||||
|
||||
// Class requests
|
||||
|
||||
#define CDC_SET_LINE_CODING 0x20
|
||||
#define CDC_GET_LINE_CODING 0x21
|
||||
#define CDC_SET_CONTROL_LINE_STATE 0x22
|
||||
|
||||
#define MSC_RESET 0xFF
|
||||
#define MSC_GET_MAX_LUN 0xFE
|
||||
|
||||
#define HID_GET_REPORT 0x01
|
||||
#define HID_GET_IDLE 0x02
|
||||
#define HID_GET_PROTOCOL 0x03
|
||||
#define HID_SET_REPORT 0x09
|
||||
#define HID_SET_IDLE 0x0A
|
||||
#define HID_SET_PROTOCOL 0x0B
|
||||
|
||||
// Descriptors
|
||||
|
||||
#define USB_DEVICE_DESC_SIZE 18
|
||||
#define USB_CONFIGUARTION_DESC_SIZE 9
|
||||
#define USB_INTERFACE_DESC_SIZE 9
|
||||
#define USB_ENDPOINT_DESC_SIZE 7
|
||||
|
||||
#define USB_DEVICE_DESCRIPTOR_TYPE 1
|
||||
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2
|
||||
#define USB_STRING_DESCRIPTOR_TYPE 3
|
||||
#define USB_INTERFACE_DESCRIPTOR_TYPE 4
|
||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE 5
|
||||
|
||||
#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
|
||||
#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
|
||||
#define USB_DEVICE_CLASS_STORAGE 0x08
|
||||
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
|
||||
|
||||
#define USB_CONFIG_POWERED_MASK 0x40
|
||||
#define USB_CONFIG_BUS_POWERED 0x80
|
||||
#define USB_CONFIG_SELF_POWERED 0xC0
|
||||
#define USB_CONFIG_REMOTE_WAKEUP 0x20
|
||||
|
||||
// bMaxPower in Configuration Descriptor
|
||||
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
|
||||
|
||||
// bEndpointAddress in Endpoint Descriptor
|
||||
#define USB_ENDPOINT_DIRECTION_MASK 0x80
|
||||
#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00)
|
||||
#define USB_ENDPOINT_IN(addr) ((addr) | 0x80)
|
||||
|
||||
#define USB_ENDPOINT_TYPE_MASK 0x03
|
||||
#define USB_ENDPOINT_TYPE_CONTROL 0x00
|
||||
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
|
||||
#define USB_ENDPOINT_TYPE_BULK 0x02
|
||||
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF)
|
||||
|
||||
#define CDC_V1_10 0x0110
|
||||
#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02
|
||||
|
||||
#define CDC_CALL_MANAGEMENT 0x01
|
||||
#define CDC_ABSTRACT_CONTROL_MODEL 0x02
|
||||
#define CDC_HEADER 0x00
|
||||
#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02
|
||||
#define CDC_UNION 0x06
|
||||
#define CDC_CS_INTERFACE 0x24
|
||||
#define CDC_CS_ENDPOINT 0x25
|
||||
#define CDC_DATA_INTERFACE_CLASS 0x0A
|
||||
|
||||
#define MSC_SUBCLASS_SCSI 0x06
|
||||
#define MSC_PROTOCOL_BULK_ONLY 0x50
|
||||
|
||||
#define HID_HID_DESCRIPTOR_TYPE 0x21
|
||||
#define HID_REPORT_DESCRIPTOR_TYPE 0x22
|
||||
#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
|
||||
|
||||
|
||||
// Device
|
||||
typedef struct {
|
||||
u8 len; // 18
|
||||
u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE
|
||||
u16 usbVersion; // 0x200
|
||||
u8 deviceClass;
|
||||
u8 deviceSubClass;
|
||||
u8 deviceProtocol;
|
||||
u8 packetSize0; // Packet 0
|
||||
u16 idVendor;
|
||||
u16 idProduct;
|
||||
u16 deviceVersion; // 0x100
|
||||
u8 iManufacturer;
|
||||
u8 iProduct;
|
||||
u8 iSerialNumber;
|
||||
u8 bNumConfigurations;
|
||||
} DeviceDescriptor;
|
||||
|
||||
// Config
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 2
|
||||
u16 clen; // total length
|
||||
u8 numInterfaces;
|
||||
u8 config;
|
||||
u8 iconfig;
|
||||
u8 attributes;
|
||||
u8 maxPower;
|
||||
} ConfigDescriptor;
|
||||
|
||||
// String
|
||||
|
||||
// Interface
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 4
|
||||
u8 number;
|
||||
u8 alternate;
|
||||
u8 numEndpoints;
|
||||
u8 interfaceClass;
|
||||
u8 interfaceSubClass;
|
||||
u8 protocol;
|
||||
u8 iInterface;
|
||||
} InterfaceDescriptor;
|
||||
|
||||
// Endpoint
|
||||
typedef struct {
|
||||
u8 len; // 7
|
||||
u8 dtype; // 5
|
||||
u8 addr;
|
||||
u8 attr;
|
||||
u16 packetSize;
|
||||
u8 interval;
|
||||
} EndpointDescriptor;
|
||||
|
||||
// Interface Association Descriptor
|
||||
// Used to bind 2 interfaces together in CDC compostite device
|
||||
typedef struct {
|
||||
u8 len; // 8
|
||||
u8 dtype; // 11
|
||||
u8 firstInterface;
|
||||
u8 interfaceCount;
|
||||
u8 functionClass;
|
||||
u8 funtionSubClass;
|
||||
u8 functionProtocol;
|
||||
u8 iInterface;
|
||||
} IADDescriptor;
|
||||
|
||||
// CDC CS interface descriptor
|
||||
typedef struct {
|
||||
u8 len; // 5
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype;
|
||||
u8 d0;
|
||||
u8 d1;
|
||||
} CDCCSInterfaceDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len; // 4
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype;
|
||||
u8 d0;
|
||||
} CDCCSInterfaceDescriptor4;
|
||||
|
||||
typedef struct {
|
||||
u8 len;
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype; // 1
|
||||
u8 bmCapabilities;
|
||||
u8 bDataInterface;
|
||||
} CMFunctionalDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len;
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype; // 1
|
||||
u8 bmCapabilities;
|
||||
} ACMFunctionalDescriptor;
|
||||
|
||||
typedef struct {
|
||||
// IAD
|
||||
IADDescriptor iad; // Only needed on compound device
|
||||
|
||||
// Control
|
||||
InterfaceDescriptor cif; //
|
||||
CDCCSInterfaceDescriptor header;
|
||||
CMFunctionalDescriptor callManagement; // Call Management
|
||||
ACMFunctionalDescriptor controlManagement; // ACM
|
||||
CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION
|
||||
EndpointDescriptor cifin;
|
||||
|
||||
// Data
|
||||
InterfaceDescriptor dif;
|
||||
EndpointDescriptor in;
|
||||
EndpointDescriptor out;
|
||||
} CDCDescriptor;
|
||||
|
||||
typedef struct {
|
||||
InterfaceDescriptor msc;
|
||||
EndpointDescriptor in;
|
||||
EndpointDescriptor out;
|
||||
} MSCDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 0x21
|
||||
u8 addr;
|
||||
u8 versionL; // 0x101
|
||||
u8 versionH; // 0x101
|
||||
u8 country;
|
||||
u8 desctype; // 0x22 report
|
||||
u8 descLenL;
|
||||
u8 descLenH;
|
||||
} HIDDescDescriptor;
|
||||
|
||||
typedef struct {
|
||||
InterfaceDescriptor hid;
|
||||
HIDDescDescriptor desc;
|
||||
EndpointDescriptor in;
|
||||
} HIDDescriptor;
|
||||
|
||||
|
||||
#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \
|
||||
{ 18, 1, 0x200, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs }
|
||||
|
||||
#define D_CONFIG(_totalLength,_interfaces) \
|
||||
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED, USB_CONFIG_POWER_MA(500) }
|
||||
|
||||
#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \
|
||||
{ 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 }
|
||||
|
||||
#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \
|
||||
{ 7, 5, _addr,_attr,_packetSize, _interval }
|
||||
|
||||
#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \
|
||||
{ 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 }
|
||||
|
||||
#define D_HIDREPORT(_descriptorLength) \
|
||||
{ 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 }
|
||||
|
||||
#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 }
|
||||
#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 }
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
/*
|
||||
* Udp.cpp: Library to send/receive UDP packets.
|
||||
*
|
||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
* might not happen often in practice, but in larger network topologies, a UDP
|
||||
* packet can be received out of sequence.
|
||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* 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.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#ifndef udp_h
|
||||
#define udp_h
|
||||
|
||||
#include <Stream.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
class UDP:public Stream {
|
||||
|
||||
public:
|
||||
virtual uint8_t begin(uint16_t) = 0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||
virtual void stop() = 0; // Finish with the UDP socket
|
||||
|
||||
// Sending UDP packets
|
||||
|
||||
// Start building up a packet to send to the remote host specific in ip and port
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
virtual int beginPacket(IPAddress ip,
|
||||
uint16_t port) = 0;
|
||||
// Start building up a packet to send to the remote host specific in host and port
|
||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||
virtual int beginPacket(const char *host,
|
||||
uint16_t port) = 0;
|
||||
// Finish off this packet and send it
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
virtual int endPacket() = 0;
|
||||
// Write a single byte into the packet
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
// Write size bytes from buffer into the packet
|
||||
virtual size_t write(const uint8_t * buffer,
|
||||
size_t size) = 0;
|
||||
|
||||
// Start processing the next available incoming packet
|
||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||
virtual int parsePacket() = 0;
|
||||
// Number of bytes remaining in the current packet
|
||||
virtual int available() = 0;
|
||||
// Read a single byte from the current packet
|
||||
virtual int read() = 0;
|
||||
// Read up to len bytes from the current packet and place them into buffer
|
||||
// Returns the number of bytes read, or 0 if none are available
|
||||
virtual int read(unsigned char *buffer,
|
||||
size_t len) = 0;
|
||||
// Read up to len characters from the current packet and place them into buffer
|
||||
// Returns the number of characters read, or 0 if none are available
|
||||
virtual int read(char *buffer,
|
||||
size_t len) = 0;
|
||||
// Return the next byte from the current packet without moving on to the next byte
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0; // Finish reading the current packet
|
||||
|
||||
// Return the IP address of the host who sent the current incoming packet
|
||||
virtual IPAddress remoteIP() = 0;
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
virtual uint16_t remotePort() = 0;
|
||||
protected:
|
||||
uint8_t * rawIPAddress(IPAddress & addr) {
|
||||
return addr.raw_address();
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Udp.cpp: Library to send/receive UDP packets.
|
||||
*
|
||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
* might not happen often in practice, but in larger network topologies, a UDP
|
||||
* packet can be received out of sequence.
|
||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* 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.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#ifndef udp_h
|
||||
#define udp_h
|
||||
|
||||
#include <Stream.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
class UDP:public Stream {
|
||||
|
||||
public:
|
||||
virtual uint8_t begin(uint16_t) = 0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||
virtual void stop() = 0; // Finish with the UDP socket
|
||||
|
||||
// Sending UDP packets
|
||||
|
||||
// Start building up a packet to send to the remote host specific in ip and port
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
virtual int beginPacket(IPAddress ip,
|
||||
uint16_t port) = 0;
|
||||
// Start building up a packet to send to the remote host specific in host and port
|
||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||
virtual int beginPacket(const char *host,
|
||||
uint16_t port) = 0;
|
||||
// Finish off this packet and send it
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
virtual int endPacket() = 0;
|
||||
// Write a single byte into the packet
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
// Write size bytes from buffer into the packet
|
||||
virtual size_t write(const uint8_t * buffer,
|
||||
size_t size) = 0;
|
||||
|
||||
// Start processing the next available incoming packet
|
||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||
virtual int parsePacket() = 0;
|
||||
// Number of bytes remaining in the current packet
|
||||
virtual int available() = 0;
|
||||
// Read a single byte from the current packet
|
||||
virtual int read() = 0;
|
||||
// Read up to len bytes from the current packet and place them into buffer
|
||||
// Returns the number of bytes read, or 0 if none are available
|
||||
virtual int read(unsigned char *buffer,
|
||||
size_t len) = 0;
|
||||
// Read up to len characters from the current packet and place them into buffer
|
||||
// Returns the number of characters read, or 0 if none are available
|
||||
virtual int read(char *buffer,
|
||||
size_t len) = 0;
|
||||
// Return the next byte from the current packet without moving on to the next byte
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0; // Finish reading the current packet
|
||||
|
||||
// Return the IP address of the host who sent the current incoming packet
|
||||
virtual IPAddress remoteIP() = 0;
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
virtual uint16_t remotePort() = 0;
|
||||
protected:
|
||||
uint8_t * rawIPAddress(IPAddress & addr) {
|
||||
return addr.raw_address();
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+515
-515
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,21 @@
|
||||
/* Header to define new/delete operators as they aren't provided by avr-gcc by default
|
||||
Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453
|
||||
*/
|
||||
|
||||
#ifndef NEW_H
|
||||
#define NEW_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void *operator new(size_t size);
|
||||
void operator delete(void *ptr);
|
||||
|
||||
__extension__ typedef int __guard __attribute__ ((mode(__DI__)));
|
||||
|
||||
extern "C" int __cxa_guard_acquire(__guard *);
|
||||
extern "C" void __cxa_guard_release(__guard *);
|
||||
extern "C" void __cxa_guard_abort(__guard *);
|
||||
|
||||
extern "C" void __cxa_pure_virtual(void);
|
||||
|
||||
#endif
|
||||
/* Header to define new/delete operators as they aren't provided by avr-gcc by default
|
||||
Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453
|
||||
*/
|
||||
|
||||
#ifndef NEW_H
|
||||
#define NEW_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void *operator new(size_t size);
|
||||
void operator delete(void *ptr);
|
||||
|
||||
__extension__ typedef int __guard __attribute__ ((mode(__DI__)));
|
||||
|
||||
extern "C" int __cxa_guard_acquire(__guard *);
|
||||
extern "C" void __cxa_guard_release(__guard *);
|
||||
extern "C" void __cxa_guard_abort(__guard *);
|
||||
|
||||
extern "C" void __cxa_pure_virtual(void);
|
||||
|
||||
#endif
|
||||
|
||||
+218
-218
@@ -1,218 +1,218 @@
|
||||
/*
|
||||
pins_arduino.h - Pin definition functions for Arduino
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2007 David A. Mellis
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define NUM_DIGITAL_PINS 20
|
||||
#define NUM_ANALOG_INPUTS 6
|
||||
#define analogInputToDigitalPin(p) ((p < 6) ? (p) + 14 : -1)
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
#define digitalPinHasPWM(p) ((p) == 9 || (p) == 10 || (p) == 11)
|
||||
#else
|
||||
#define digitalPinHasPWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11)
|
||||
#endif
|
||||
|
||||
static const uint8_t SS = 10;
|
||||
static const uint8_t MOSI = 11;
|
||||
static const uint8_t MISO = 12;
|
||||
static const uint8_t SCK = 13;
|
||||
|
||||
static const uint8_t SDA = 18;
|
||||
static const uint8_t SCL = 19;
|
||||
static const uint8_t LED_BUILTIN = 13;
|
||||
|
||||
static const uint8_t A0 = 14;
|
||||
static const uint8_t A1 = 15;
|
||||
static const uint8_t A2 = 16;
|
||||
static const uint8_t A3 = 17;
|
||||
static const uint8_t A4 = 18;
|
||||
static const uint8_t A5 = 19;
|
||||
static const uint8_t A6 = 20;
|
||||
static const uint8_t A7 = 21;
|
||||
|
||||
#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0))
|
||||
#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1))
|
||||
#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0))))
|
||||
#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14)))
|
||||
|
||||
#ifdef ARDUINO_MAIN
|
||||
|
||||
// On the Arduino board, digital pins are also used
|
||||
// for the analog output (software PWM). Analog input
|
||||
// pins are a separate set.
|
||||
|
||||
// ATMEL ATMEGA8 & 168 / ARDUINO
|
||||
//
|
||||
// +-\/-+
|
||||
// PC6 1| |28 PC5 (AI 5)
|
||||
// (D 0) PD0 2| |27 PC4 (AI 4)
|
||||
// (D 1) PD1 3| |26 PC3 (AI 3)
|
||||
// (D 2) PD2 4| |25 PC2 (AI 2)
|
||||
// PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
|
||||
// (D 4) PD4 6| |23 PC0 (AI 0)
|
||||
// VCC 7| |22 GND
|
||||
// GND 8| |21 AREF
|
||||
// PB6 9| |20 AVCC
|
||||
// PB7 10| |19 PB5 (D 13)
|
||||
// PWM+ (D 5) PD5 11| |18 PB4 (D 12)
|
||||
// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
|
||||
// (D 7) PD7 13| |16 PB2 (D 10) PWM
|
||||
// (D 8) PB0 14| |15 PB1 (D 9) PWM
|
||||
// +----+
|
||||
//
|
||||
// (PWM+ indicates the additional PWM pins on the ATmega168.)
|
||||
|
||||
// ATMEL ATMEGA1280 / ARDUINO
|
||||
//
|
||||
// 0-7 PE0-PE7 works
|
||||
// 8-13 PB0-PB5 works
|
||||
// 14-21 PA0-PA7 works
|
||||
// 22-29 PH0-PH7 works
|
||||
// 30-35 PG5-PG0 works
|
||||
// 36-43 PC7-PC0 works
|
||||
// 44-51 PJ7-PJ0 works
|
||||
// 52-59 PL7-PL0 works
|
||||
// 60-67 PD7-PD0 works
|
||||
// A0-A7 PF0-PF7
|
||||
// A8-A15 PK0-PK7
|
||||
|
||||
|
||||
// these arrays map port names (e.g. port B) to the
|
||||
// appropriate addresses for various functions (e.g. reading
|
||||
// and writing)
|
||||
const uint16_t PROGMEM port_to_mode_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & DDRB,
|
||||
(uint16_t) & DDRC,
|
||||
(uint16_t) & DDRD,
|
||||
};
|
||||
|
||||
const uint16_t PROGMEM port_to_output_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & PORTB,
|
||||
(uint16_t) & PORTC,
|
||||
(uint16_t) & PORTD,
|
||||
};
|
||||
|
||||
const uint16_t PROGMEM port_to_input_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & PINB,
|
||||
(uint16_t) & PINC,
|
||||
(uint16_t) & PIND,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
|
||||
PD, /* 0 */
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PB, /* 8 */
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PC, /* 14 */
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
|
||||
_BV(0), /* 0, port D */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(6),
|
||||
_BV(7),
|
||||
_BV(0), /* 8, port B */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(0), /* 14, port C */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
|
||||
NOT_ON_TIMER, /* 0 - port D */
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
// on the ATmega168, digital pin 3 has hardware pwm
|
||||
#if defined(__AVR_ATmega8__)
|
||||
NOT_ON_TIMER,
|
||||
#else
|
||||
TIMER2B,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
// on the ATmega168, digital pins 5 and 6 have hardware pwm
|
||||
#if defined(__AVR_ATmega8__)
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
#else
|
||||
TIMER0B,
|
||||
TIMER0A,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER, /* 8 - port B */
|
||||
TIMER1A,
|
||||
TIMER1B,
|
||||
#if defined(__AVR_ATmega8__)
|
||||
TIMER2,
|
||||
#else
|
||||
TIMER2A,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER, /* 14 - port C */
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*
|
||||
pins_arduino.h - Pin definition functions for Arduino
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2007 David A. Mellis
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define NUM_DIGITAL_PINS 20
|
||||
#define NUM_ANALOG_INPUTS 6
|
||||
#define analogInputToDigitalPin(p) ((p < 6) ? (p) + 14 : -1)
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
#define digitalPinHasPWM(p) ((p) == 9 || (p) == 10 || (p) == 11)
|
||||
#else
|
||||
#define digitalPinHasPWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11)
|
||||
#endif
|
||||
|
||||
static const uint8_t SS = 10;
|
||||
static const uint8_t MOSI = 11;
|
||||
static const uint8_t MISO = 12;
|
||||
static const uint8_t SCK = 13;
|
||||
|
||||
static const uint8_t SDA = 18;
|
||||
static const uint8_t SCL = 19;
|
||||
static const uint8_t LED_BUILTIN = 13;
|
||||
|
||||
static const uint8_t A0 = 14;
|
||||
static const uint8_t A1 = 15;
|
||||
static const uint8_t A2 = 16;
|
||||
static const uint8_t A3 = 17;
|
||||
static const uint8_t A4 = 18;
|
||||
static const uint8_t A5 = 19;
|
||||
static const uint8_t A6 = 20;
|
||||
static const uint8_t A7 = 21;
|
||||
|
||||
#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0))
|
||||
#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1))
|
||||
#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0))))
|
||||
#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14)))
|
||||
|
||||
#ifdef ARDUINO_MAIN
|
||||
|
||||
// On the Arduino board, digital pins are also used
|
||||
// for the analog output (software PWM). Analog input
|
||||
// pins are a separate set.
|
||||
|
||||
// ATMEL ATMEGA8 & 168 / ARDUINO
|
||||
//
|
||||
// +-\/-+
|
||||
// PC6 1| |28 PC5 (AI 5)
|
||||
// (D 0) PD0 2| |27 PC4 (AI 4)
|
||||
// (D 1) PD1 3| |26 PC3 (AI 3)
|
||||
// (D 2) PD2 4| |25 PC2 (AI 2)
|
||||
// PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
|
||||
// (D 4) PD4 6| |23 PC0 (AI 0)
|
||||
// VCC 7| |22 GND
|
||||
// GND 8| |21 AREF
|
||||
// PB6 9| |20 AVCC
|
||||
// PB7 10| |19 PB5 (D 13)
|
||||
// PWM+ (D 5) PD5 11| |18 PB4 (D 12)
|
||||
// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
|
||||
// (D 7) PD7 13| |16 PB2 (D 10) PWM
|
||||
// (D 8) PB0 14| |15 PB1 (D 9) PWM
|
||||
// +----+
|
||||
//
|
||||
// (PWM+ indicates the additional PWM pins on the ATmega168.)
|
||||
|
||||
// ATMEL ATMEGA1280 / ARDUINO
|
||||
//
|
||||
// 0-7 PE0-PE7 works
|
||||
// 8-13 PB0-PB5 works
|
||||
// 14-21 PA0-PA7 works
|
||||
// 22-29 PH0-PH7 works
|
||||
// 30-35 PG5-PG0 works
|
||||
// 36-43 PC7-PC0 works
|
||||
// 44-51 PJ7-PJ0 works
|
||||
// 52-59 PL7-PL0 works
|
||||
// 60-67 PD7-PD0 works
|
||||
// A0-A7 PF0-PF7
|
||||
// A8-A15 PK0-PK7
|
||||
|
||||
|
||||
// these arrays map port names (e.g. port B) to the
|
||||
// appropriate addresses for various functions (e.g. reading
|
||||
// and writing)
|
||||
const uint16_t PROGMEM port_to_mode_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & DDRB,
|
||||
(uint16_t) & DDRC,
|
||||
(uint16_t) & DDRD,
|
||||
};
|
||||
|
||||
const uint16_t PROGMEM port_to_output_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & PORTB,
|
||||
(uint16_t) & PORTC,
|
||||
(uint16_t) & PORTD,
|
||||
};
|
||||
|
||||
const uint16_t PROGMEM port_to_input_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & PINB,
|
||||
(uint16_t) & PINC,
|
||||
(uint16_t) & PIND,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
|
||||
PD, /* 0 */
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PB, /* 8 */
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PC, /* 14 */
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
|
||||
_BV(0), /* 0, port D */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(6),
|
||||
_BV(7),
|
||||
_BV(0), /* 8, port B */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(0), /* 14, port C */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
|
||||
NOT_ON_TIMER, /* 0 - port D */
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
// on the ATmega168, digital pin 3 has hardware pwm
|
||||
#if defined(__AVR_ATmega8__)
|
||||
NOT_ON_TIMER,
|
||||
#else
|
||||
TIMER2B,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
// on the ATmega168, digital pins 5 and 6 have hardware pwm
|
||||
#if defined(__AVR_ATmega8__)
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
#else
|
||||
TIMER0B,
|
||||
TIMER0A,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER, /* 8 - port B */
|
||||
TIMER1A,
|
||||
TIMER1B,
|
||||
#if defined(__AVR_ATmega8__)
|
||||
TIMER2,
|
||||
#else
|
||||
TIMER2A,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER, /* 14 - port C */
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+70
-70
@@ -1,70 +1,70 @@
|
||||
/*
|
||||
wiring_private.h - Internal header file.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef WiringPrivate_h
|
||||
#define WiringPrivate_h
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
|
||||
#define EXTERNAL_INT_0 0
|
||||
#define EXTERNAL_INT_1 1
|
||||
#define EXTERNAL_INT_2 2
|
||||
#define EXTERNAL_INT_3 3
|
||||
#define EXTERNAL_INT_4 4
|
||||
#define EXTERNAL_INT_5 5
|
||||
#define EXTERNAL_INT_6 6
|
||||
#define EXTERNAL_INT_7 7
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 8
|
||||
#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 3
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 4
|
||||
#else
|
||||
#define EXTERNAL_NUM_INTERRUPTS 2
|
||||
#endif
|
||||
|
||||
typedef void (*voidFuncPtr) (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
wiring_private.h - Internal header file.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef WiringPrivate_h
|
||||
#define WiringPrivate_h
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
|
||||
#define EXTERNAL_INT_0 0
|
||||
#define EXTERNAL_INT_1 1
|
||||
#define EXTERNAL_INT_2 2
|
||||
#define EXTERNAL_INT_3 3
|
||||
#define EXTERNAL_INT_4 4
|
||||
#define EXTERNAL_INT_5 5
|
||||
#define EXTERNAL_INT_6 6
|
||||
#define EXTERNAL_INT_7 7
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 8
|
||||
#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 3
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 4
|
||||
#else
|
||||
#define EXTERNAL_NUM_INTERRUPTS 2
|
||||
#endif
|
||||
|
||||
typedef void (*voidFuncPtr) (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "whois.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
bool Send_I_Am_Flag = true;
|
||||
|
||||
void sendIamUnicast(uint8_t * buffer,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* encode the data */
|
||||
int npdu_len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
/* The destination will be the same as the src, so copy it over. */
|
||||
memcpy(&dest, src, sizeof(BACNET_ADDRESS));
|
||||
/* dest->net = 0; - no, must direct back to src->net to meet BTL tests */
|
||||
|
||||
datalink_get_my_address(&my_address);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
npdu_len = npdu_encode_pdu(&buffer[0], &dest, &my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
apdu_len =
|
||||
iam_encode_apdu(&buffer[npdu_len], Device_Object_Instance_Number(),
|
||||
MAX_APDU, SEGMENTATION_NONE, Device_Vendor_Identifier());
|
||||
/* send data */
|
||||
pdu_len = npdu_len + apdu_len;
|
||||
int bytes = datalink_send_pdu(&dest, &npdu_data, &buffer[0], pdu_len);
|
||||
}
|
||||
|
||||
void handler_who_is(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
int32_t low_limit = 0;
|
||||
int32_t high_limit = 0;
|
||||
int32_t target_device;
|
||||
|
||||
len =
|
||||
whois_decode_service_request(service_request, service_len, &low_limit,
|
||||
&high_limit);
|
||||
if (len == 0) {
|
||||
sendIamUnicast(&Handler_Transmit_Buffer[0], src);
|
||||
} else if (len != -1) {
|
||||
/* is my device id within the limits? */
|
||||
target_device = Device_Object_Instance_Number();
|
||||
if (((target_device >= low_limit) && (target_device <= high_limit)) {
|
||||
sendIamUnicast(&Handler_Transmit_Buffer[0], src);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "whois.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
bool Send_I_Am_Flag = true;
|
||||
|
||||
void sendIamUnicast(uint8_t * buffer,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* encode the data */
|
||||
int npdu_len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
/* The destination will be the same as the src, so copy it over. */
|
||||
memcpy(&dest, src, sizeof(BACNET_ADDRESS));
|
||||
/* dest->net = 0; - no, must direct back to src->net to meet BTL tests */
|
||||
|
||||
datalink_get_my_address(&my_address);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
npdu_len = npdu_encode_pdu(&buffer[0], &dest, &my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
apdu_len =
|
||||
iam_encode_apdu(&buffer[npdu_len], Device_Object_Instance_Number(),
|
||||
MAX_APDU, SEGMENTATION_NONE, Device_Vendor_Identifier());
|
||||
/* send data */
|
||||
pdu_len = npdu_len + apdu_len;
|
||||
int bytes = datalink_send_pdu(&dest, &npdu_data, &buffer[0], pdu_len);
|
||||
}
|
||||
|
||||
void handler_who_is(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
int32_t low_limit = 0;
|
||||
int32_t high_limit = 0;
|
||||
int32_t target_device;
|
||||
|
||||
len =
|
||||
whois_decode_service_request(service_request, service_len, &low_limit,
|
||||
&high_limit);
|
||||
if (len == 0) {
|
||||
sendIamUnicast(&Handler_Transmit_Buffer[0], src);
|
||||
} else if (len != -1) {
|
||||
/* is my device id within the limits? */
|
||||
target_device = Device_Object_Instance_Number();
|
||||
if (((target_device >= low_limit) && (target_device <= high_limit)) {
|
||||
sendIamUnicast(&Handler_Transmit_Buffer[0], src);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,135 +1,135 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "wp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "bv.h"
|
||||
|
||||
/* too big to reside on stack frame for PIC */
|
||||
static BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
|
||||
void handler_write_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len =
|
||||
npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address,
|
||||
&npdu_data);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
} else if (service_data->segmented_message) {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
} else {
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "wp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "bv.h"
|
||||
|
||||
/* too big to reside on stack frame for PIC */
|
||||
static BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
|
||||
void handler_write_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len =
|
||||
npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address,
|
||||
&npdu_data);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
} else if (service_data->segmented_message) {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
} else {
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet/IP for Wiznet on Arduino-Uno
|
||||
*
|
||||
* This port is for BACnet/ip and uses part of the Arduino Ethernet
|
||||
* library so it needs the stock Arduino Etherenet Shield
|
||||
* (the one with the W5100 chip). The port was done by writting a C
|
||||
* wrapper around the c++ Ethernet library and adapting the
|
||||
* existing port for Atmega168 (mainly functions bip.c and bip-init.c)
|
||||
* to use the wrapper functions. The port also needs Arduino core and
|
||||
* Ethernet libraries to compile.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "datalink.h"
|
||||
#include "npdu.h"
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "uart.h"
|
||||
#include "w5100Wrapper.h"
|
||||
#include "Arduino.h"
|
||||
#include <avr/io.h>
|
||||
#define BAUD 9600
|
||||
#include <util/setbaud.h>
|
||||
|
||||
/* From the WhoIs hander - performed by the DLMSTP module */
|
||||
extern bool Send_I_Am_Flag;
|
||||
/* local version override */
|
||||
const char *BACnet_Version = "1.0";
|
||||
static uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] =
|
||||
{ 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
uint8_t ipAddress[] = { 192, 168, 0, 185 };
|
||||
uint8_t gateway[] = { 192, 168, 0, 1 };
|
||||
uint8_t netmask[] = { 255, 255, 255, 0 };
|
||||
|
||||
FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
||||
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
|
||||
FILE uart_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
|
||||
|
||||
/* For porting to IAR, see:
|
||||
http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/
|
||||
|
||||
/* dummy function - so we can use default demo handlers */
|
||||
bool dcc_communication_enabled(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
//INIT W5100
|
||||
init_func(CW5100Class_new());
|
||||
setMACAddress_func(CW5100Class_new(), Ethernet_MAC_Address);
|
||||
setIPAddress_func(CW5100Class_new(), ipAddress);
|
||||
setGatewayIp_func(CW5100Class_new(), gateway);
|
||||
setSubnetMask_func(CW5100Class_new(), netmask);
|
||||
|
||||
uart_init();
|
||||
stdout = &uart_output;
|
||||
stdin = &uart_input;
|
||||
stderr = &uart_output;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Starting BACNET application..\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static uint8_t PDUBuffer[MAX_MPDU];
|
||||
int main(void)
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
BACNET_ADDRESS src; /* source address */
|
||||
|
||||
init();
|
||||
|
||||
setup();
|
||||
|
||||
datalink_init(NULL);
|
||||
for (;;) {
|
||||
|
||||
/* other tasks */
|
||||
/* BACnet handling */
|
||||
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
|
||||
if (pdu_len) {
|
||||
npdu_handler(&src, &PDUBuffer[0], pdu_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet/IP for Wiznet on Arduino-Uno
|
||||
*
|
||||
* This port is for BACnet/ip and uses part of the Arduino Ethernet
|
||||
* library so it needs the stock Arduino Etherenet Shield
|
||||
* (the one with the W5100 chip). The port was done by writting a C
|
||||
* wrapper around the c++ Ethernet library and adapting the
|
||||
* existing port for Atmega168 (mainly functions bip.c and bip-init.c)
|
||||
* to use the wrapper functions. The port also needs Arduino core and
|
||||
* Ethernet libraries to compile.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "datalink.h"
|
||||
#include "npdu.h"
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "uart.h"
|
||||
#include "w5100Wrapper.h"
|
||||
#include "Arduino.h"
|
||||
#include <avr/io.h>
|
||||
#define BAUD 9600
|
||||
#include <util/setbaud.h>
|
||||
|
||||
/* From the WhoIs hander - performed by the DLMSTP module */
|
||||
extern bool Send_I_Am_Flag;
|
||||
/* local version override */
|
||||
const char *BACnet_Version = "1.0";
|
||||
static uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] =
|
||||
{ 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
uint8_t ipAddress[] = { 192, 168, 0, 185 };
|
||||
uint8_t gateway[] = { 192, 168, 0, 1 };
|
||||
uint8_t netmask[] = { 255, 255, 255, 0 };
|
||||
|
||||
FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
||||
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
|
||||
FILE uart_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
|
||||
|
||||
/* For porting to IAR, see:
|
||||
http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/
|
||||
|
||||
/* dummy function - so we can use default demo handlers */
|
||||
bool dcc_communication_enabled(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
//INIT W5100
|
||||
init_func(CW5100Class_new());
|
||||
setMACAddress_func(CW5100Class_new(), Ethernet_MAC_Address);
|
||||
setIPAddress_func(CW5100Class_new(), ipAddress);
|
||||
setGatewayIp_func(CW5100Class_new(), gateway);
|
||||
setSubnetMask_func(CW5100Class_new(), netmask);
|
||||
|
||||
uart_init();
|
||||
stdout = &uart_output;
|
||||
stdin = &uart_input;
|
||||
stderr = &uart_output;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Starting BACNET application..\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static uint8_t PDUBuffer[MAX_MPDU];
|
||||
int main(void)
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
BACNET_ADDRESS src; /* source address */
|
||||
|
||||
init();
|
||||
|
||||
setup();
|
||||
|
||||
datalink_init(NULL);
|
||||
for (;;) {
|
||||
|
||||
/* other tasks */
|
||||
/* BACnet handling */
|
||||
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
|
||||
if (pdu_len) {
|
||||
npdu_handler(&src, &PDUBuffer[0], pdu_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* typedef char _Bool; */
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* typedef char _Bool; */
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/* Defines the standard integer types that are used in code */
|
||||
|
||||
#ifndef STDINT_H
|
||||
#define STDINT_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t; /* 1 byte 0 to 255 */
|
||||
typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
/* Defines the standard integer types that are used in code */
|
||||
|
||||
#ifndef STDINT_H
|
||||
#define STDINT_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t; /* 1 byte 0 to 255 */
|
||||
typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef TXBUF_H
|
||||
#define TXBUF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "datalink.h"
|
||||
|
||||
extern uint8_t Handler_Transmit_Buffer[MAX_PDU];
|
||||
|
||||
#endif
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef TXBUF_H
|
||||
#define TXBUF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "datalink.h"
|
||||
|
||||
extern uint8_t Handler_Transmit_Buffer[MAX_PDU];
|
||||
|
||||
#endif
|
||||
|
||||
+2001
-2001
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
|
||||
<workspace>
|
||||
<project>
|
||||
<path>$WS_DIR$\bacnet.ewp</path>
|
||||
</project>
|
||||
<batchBuild/>
|
||||
</workspace>
|
||||
|
||||
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
|
||||
<workspace>
|
||||
<project>
|
||||
<path>$WS_DIR$\bacnet.ewp</path>
|
||||
</project>
|
||||
<batchBuild/>
|
||||
</workspace>
|
||||
|
||||
|
||||
|
||||
@@ -1,108 +1,108 @@
|
||||
#
|
||||
# There exist several targets which are by default empty and which can be
|
||||
# used for execution of your targets. These targets are usually executed
|
||||
# before and after some main targets. They are:
|
||||
#
|
||||
# .build-pre: called before 'build' target
|
||||
# .build-post: called after 'build' target
|
||||
# .clean-pre: called before 'clean' target
|
||||
# .clean-post: called after 'clean' target
|
||||
# .clobber-pre: called before 'clobber' target
|
||||
# .clobber-post: called after 'clobber' target
|
||||
# .all-pre: called before 'all' target
|
||||
# .all-post: called after 'all' target
|
||||
# .help-pre: called before 'help' target
|
||||
# .help-post: called after 'help' target
|
||||
#
|
||||
# Targets beginning with '.' are not intended to be called on their own.
|
||||
#
|
||||
# Main targets can be executed directly, and they are:
|
||||
#
|
||||
# build build a specific configuration
|
||||
# clean remove built files from a configuration
|
||||
# clobber remove all built files
|
||||
# all build all configurations
|
||||
# help print help mesage
|
||||
#
|
||||
# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
|
||||
# .help-impl are implemented in nbproject/makefile-impl.mk.
|
||||
#
|
||||
# Available make variables:
|
||||
#
|
||||
# CND_BASEDIR base directory for relative paths
|
||||
# CND_DISTDIR default top distribution directory (build artifacts)
|
||||
# CND_BUILDDIR default top build directory (object files, ...)
|
||||
# CONF name of current configuration
|
||||
# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
|
||||
# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
|
||||
# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
|
||||
# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
|
||||
# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
|
||||
# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
|
||||
#
|
||||
# NOCDDL
|
||||
|
||||
|
||||
# Environment
|
||||
MKDIR=mkdir
|
||||
CP=cp
|
||||
CCADMIN=CCadmin
|
||||
RANLIB=ranlib
|
||||
|
||||
|
||||
# build
|
||||
build: .build-post
|
||||
|
||||
.build-pre:
|
||||
# Add your pre 'build' code here...
|
||||
|
||||
.build-post: .build-impl
|
||||
# Add your post 'build' code here...
|
||||
|
||||
|
||||
# clean
|
||||
clean: .clean-post
|
||||
|
||||
.clean-pre:
|
||||
# Add your pre 'clean' code here...
|
||||
|
||||
.clean-post: .clean-impl
|
||||
# Add your post 'clean' code here...
|
||||
|
||||
|
||||
# clobber
|
||||
clobber: .clobber-post
|
||||
|
||||
.clobber-pre:
|
||||
# Add your pre 'clobber' code here...
|
||||
|
||||
.clobber-post: .clobber-impl
|
||||
# Add your post 'clobber' code here...
|
||||
|
||||
|
||||
# all
|
||||
all: .all-post
|
||||
|
||||
.all-pre:
|
||||
# Add your pre 'all' code here...
|
||||
|
||||
.all-post: .all-impl
|
||||
# Add your post 'all' code here...
|
||||
|
||||
|
||||
# help
|
||||
help: .help-post
|
||||
|
||||
.help-pre:
|
||||
# Add your pre 'help' code here...
|
||||
|
||||
.help-post: .help-impl
|
||||
# Add your post 'help' code here...
|
||||
|
||||
|
||||
|
||||
# include project implementation makefile
|
||||
include nbproject/Makefile-impl.mk
|
||||
|
||||
# include project make variables
|
||||
include nbproject/Makefile-variables.mk
|
||||
#
|
||||
# There exist several targets which are by default empty and which can be
|
||||
# used for execution of your targets. These targets are usually executed
|
||||
# before and after some main targets. They are:
|
||||
#
|
||||
# .build-pre: called before 'build' target
|
||||
# .build-post: called after 'build' target
|
||||
# .clean-pre: called before 'clean' target
|
||||
# .clean-post: called after 'clean' target
|
||||
# .clobber-pre: called before 'clobber' target
|
||||
# .clobber-post: called after 'clobber' target
|
||||
# .all-pre: called before 'all' target
|
||||
# .all-post: called after 'all' target
|
||||
# .help-pre: called before 'help' target
|
||||
# .help-post: called after 'help' target
|
||||
#
|
||||
# Targets beginning with '.' are not intended to be called on their own.
|
||||
#
|
||||
# Main targets can be executed directly, and they are:
|
||||
#
|
||||
# build build a specific configuration
|
||||
# clean remove built files from a configuration
|
||||
# clobber remove all built files
|
||||
# all build all configurations
|
||||
# help print help mesage
|
||||
#
|
||||
# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
|
||||
# .help-impl are implemented in nbproject/makefile-impl.mk.
|
||||
#
|
||||
# Available make variables:
|
||||
#
|
||||
# CND_BASEDIR base directory for relative paths
|
||||
# CND_DISTDIR default top distribution directory (build artifacts)
|
||||
# CND_BUILDDIR default top build directory (object files, ...)
|
||||
# CONF name of current configuration
|
||||
# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
|
||||
# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
|
||||
# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
|
||||
# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
|
||||
# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
|
||||
# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
|
||||
#
|
||||
# NOCDDL
|
||||
|
||||
|
||||
# Environment
|
||||
MKDIR=mkdir
|
||||
CP=cp
|
||||
CCADMIN=CCadmin
|
||||
RANLIB=ranlib
|
||||
|
||||
|
||||
# build
|
||||
build: .build-post
|
||||
|
||||
.build-pre:
|
||||
# Add your pre 'build' code here...
|
||||
|
||||
.build-post: .build-impl
|
||||
# Add your post 'build' code here...
|
||||
|
||||
|
||||
# clean
|
||||
clean: .clean-post
|
||||
|
||||
.clean-pre:
|
||||
# Add your pre 'clean' code here...
|
||||
|
||||
.clean-post: .clean-impl
|
||||
# Add your post 'clean' code here...
|
||||
|
||||
|
||||
# clobber
|
||||
clobber: .clobber-post
|
||||
|
||||
.clobber-pre:
|
||||
# Add your pre 'clobber' code here...
|
||||
|
||||
.clobber-post: .clobber-impl
|
||||
# Add your post 'clobber' code here...
|
||||
|
||||
|
||||
# all
|
||||
all: .all-post
|
||||
|
||||
.all-pre:
|
||||
# Add your pre 'all' code here...
|
||||
|
||||
.all-post: .all-impl
|
||||
# Add your post 'all' code here...
|
||||
|
||||
|
||||
# help
|
||||
help: .help-post
|
||||
|
||||
.help-pre:
|
||||
# Add your pre 'help' code here...
|
||||
|
||||
.help-post: .help-impl
|
||||
# Add your post 'help' code here...
|
||||
|
||||
|
||||
|
||||
# include project implementation makefile
|
||||
include nbproject/Makefile-impl.mk
|
||||
|
||||
# include project make variables
|
||||
include nbproject/Makefile-variables.mk
|
||||
|
||||
@@ -1,164 +1,164 @@
|
||||
###############################################################################
|
||||
# Makefile for BACnet
|
||||
###############################################################################
|
||||
|
||||
## General Flags
|
||||
MCU = pic18
|
||||
PORT = 18f6720
|
||||
TARGET = bacnet
|
||||
## Tools
|
||||
CC = sdcc
|
||||
PACK = packihx
|
||||
|
||||
# Source locations
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_DEMO = ../../demo
|
||||
|
||||
CSRC = main.c \
|
||||
isr.c \
|
||||
rs485.c \
|
||||
dlmstp.c \
|
||||
mstp.c \
|
||||
$(BACNET_CORE)/crc.c
|
||||
|
||||
DEMOSRC = h_rp.c \
|
||||
device.c \
|
||||
ai.c \
|
||||
av.c \
|
||||
bi.c \
|
||||
bv.c \
|
||||
$(BACNET_DEMO)/handler/txbuf.c \
|
||||
$(BACNET_DEMO)/handler/noserv.c \
|
||||
$(BACNET_DEMO)/handler/h_npdu.c \
|
||||
$(BACNET_DEMO)/handler/h_whois.c \
|
||||
h_wp.c
|
||||
|
||||
CORESRC = \
|
||||
$(BACNET_CORE)/apdu.c \
|
||||
$(BACNET_CORE)/npdu.c \
|
||||
$(BACNET_CORE)/bacdcode.c \
|
||||
$(BACNET_CORE)/bacint.c \
|
||||
$(BACNET_CORE)/bacreal.c \
|
||||
$(BACNET_CORE)/bacstr.c \
|
||||
$(BACNET_CORE)/iam.c \
|
||||
$(BACNET_CORE)/rp.c \
|
||||
$(BACNET_CORE)/wp.c \
|
||||
$(BACNET_CORE)/whois.c \
|
||||
$(BACNET_CORE)/bacaddr.c \
|
||||
$(BACNET_CORE)/abort.c \
|
||||
$(BACNET_CORE)/reject.c \
|
||||
$(BACNET_CORE)/bacerror.c \
|
||||
$(BACNET_CORE)/bacapp.c \
|
||||
$(BACNET_CORE)/version.c
|
||||
|
||||
# $(BACNET_CORE)/bacprop.c \
|
||||
# $(BACNET_CORE)/bactext.c \
|
||||
# $(BACNET_CORE)/datetime.c \
|
||||
# $(BACNET_CORE)/indtext.c \
|
||||
# $(BACNET_CORE)/bigend.c \
|
||||
# $(BACNET_CORE)/arf.c \
|
||||
# $(BACNET_CORE)/awf.c \
|
||||
# $(BACNET_CORE)/cov.c \
|
||||
# $(BACNET_CORE)/dcc.c \
|
||||
# $(BACNET_CORE)/iam/iam_client.c \
|
||||
# $(BACNET_CORE)/ihave.c \
|
||||
# $(BACNET_CORE)/rd.c \
|
||||
# $(BACNET_CORE)/rpm.c \
|
||||
# $(BACNET_CORE)/timesync.c \
|
||||
# $(BACNET_CORE)/whohas.c \
|
||||
# $(BACNET_CORE)/filename.c \
|
||||
# $(BACNET_CORE)/tsm.c \
|
||||
# $(BACNET_CORE)/address.c \
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE)
|
||||
|
||||
# Source to Object conversion
|
||||
COBJ = $(CSRC:.c=.o)
|
||||
DEMOOBJ = $(DEMOSRC:.c=.o)
|
||||
COREOBJ = $(CORESRC:.c=.o)
|
||||
|
||||
LIBRARY = lib$(TARGET).a
|
||||
|
||||
## Options common to compile, link and assembly rules
|
||||
COMMON = -m$(MCU) -p$(PORT)
|
||||
OPTIMIZATION = --opt-code-size
|
||||
|
||||
## Compile options common for all C compilation units.
|
||||
BFLAGS = -DBACDL_MSTP
|
||||
BFLAGS += -DMAX_APDU=128
|
||||
BFLAGS += -DBIG_ENDIAN=0
|
||||
BFLAGS += -DMAX_TSM_TRANSACTIONS=0
|
||||
#BFLAGS += -DCRC_USE_TABLE
|
||||
BFLAGS += -DBACAPP_REAL
|
||||
CFLAGS = $(COMMON)
|
||||
# dead code removal
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
CFLAGS += -Wall $(BFLAGS) $(OPTIMIZATION)
|
||||
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d
|
||||
|
||||
## Assembly specific flags
|
||||
ASMFLAGS = $(COMMON)
|
||||
ASMFLAGS += $(CFLAGS)
|
||||
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2
|
||||
|
||||
## Linker flags
|
||||
LDFLAGS = $(COMMON)
|
||||
#dead code removal
|
||||
LDFLAGS += -Wl,--gc-sections,-static
|
||||
LDFLAGS += -Wl,-Map=$(TARGET).map,-L.,-l$(TARGET)
|
||||
#LDFLAGS += -Wl,-Map=$(TARGET).map
|
||||
|
||||
## Intel Hex file production flags
|
||||
HEX_FLASH_FLAGS = -R .eeprom
|
||||
HEX_EEPROM_FLAGS = -j .eeprom
|
||||
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
|
||||
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings
|
||||
|
||||
## Objects that must be built in order to link
|
||||
OBJECTS = $(COBJ) $(DEMOOBJ)
|
||||
#OBJECTS = $(COBJ)
|
||||
|
||||
## Build
|
||||
TARGET_ELF=$(TARGET).elf
|
||||
|
||||
all: $(LIBRARY) $(TARGET_ELF) $(TARGET).hex $(TARGET).eep $(TARGET).lst \
|
||||
size Makefile
|
||||
|
||||
##Link
|
||||
$(TARGET_ELF): $(OBJECTS) $(LIBRARY)
|
||||
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||
|
||||
%.hex: $(TARGET_ELF)
|
||||
$(OBJCOPY) -O ihex $(HEX_FLASH_FLAGS) $< $@
|
||||
|
||||
%.eep: $(TARGET_ELF)
|
||||
-$(OBJCOPY) $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0
|
||||
|
||||
%.lst: $(TARGET_ELF)
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
lib: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(COREOBJ) Makefile
|
||||
$(AR) rcs $@ $(COREOBJ)
|
||||
$(OBJDUMP) --syms $@ > $(LIBRARY:.a=.lst)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@
|
||||
|
||||
size: ${TARGET_ELF}
|
||||
@echo
|
||||
@${SIZE} -C --mcu=${MCU} ${TARGET_ELF}
|
||||
|
||||
## Clean target
|
||||
.PHONY: clean
|
||||
clean:
|
||||
touch Makefile
|
||||
-rm -rf $(OBJECTS) $(TARGET_ELF) dep/*
|
||||
-rm -rf $(LIBRARY) $(COREOBJ) $(LIBRARY:.a=.lst)
|
||||
-rm -rf $(TARGET).hex $(TARGET).eep $(TARGET).lst $(TARGET).map
|
||||
|
||||
## Other dependencies
|
||||
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)
|
||||
###############################################################################
|
||||
# Makefile for BACnet
|
||||
###############################################################################
|
||||
|
||||
## General Flags
|
||||
MCU = pic18
|
||||
PORT = 18f6720
|
||||
TARGET = bacnet
|
||||
## Tools
|
||||
CC = sdcc
|
||||
PACK = packihx
|
||||
|
||||
# Source locations
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_DEMO = ../../demo
|
||||
|
||||
CSRC = main.c \
|
||||
isr.c \
|
||||
rs485.c \
|
||||
dlmstp.c \
|
||||
mstp.c \
|
||||
$(BACNET_CORE)/crc.c
|
||||
|
||||
DEMOSRC = h_rp.c \
|
||||
device.c \
|
||||
ai.c \
|
||||
av.c \
|
||||
bi.c \
|
||||
bv.c \
|
||||
$(BACNET_DEMO)/handler/txbuf.c \
|
||||
$(BACNET_DEMO)/handler/noserv.c \
|
||||
$(BACNET_DEMO)/handler/h_npdu.c \
|
||||
$(BACNET_DEMO)/handler/h_whois.c \
|
||||
h_wp.c
|
||||
|
||||
CORESRC = \
|
||||
$(BACNET_CORE)/apdu.c \
|
||||
$(BACNET_CORE)/npdu.c \
|
||||
$(BACNET_CORE)/bacdcode.c \
|
||||
$(BACNET_CORE)/bacint.c \
|
||||
$(BACNET_CORE)/bacreal.c \
|
||||
$(BACNET_CORE)/bacstr.c \
|
||||
$(BACNET_CORE)/iam.c \
|
||||
$(BACNET_CORE)/rp.c \
|
||||
$(BACNET_CORE)/wp.c \
|
||||
$(BACNET_CORE)/whois.c \
|
||||
$(BACNET_CORE)/bacaddr.c \
|
||||
$(BACNET_CORE)/abort.c \
|
||||
$(BACNET_CORE)/reject.c \
|
||||
$(BACNET_CORE)/bacerror.c \
|
||||
$(BACNET_CORE)/bacapp.c \
|
||||
$(BACNET_CORE)/version.c
|
||||
|
||||
# $(BACNET_CORE)/bacprop.c \
|
||||
# $(BACNET_CORE)/bactext.c \
|
||||
# $(BACNET_CORE)/datetime.c \
|
||||
# $(BACNET_CORE)/indtext.c \
|
||||
# $(BACNET_CORE)/bigend.c \
|
||||
# $(BACNET_CORE)/arf.c \
|
||||
# $(BACNET_CORE)/awf.c \
|
||||
# $(BACNET_CORE)/cov.c \
|
||||
# $(BACNET_CORE)/dcc.c \
|
||||
# $(BACNET_CORE)/iam/iam_client.c \
|
||||
# $(BACNET_CORE)/ihave.c \
|
||||
# $(BACNET_CORE)/rd.c \
|
||||
# $(BACNET_CORE)/rpm.c \
|
||||
# $(BACNET_CORE)/timesync.c \
|
||||
# $(BACNET_CORE)/whohas.c \
|
||||
# $(BACNET_CORE)/filename.c \
|
||||
# $(BACNET_CORE)/tsm.c \
|
||||
# $(BACNET_CORE)/address.c \
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE)
|
||||
|
||||
# Source to Object conversion
|
||||
COBJ = $(CSRC:.c=.o)
|
||||
DEMOOBJ = $(DEMOSRC:.c=.o)
|
||||
COREOBJ = $(CORESRC:.c=.o)
|
||||
|
||||
LIBRARY = lib$(TARGET).a
|
||||
|
||||
## Options common to compile, link and assembly rules
|
||||
COMMON = -m$(MCU) -p$(PORT)
|
||||
OPTIMIZATION = --opt-code-size
|
||||
|
||||
## Compile options common for all C compilation units.
|
||||
BFLAGS = -DBACDL_MSTP
|
||||
BFLAGS += -DMAX_APDU=128
|
||||
BFLAGS += -DBIG_ENDIAN=0
|
||||
BFLAGS += -DMAX_TSM_TRANSACTIONS=0
|
||||
#BFLAGS += -DCRC_USE_TABLE
|
||||
BFLAGS += -DBACAPP_REAL
|
||||
CFLAGS = $(COMMON)
|
||||
# dead code removal
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
CFLAGS += -Wall $(BFLAGS) $(OPTIMIZATION)
|
||||
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d
|
||||
|
||||
## Assembly specific flags
|
||||
ASMFLAGS = $(COMMON)
|
||||
ASMFLAGS += $(CFLAGS)
|
||||
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2
|
||||
|
||||
## Linker flags
|
||||
LDFLAGS = $(COMMON)
|
||||
#dead code removal
|
||||
LDFLAGS += -Wl,--gc-sections,-static
|
||||
LDFLAGS += -Wl,-Map=$(TARGET).map,-L.,-l$(TARGET)
|
||||
#LDFLAGS += -Wl,-Map=$(TARGET).map
|
||||
|
||||
## Intel Hex file production flags
|
||||
HEX_FLASH_FLAGS = -R .eeprom
|
||||
HEX_EEPROM_FLAGS = -j .eeprom
|
||||
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
|
||||
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings
|
||||
|
||||
## Objects that must be built in order to link
|
||||
OBJECTS = $(COBJ) $(DEMOOBJ)
|
||||
#OBJECTS = $(COBJ)
|
||||
|
||||
## Build
|
||||
TARGET_ELF=$(TARGET).elf
|
||||
|
||||
all: $(LIBRARY) $(TARGET_ELF) $(TARGET).hex $(TARGET).eep $(TARGET).lst \
|
||||
size Makefile
|
||||
|
||||
##Link
|
||||
$(TARGET_ELF): $(OBJECTS) $(LIBRARY)
|
||||
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||
|
||||
%.hex: $(TARGET_ELF)
|
||||
$(OBJCOPY) -O ihex $(HEX_FLASH_FLAGS) $< $@
|
||||
|
||||
%.eep: $(TARGET_ELF)
|
||||
-$(OBJCOPY) $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0
|
||||
|
||||
%.lst: $(TARGET_ELF)
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
lib: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(COREOBJ) Makefile
|
||||
$(AR) rcs $@ $(COREOBJ)
|
||||
$(OBJDUMP) --syms $@ > $(LIBRARY:.a=.lst)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@
|
||||
|
||||
size: ${TARGET_ELF}
|
||||
@echo
|
||||
@${SIZE} -C --mcu=${MCU} ${TARGET_ELF}
|
||||
|
||||
## Clean target
|
||||
.PHONY: clean
|
||||
clean:
|
||||
touch Makefile
|
||||
-rm -rf $(OBJECTS) $(TARGET_ELF) dep/*
|
||||
-rm -rf $(LIBRARY) $(COREOBJ) $(LIBRARY:.a=.lst)
|
||||
-rm -rf $(TARGET).hex $(TARGET).eep $(TARGET).lst $(TARGET).map
|
||||
|
||||
## Other dependencies
|
||||
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)
|
||||
|
||||
+174
-174
@@ -1,174 +1,174 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 Input Objects customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "ai.h"
|
||||
|
||||
/* Analog Input = Photocell */
|
||||
#define MAX_ANALOG_INPUTS 2
|
||||
|
||||
static uint8_t Present_Value[MAX_ANALOG_INPUTS];
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Analog_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ANALOG_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Analog_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
sprintf(text_string, "AI-%lu", (unsigned long) object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float Analog_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
value = Present_Value[object_instance];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void Analog_Input_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
Present_Value[object_instance] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_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:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(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_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0],
|
||||
Analog_Input_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 Input Objects customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "ai.h"
|
||||
|
||||
/* Analog Input = Photocell */
|
||||
#define MAX_ANALOG_INPUTS 2
|
||||
|
||||
static uint8_t Present_Value[MAX_ANALOG_INPUTS];
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Analog_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ANALOG_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Analog_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
sprintf(text_string, "AI-%lu", (unsigned long) object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float Analog_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = 0.0;
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
value = Present_Value[object_instance];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void Analog_Input_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
Present_Value[object_instance] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_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:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(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_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0],
|
||||
Analog_Input_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
@@ -1,232 +1,232 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "dcc.h"
|
||||
#include "handlers.h"
|
||||
/* me */
|
||||
#include "apdu.h"
|
||||
|
||||
uint16_t apdu_timeout(
|
||||
void)
|
||||
{
|
||||
return 3000;
|
||||
}
|
||||
|
||||
uint8_t apdu_retries(
|
||||
void)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool apdu_service_supported(
|
||||
BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
switch (service_supported) {
|
||||
case SERVICE_SUPPORTED_READ_PROPERTY:
|
||||
case SERVICE_SUPPORTED_WHO_IS:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
case SERVICE_SUPPORTED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.
|
||||
When the initiation of communications is disabled,
|
||||
all APDUs shall be processed and responses returned as
|
||||
required... */
|
||||
static bool apdu_confirmed_dcc_disabled(
|
||||
uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dcc_communication_disabled()) {
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
break;
|
||||
default:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
/* If the request is valid and the 'Enable/Disable' parameter is
|
||||
DISABLE_INITIATION, the responding BACnet-user shall
|
||||
discontinue the initiation of messages except for I-Am
|
||||
requests issued in accordance with the Who-Is service procedure.*/
|
||||
static bool apdu_unconfirmed_dcc_disabled(
|
||||
uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dcc_communication_disabled()) {
|
||||
/* there are no Unconfirmed messages that
|
||||
can be processed in this state */
|
||||
status = true;
|
||||
} else if (dcc_communication_initiation_disabled()) {
|
||||
/* WhoIs will be processed and I-Am initiated as response. */
|
||||
switch (service_choice) {
|
||||
case SERVICE_UNCONFIRMED_WHO_IS:
|
||||
break;
|
||||
default:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (apdu_confirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
break;
|
||||
}
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request, service_request_len,
|
||||
src, &service_data);
|
||||
} else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else if (service_choice ==
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE) {
|
||||
handler_reinitialize_device(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else if (service_choice ==
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) {
|
||||
handler_device_communication_control(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (apdu_unconfirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.
|
||||
If communications have been initiation disabled, then
|
||||
WhoIs may be processed. */
|
||||
break;
|
||||
}
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "dcc.h"
|
||||
#include "handlers.h"
|
||||
/* me */
|
||||
#include "apdu.h"
|
||||
|
||||
uint16_t apdu_timeout(
|
||||
void)
|
||||
{
|
||||
return 3000;
|
||||
}
|
||||
|
||||
uint8_t apdu_retries(
|
||||
void)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool apdu_service_supported(
|
||||
BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
switch (service_supported) {
|
||||
case SERVICE_SUPPORTED_READ_PROPERTY:
|
||||
case SERVICE_SUPPORTED_WHO_IS:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
case SERVICE_SUPPORTED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.
|
||||
When the initiation of communications is disabled,
|
||||
all APDUs shall be processed and responses returned as
|
||||
required... */
|
||||
static bool apdu_confirmed_dcc_disabled(
|
||||
uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dcc_communication_disabled()) {
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
break;
|
||||
default:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
/* If the request is valid and the 'Enable/Disable' parameter is
|
||||
DISABLE_INITIATION, the responding BACnet-user shall
|
||||
discontinue the initiation of messages except for I-Am
|
||||
requests issued in accordance with the Who-Is service procedure.*/
|
||||
static bool apdu_unconfirmed_dcc_disabled(
|
||||
uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dcc_communication_disabled()) {
|
||||
/* there are no Unconfirmed messages that
|
||||
can be processed in this state */
|
||||
status = true;
|
||||
} else if (dcc_communication_initiation_disabled()) {
|
||||
/* WhoIs will be processed and I-Am initiated as response. */
|
||||
switch (service_choice) {
|
||||
case SERVICE_UNCONFIRMED_WHO_IS:
|
||||
break;
|
||||
default:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (apdu_confirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
break;
|
||||
}
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request, service_request_len,
|
||||
src, &service_data);
|
||||
} else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else if (service_choice ==
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE) {
|
||||
handler_reinitialize_device(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else if (service_choice ==
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) {
|
||||
handler_device_communication_control(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (apdu_unconfirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.
|
||||
If communications have been initiation disabled, then
|
||||
WhoIs may be processed. */
|
||||
break;
|
||||
}
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
+413
-413
@@ -1,413 +1,413 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "av.h"
|
||||
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
|
||||
/* we choose to have a NULL level in our system represented by */
|
||||
/* a particular value. When the priorities are not in use, they */
|
||||
/* will be relinquished (i.e. set to the NULL level). */
|
||||
#define ANALOG_LEVEL_NULL 255
|
||||
/* When all the priorities are level null, the present value returns */
|
||||
/* the Relinquish Default value */
|
||||
#define ANALOG_RELINQUISH_DEFAULT 0
|
||||
/* Here is our Present_Value. They are supposed to be Real, but */
|
||||
/* we don't have that kind of memory, so we will use a single byte */
|
||||
/* and load a Real for returning the value when asked. */
|
||||
static uint8_t Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* we need to have our arrays initialized before answering any calls */
|
||||
static bool Analog_Value_Initialized = false;
|
||||
|
||||
void Analog_Value_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Analog_Value_Initialized) {
|
||||
Analog_Value_Initialized = true;
|
||||
|
||||
/* initialize all the analog output priority arrays to NULL */
|
||||
for (i = 0; i < MAX_ANALOG_VALUES; i++) {
|
||||
Present_Value[i] = ANALOG_LEVEL_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(
|
||||
void)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return MAX_ANALOG_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ANALOG_VALUES;
|
||||
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
float Analog_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = ANALOG_RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
Analog_Value_Init();
|
||||
index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ANALOG_VALUES) {
|
||||
value = Present_Value[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_VALUES) {
|
||||
sprintf(text_string, "AV-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float real_value = (float) 1.414;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Analog_Value_Init();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(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_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
state = Analog_Value_Out_Of_Service[object_index];
|
||||
#endif
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
#if 0
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
/* Array element zero is the number of elements in the array */
|
||||
if (array_index == 0)
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Present_Value[object_index][array_index - 1] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value =
|
||||
Present_Value[object_index][array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], real_value);
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = ANALOG_RELINQUISH_DEFAULT;
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) &&
|
||||
#if 0
|
||||
(property != PROP_PRIORITY_ARRAY) &&
|
||||
#endif
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
uint8_t level = ANALOG_LEVEL_NULL;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
Analog_Value_Init();
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = 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) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[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) */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_DESCRIPTION:
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "av.h"
|
||||
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
|
||||
/* we choose to have a NULL level in our system represented by */
|
||||
/* a particular value. When the priorities are not in use, they */
|
||||
/* will be relinquished (i.e. set to the NULL level). */
|
||||
#define ANALOG_LEVEL_NULL 255
|
||||
/* When all the priorities are level null, the present value returns */
|
||||
/* the Relinquish Default value */
|
||||
#define ANALOG_RELINQUISH_DEFAULT 0
|
||||
/* Here is our Present_Value. They are supposed to be Real, but */
|
||||
/* we don't have that kind of memory, so we will use a single byte */
|
||||
/* and load a Real for returning the value when asked. */
|
||||
static uint8_t Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* we need to have our arrays initialized before answering any calls */
|
||||
static bool Analog_Value_Initialized = false;
|
||||
|
||||
void Analog_Value_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Analog_Value_Initialized) {
|
||||
Analog_Value_Initialized = true;
|
||||
|
||||
/* initialize all the analog output priority arrays to NULL */
|
||||
for (i = 0; i < MAX_ANALOG_VALUES; i++) {
|
||||
Present_Value[i] = ANALOG_LEVEL_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(
|
||||
void)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return MAX_ANALOG_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ANALOG_VALUES;
|
||||
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
float Analog_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = ANALOG_RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
Analog_Value_Init();
|
||||
index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ANALOG_VALUES) {
|
||||
value = Present_Value[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_VALUES) {
|
||||
sprintf(text_string, "AV-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float real_value = (float) 1.414;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Analog_Value_Init();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(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_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
state = Analog_Value_Out_Of_Service[object_index];
|
||||
#endif
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
#if 0
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
/* Array element zero is the number of elements in the array */
|
||||
if (array_index == 0)
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Present_Value[object_index][array_index - 1] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value =
|
||||
Present_Value[object_index][array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], real_value);
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = ANALOG_RELINQUISH_DEFAULT;
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) &&
|
||||
#if 0
|
||||
(property != PROP_PRIORITY_ARRAY) &&
|
||||
#endif
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
uint8_t level = ANALOG_LEVEL_NULL;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
Analog_Value_Init();
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = 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) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[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) */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_DESCRIPTION:
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
+197
-197
@@ -1,197 +1,197 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bi.h"
|
||||
|
||||
#define MAX_BINARY_INPUTS 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
|
||||
|
||||
static void Binary_Input_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_INPUTS; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_INPUTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances.*/
|
||||
uint32_t Binary_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Binary_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_INPUTS;
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
unsigned index = 0;
|
||||
|
||||
Binary_Input_Initialize();
|
||||
index = Binary_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_BINARY_INPUTS) {
|
||||
value = Present_Value[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
char *Binary_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS) {
|
||||
sprintf(text_string, "BI-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object already exists, and has been bounds checked */
|
||||
int Binary_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Binary_Input_Initialize();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
/* note: object name must be unique in our device */
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Input_Name(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_BINARY_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
value = Binary_Input_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bi.h"
|
||||
|
||||
#define MAX_BINARY_INPUTS 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
|
||||
|
||||
static void Binary_Input_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_INPUTS; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_INPUTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances.*/
|
||||
uint32_t Binary_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Binary_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_INPUTS;
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Input_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
unsigned index = 0;
|
||||
|
||||
Binary_Input_Initialize();
|
||||
index = Binary_Input_Instance_To_Index(object_instance);
|
||||
if (index < MAX_BINARY_INPUTS) {
|
||||
value = Present_Value[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
char *Binary_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS) {
|
||||
sprintf(text_string, "BI-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object already exists, and has been bounds checked */
|
||||
int Binary_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Binary_Input_Initialize();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
/* note: object name must be unique in our device */
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Input_Name(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_BINARY_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
value = Binary_Input_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
+328
-328
@@ -1,328 +1,328 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bv.h"
|
||||
|
||||
#define MAX_BINARY_VALUES 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
static void Binary_Value_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
Binary_Value_Initialize();
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
value = Present_Value[object_instance];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
sprintf(text_string, "BV-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Binary_Value_Initialize();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
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:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Value_Name(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_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
Binary_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
BACNET_BINARY_PV level = BINARY_NULL;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Enumerated >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = 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. */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
#if 0
|
||||
/* NOTE: this Binary Value has no priority array */
|
||||
level = BINARY_NULL;
|
||||
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) */
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#else
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_POLARITY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bv.h"
|
||||
|
||||
#define MAX_BINARY_VALUES 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
static void Binary_Value_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
Binary_Value_Initialize();
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
value = Present_Value[object_instance];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
sprintf(text_string, "BV-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Binary_Value_Initialize();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
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:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Value_Name(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_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
Binary_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
BACNET_BINARY_PV level = BINARY_NULL;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Enumerated >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = 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. */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
#if 0
|
||||
/* NOTE: this Binary Value has no priority array */
|
||||
level = BINARY_NULL;
|
||||
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) */
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#else
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_POLARITY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,319 +1,319 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#if PRINT_ENABLED
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "bacdef.h"
|
||||
#include "mstp.h"
|
||||
#include "dlmstp.h"
|
||||
#include "rs485.h"
|
||||
#include "npdu.h"
|
||||
#include "handlers.h"
|
||||
|
||||
/* Number of MS/TP Packets Rx/Tx */
|
||||
uint16_t MSTP_Packets = 0;
|
||||
|
||||
/* receive buffer */
|
||||
#pragma udata MSTP_RxData
|
||||
static DLMSTP_PACKET Receive_Buffer;
|
||||
/* temp buffer for NPDU insertion */
|
||||
/* local MS/TP port data - shared with RS-485 */
|
||||
#pragma udata MSTP_PortData
|
||||
volatile struct mstp_port_struct_t MSTP_Port;
|
||||
#pragma udata
|
||||
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
|
||||
void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer);
|
||||
}
|
||||
|
||||
void dlmstp_reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Reinit();
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES);
|
||||
dlmstp_set_max_master(DEFAULT_MAX_MASTER);
|
||||
}
|
||||
|
||||
void dlmstp_init(
|
||||
void)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
/* initialize buffer */
|
||||
Receive_Buffer.ready = false;
|
||||
Receive_Buffer.pdu_len = 0;
|
||||
/* initialize hardware */
|
||||
RS485_Initialize();
|
||||
MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0];
|
||||
MSTP_Init(&MSTP_Port);
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
/* nothing to do for static buffers */
|
||||
}
|
||||
|
||||
/* returns number of bytes sent on success, zero on failure */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
int bytes_sent = 0;
|
||||
unsigned npdu_len = 0;
|
||||
uint8_t frame_type = 0;
|
||||
BACNET_ADDRESS src;
|
||||
unsigned i = 0; /* loop counter */
|
||||
|
||||
if (MSTP_Port.TxReady == false) {
|
||||
if (npdu_data->data_expecting_reply)
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
else
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
|
||||
/* load destination MAC address */
|
||||
if (dest && dest->mac_len) {
|
||||
MSTP_Port.TxDestination = dest->mac[0];
|
||||
} else {
|
||||
/* mac_len = 0 is a broadcast address */
|
||||
MSTP_Port.TxDestination = MSTP_BROADCAST_ADDRESS;
|
||||
}
|
||||
dlmstp_get_my_address(&src);
|
||||
if ((MAX_HEADER + pdu_len) > MAX_MPDU) {
|
||||
return -4;
|
||||
}
|
||||
bytes_sent =
|
||||
MSTP_Create_Frame((uint8_t *) & MSTP_Port.TxBuffer[0],
|
||||
sizeof(MSTP_Port.TxBuffer), MSTP_Port.TxFrameType,
|
||||
MSTP_Port.TxDestination, MSTP_Port.This_Station, pdu, pdu_len);
|
||||
MSTP_Port.TxLength = bytes_sent;
|
||||
MSTP_Port.TxReady = true;
|
||||
MSTP_Packets++;
|
||||
}
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
void dlmstp_task(
|
||||
void)
|
||||
{
|
||||
bool bytes_remaining;
|
||||
bool received_frame;
|
||||
|
||||
/* only do receive state machine while we don't have a frame */
|
||||
if ((MSTP_Port.ReceivedValidFrame == false) &&
|
||||
(MSTP_Port.ReceivedInvalidFrame == false)) {
|
||||
do {
|
||||
bytes_remaining = RS485_Check_UART_Data(&MSTP_Port);
|
||||
MSTP_Receive_Frame_FSM(&MSTP_Port);
|
||||
received_frame = MSTP_Port.ReceivedValidFrame ||
|
||||
MSTP_Port.ReceivedInvalidFrame;
|
||||
if (received_frame)
|
||||
break;
|
||||
} while (bytes_remaining);
|
||||
}
|
||||
/* only do master state machine while rx is idle */
|
||||
if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
||||
if (MSTP_Port.This_Station <= DEFAULT_MAX_MASTER) {
|
||||
while (MSTP_Master_Node_FSM(&MSTP_Port)) {
|
||||
/* do nothing while some states fast transition */
|
||||
};
|
||||
}
|
||||
}
|
||||
/* see if there is a packet available, and a place
|
||||
to put the reply (if necessary) and process it */
|
||||
if (Receive_Buffer.ready && !MSTP_Port.TxReady) {
|
||||
if (Receive_Buffer.pdu_len) {
|
||||
MSTP_Packets++;
|
||||
npdu_handler(&Receive_Buffer.address, &Receive_Buffer.pdu[0],
|
||||
Receive_Buffer.pdu_len);
|
||||
}
|
||||
Receive_Buffer.ready = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_fill_bacnet_address(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t mstp_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (mstp_address == MSTP_BROADCAST_ADDRESS) {
|
||||
/* mac_len = 0 if broadcast address */
|
||||
src->mac_len = 0;
|
||||
src->mac[0] = 0;
|
||||
} else {
|
||||
src->mac_len = 1;
|
||||
src->mac[0] = mstp_address;
|
||||
}
|
||||
/* fill with 0's starting with index 1; index 0 filled above */
|
||||
for (i = 1; i < MAX_MAC_LEN; i++) {
|
||||
src->mac[i] = 0;
|
||||
}
|
||||
src->net = 0;
|
||||
src->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
src->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len)
|
||||
{ /* amount of PDU data */
|
||||
/* PDU is already in the Receive_Buffer */
|
||||
dlmstp_fill_bacnet_address(&Receive_Buffer.address, src);
|
||||
Receive_Buffer.pdu_len = pdu_len;
|
||||
Receive_Buffer.ready = true;
|
||||
}
|
||||
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t mac_address)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127) {
|
||||
MSTP_Port.This_Station = mac_address;
|
||||
/* FIXME: implement your data storage */
|
||||
/* I2C_Write_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
mac_address,
|
||||
EEPROM_MSTP_MAC_ADDR); */
|
||||
if (mac_address > MSTP_Port.Nmax_master)
|
||||
dlmstp_set_max_master(mac_address);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_my_address(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.This_Station;
|
||||
}
|
||||
|
||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||
/* maximum number of information frames the node may send before it must */
|
||||
/* pass the token. Max_Info_Frames may have different values on different */
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(
|
||||
uint8_t max_info_frames)
|
||||
{
|
||||
if (max_info_frames >= 1) {
|
||||
MSTP_Port.Nmax_info_frames = max_info_frames;
|
||||
/* FIXME: implement your data storage */
|
||||
/* I2C_Write_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(uint8_t)max_info_frames,
|
||||
EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_info_frames;
|
||||
}
|
||||
|
||||
/* This parameter represents the value of the Max_Master property of the */
|
||||
/* node's Device object. The value of Max_Master specifies the highest */
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master)
|
||||
{
|
||||
if (max_master <= 127) {
|
||||
if (MSTP_Port.This_Station <= max_master) {
|
||||
MSTP_Port.Nmax_master = max_master;
|
||||
/* FIXME: implement your data storage */
|
||||
/* I2C_Write_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
max_master,
|
||||
EEPROM_MSTP_MAX_MASTER_ADDR); */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_max_master(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_master;
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
|
||||
my_address->mac_len = 1;
|
||||
my_address->mac[0] = MSTP_Port.This_Station;
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 1;
|
||||
dest->mac[0] = MSTP_BROADCAST_ADDRESS;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#if PRINT_ENABLED
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "bacdef.h"
|
||||
#include "mstp.h"
|
||||
#include "dlmstp.h"
|
||||
#include "rs485.h"
|
||||
#include "npdu.h"
|
||||
#include "handlers.h"
|
||||
|
||||
/* Number of MS/TP Packets Rx/Tx */
|
||||
uint16_t MSTP_Packets = 0;
|
||||
|
||||
/* receive buffer */
|
||||
#pragma udata MSTP_RxData
|
||||
static DLMSTP_PACKET Receive_Buffer;
|
||||
/* temp buffer for NPDU insertion */
|
||||
/* local MS/TP port data - shared with RS-485 */
|
||||
#pragma udata MSTP_PortData
|
||||
volatile struct mstp_port_struct_t MSTP_Port;
|
||||
#pragma udata
|
||||
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
|
||||
void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer);
|
||||
}
|
||||
|
||||
void dlmstp_reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Reinit();
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES);
|
||||
dlmstp_set_max_master(DEFAULT_MAX_MASTER);
|
||||
}
|
||||
|
||||
void dlmstp_init(
|
||||
void)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
/* initialize buffer */
|
||||
Receive_Buffer.ready = false;
|
||||
Receive_Buffer.pdu_len = 0;
|
||||
/* initialize hardware */
|
||||
RS485_Initialize();
|
||||
MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0];
|
||||
MSTP_Init(&MSTP_Port);
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
/* nothing to do for static buffers */
|
||||
}
|
||||
|
||||
/* returns number of bytes sent on success, zero on failure */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
int bytes_sent = 0;
|
||||
unsigned npdu_len = 0;
|
||||
uint8_t frame_type = 0;
|
||||
BACNET_ADDRESS src;
|
||||
unsigned i = 0; /* loop counter */
|
||||
|
||||
if (MSTP_Port.TxReady == false) {
|
||||
if (npdu_data->data_expecting_reply)
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
else
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
|
||||
/* load destination MAC address */
|
||||
if (dest && dest->mac_len) {
|
||||
MSTP_Port.TxDestination = dest->mac[0];
|
||||
} else {
|
||||
/* mac_len = 0 is a broadcast address */
|
||||
MSTP_Port.TxDestination = MSTP_BROADCAST_ADDRESS;
|
||||
}
|
||||
dlmstp_get_my_address(&src);
|
||||
if ((MAX_HEADER + pdu_len) > MAX_MPDU) {
|
||||
return -4;
|
||||
}
|
||||
bytes_sent =
|
||||
MSTP_Create_Frame((uint8_t *) & MSTP_Port.TxBuffer[0],
|
||||
sizeof(MSTP_Port.TxBuffer), MSTP_Port.TxFrameType,
|
||||
MSTP_Port.TxDestination, MSTP_Port.This_Station, pdu, pdu_len);
|
||||
MSTP_Port.TxLength = bytes_sent;
|
||||
MSTP_Port.TxReady = true;
|
||||
MSTP_Packets++;
|
||||
}
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
void dlmstp_task(
|
||||
void)
|
||||
{
|
||||
bool bytes_remaining;
|
||||
bool received_frame;
|
||||
|
||||
/* only do receive state machine while we don't have a frame */
|
||||
if ((MSTP_Port.ReceivedValidFrame == false) &&
|
||||
(MSTP_Port.ReceivedInvalidFrame == false)) {
|
||||
do {
|
||||
bytes_remaining = RS485_Check_UART_Data(&MSTP_Port);
|
||||
MSTP_Receive_Frame_FSM(&MSTP_Port);
|
||||
received_frame = MSTP_Port.ReceivedValidFrame ||
|
||||
MSTP_Port.ReceivedInvalidFrame;
|
||||
if (received_frame)
|
||||
break;
|
||||
} while (bytes_remaining);
|
||||
}
|
||||
/* only do master state machine while rx is idle */
|
||||
if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
||||
if (MSTP_Port.This_Station <= DEFAULT_MAX_MASTER) {
|
||||
while (MSTP_Master_Node_FSM(&MSTP_Port)) {
|
||||
/* do nothing while some states fast transition */
|
||||
};
|
||||
}
|
||||
}
|
||||
/* see if there is a packet available, and a place
|
||||
to put the reply (if necessary) and process it */
|
||||
if (Receive_Buffer.ready && !MSTP_Port.TxReady) {
|
||||
if (Receive_Buffer.pdu_len) {
|
||||
MSTP_Packets++;
|
||||
npdu_handler(&Receive_Buffer.address, &Receive_Buffer.pdu[0],
|
||||
Receive_Buffer.pdu_len);
|
||||
}
|
||||
Receive_Buffer.ready = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_fill_bacnet_address(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t mstp_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (mstp_address == MSTP_BROADCAST_ADDRESS) {
|
||||
/* mac_len = 0 if broadcast address */
|
||||
src->mac_len = 0;
|
||||
src->mac[0] = 0;
|
||||
} else {
|
||||
src->mac_len = 1;
|
||||
src->mac[0] = mstp_address;
|
||||
}
|
||||
/* fill with 0's starting with index 1; index 0 filled above */
|
||||
for (i = 1; i < MAX_MAC_LEN; i++) {
|
||||
src->mac[i] = 0;
|
||||
}
|
||||
src->net = 0;
|
||||
src->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
src->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len)
|
||||
{ /* amount of PDU data */
|
||||
/* PDU is already in the Receive_Buffer */
|
||||
dlmstp_fill_bacnet_address(&Receive_Buffer.address, src);
|
||||
Receive_Buffer.pdu_len = pdu_len;
|
||||
Receive_Buffer.ready = true;
|
||||
}
|
||||
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t mac_address)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127) {
|
||||
MSTP_Port.This_Station = mac_address;
|
||||
/* FIXME: implement your data storage */
|
||||
/* I2C_Write_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
mac_address,
|
||||
EEPROM_MSTP_MAC_ADDR); */
|
||||
if (mac_address > MSTP_Port.Nmax_master)
|
||||
dlmstp_set_max_master(mac_address);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_my_address(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.This_Station;
|
||||
}
|
||||
|
||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||
/* maximum number of information frames the node may send before it must */
|
||||
/* pass the token. Max_Info_Frames may have different values on different */
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(
|
||||
uint8_t max_info_frames)
|
||||
{
|
||||
if (max_info_frames >= 1) {
|
||||
MSTP_Port.Nmax_info_frames = max_info_frames;
|
||||
/* FIXME: implement your data storage */
|
||||
/* I2C_Write_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(uint8_t)max_info_frames,
|
||||
EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_info_frames;
|
||||
}
|
||||
|
||||
/* This parameter represents the value of the Max_Master property of the */
|
||||
/* node's Device object. The value of Max_Master specifies the highest */
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master)
|
||||
{
|
||||
if (max_master <= 127) {
|
||||
if (MSTP_Port.This_Station <= max_master) {
|
||||
MSTP_Port.Nmax_master = max_master;
|
||||
/* FIXME: implement your data storage */
|
||||
/* I2C_Write_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
max_master,
|
||||
EEPROM_MSTP_MAX_MASTER_ADDR); */
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_max_master(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.Nmax_master;
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
|
||||
my_address->mac_len = 1;
|
||||
my_address->mac[0] = MSTP_Port.This_Station;
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 1;
|
||||
dest->mac[0] = MSTP_BROADCAST_ADDRESS;
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* always zero when DNET is broadcast */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,125 +1,125 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DLMSTP_H
|
||||
#define DLMSTP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
/* defines specific to MS/TP */
|
||||
#define MAX_HEADER (2+1+1+1+2+1)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
typedef struct dlmstp_packet {
|
||||
bool ready; /* true if ready to be sent or received */
|
||||
BACNET_ADDRESS address; /* source address */
|
||||
uint8_t frame_type; /* type of message */
|
||||
unsigned pdu_len; /* packet length */
|
||||
uint8_t pdu[MAX_MPDU]; /* packet */
|
||||
} DLMSTP_PACKET;
|
||||
|
||||
/* number of MS/TP tx/rx packets */
|
||||
extern uint16_t MSTP_Packets;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void dlmstp_reinit(
|
||||
void);
|
||||
void dlmstp_init(
|
||||
void);
|
||||
void dlmstp_cleanup(
|
||||
void);
|
||||
void dlmstp_millisecond_timer(
|
||||
void);
|
||||
void dlmstp_task(
|
||||
void);
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||
/* maximum number of information frames the node may send before it must */
|
||||
/* pass the token. Max_Info_Frames may have different values on different */
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(
|
||||
uint8_t max_info_frames);
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void);
|
||||
|
||||
/* This parameter represents the value of the Max_Master property of the */
|
||||
/* node's Device object. The value of Max_Master specifies the highest */
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master);
|
||||
uint8_t dlmstp_max_master(
|
||||
void);
|
||||
|
||||
/* MAC address for MS/TP */
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t my_address);
|
||||
uint8_t dlmstp_my_address(
|
||||
void);
|
||||
|
||||
/* BACnet address used in datalink */
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest); /* destination address */
|
||||
|
||||
/* MS/TP state machine functions */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DLMSTP_H
|
||||
#define DLMSTP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
/* defines specific to MS/TP */
|
||||
#define MAX_HEADER (2+1+1+1+2+1)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
typedef struct dlmstp_packet {
|
||||
bool ready; /* true if ready to be sent or received */
|
||||
BACNET_ADDRESS address; /* source address */
|
||||
uint8_t frame_type; /* type of message */
|
||||
unsigned pdu_len; /* packet length */
|
||||
uint8_t pdu[MAX_MPDU]; /* packet */
|
||||
} DLMSTP_PACKET;
|
||||
|
||||
/* number of MS/TP tx/rx packets */
|
||||
extern uint16_t MSTP_Packets;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void dlmstp_reinit(
|
||||
void);
|
||||
void dlmstp_init(
|
||||
void);
|
||||
void dlmstp_cleanup(
|
||||
void);
|
||||
void dlmstp_millisecond_timer(
|
||||
void);
|
||||
void dlmstp_task(
|
||||
void);
|
||||
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
int dlmstp_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||
/* maximum number of information frames the node may send before it must */
|
||||
/* pass the token. Max_Info_Frames may have different values on different */
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
void dlmstp_set_max_info_frames(
|
||||
uint8_t max_info_frames);
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void);
|
||||
|
||||
/* This parameter represents the value of the Max_Master property of the */
|
||||
/* node's Device object. The value of Max_Master specifies the highest */
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
void dlmstp_set_max_master(
|
||||
uint8_t max_master);
|
||||
uint8_t dlmstp_max_master(
|
||||
void);
|
||||
|
||||
/* MAC address for MS/TP */
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t my_address);
|
||||
uint8_t dlmstp_my_address(
|
||||
void);
|
||||
|
||||
/* BACnet address used in datalink */
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest); /* destination address */
|
||||
|
||||
/* MS/TP state machine functions */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,128 +1,128 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef HARDWARE_H
|
||||
#define HARDWARE_H
|
||||
|
||||
#include <p18f87j60.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* PORTA.0 Photocell Input PORTA.1 LED Row6 PORTA.2 LED Row5 PORTA.3 LED
|
||||
* Row4 PORTA.4 Square Wave input from RTC PORTA.5 LCD RW PORTB.0 Zero
|
||||
* Cross PORTB.1 USB RXF# PORTB.2 USB TXE# PORTB.3 Keypad Row Enable
|
||||
* (74HC373 Output Control) PORTB.4 Keypad Row Gate (74HC373 Gate)
|
||||
* PORTB.5 Switch Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6
|
||||
* ICD connection PORTB.7 ICD connection PORTC.0 Pilot Latch PORTC.1
|
||||
* Pilot Output Enable (low) PORTC.2 Piezo PORTC.3 I2C clock PORTC.4 I2C
|
||||
* data PORTC.5 RS232 enable (low) PORTC.6 RS232 Tx PORTC.7 RS232 Rx
|
||||
* PORTD.0 Data bus PORTD.1 Data bus PORTD.2 Data bus PORTD.3 Data bus
|
||||
* PORTD.4 Data bus PORTD.5 Data bus PORTD.6 Data bus PORTD.7 Data bus
|
||||
* PORTE.0 USB RD PORTE.1 USB WR PORTE.2 LCD RS PORTE.3 485 transmit
|
||||
* enable PORTE.4 Relay data latch PORTE.5 Switch Input Clock PORTE.6
|
||||
* Switch Input High/Low PORTE.7 Switch Input Data PORTF.0 LED Row2
|
||||
* PORTF.1 LED Row1 PORTF.2 LED Col5 PORTF.3 LED Col4 PORTF.4 LED Col3
|
||||
* PORTF.5 LED Col2 PORTF.6 LED Col1 PORTF.7 LED Col0 PORTG.0 485 receive
|
||||
* enable PORTG.1 485 Tx PORTG.2 485 Rx PORTG.3 LCD E PORTG.4 LED Row0 */
|
||||
#define RS485_TX_ENABLE PORTEbits.RE3
|
||||
#define RS485_RX_DISABLE PORTGbits.RG0
|
||||
|
||||
#define LEDPORT PORTG
|
||||
#define LEDTRIS TRISG
|
||||
#define LED_ROW1 PORTGbits.RG1
|
||||
#define LED_ROW2 PORTGbits.RG2
|
||||
#define LED_ROW3 PORTGbits.RG3
|
||||
#define LED_ROW4 PORTGbits.RG4
|
||||
|
||||
#define TURN_OFF_COMPARATORS() CMCON = 0x07
|
||||
|
||||
enum INT_STATE { INT_DISABLED, INT_ENABLED, INT_RESTORE };
|
||||
|
||||
#define RESTART_WDT() { _asm CLRWDT _endasm }
|
||||
|
||||
/* *************************************************************************
|
||||
define ENABLE_GLOBAL_INT() INTCONbits.GIE = 1 £
|
||||
#define DISABLE_GLOBAL_INT() INTCONbits.GIE = 0 £
|
||||
#define ENABLE_PERIPHERAL_INT() INTCONbits.PEIE = 1 £
|
||||
#define DISABLE_PERIPHERAL_INT() INTCONbits.PEIE = 0
|
||||
*************************************************************************** */
|
||||
#define ENABLE_HIGH_INT() INTCONbits.GIE = 1
|
||||
#define DISABLE_HIGH_INT() INTCONbits.GIE = 0
|
||||
|
||||
#define ENABLE_LOW_INT() INTCONbits.PEIE = 1
|
||||
#define DISABLE_LOW_INT() INTCONbits.PEIE = 0
|
||||
|
||||
#define ENABLE_TIMER0_INT() INTCONbits.TMR0IE = 1
|
||||
#define DISABLE_TIMER0_INT() INTCONbits.TMR0IE = 0
|
||||
|
||||
#define ENABLE_TIMER2_INT() PIE1bits.TMR2IE = 1
|
||||
#define DISABLE_TIMER2_INT() PIE1bits.TMR2IE = 0
|
||||
|
||||
#define ENABLE_TIMER4_INT() PIE3bits.TMR4IE = 1
|
||||
#define DISABLE_TIMER4_INT() PIE3bits.TMR4IE = 0
|
||||
|
||||
#define ENABLE_CCP2_INT() PIE2bits.CCP2IE = 1
|
||||
#define DISABLE_CCP2_INT() PIE2bits.CCP2IE = 0
|
||||
|
||||
#define ENABLE_CCP1_INT() PIE1bits.CCP1IE = 1
|
||||
#define DISABLE_CCP1_INT() PIE1bits.CCP1IE = 0
|
||||
|
||||
#define ENABLE_ABUS_INT() PIE1bits.SSPIE = 1
|
||||
#define DISABLE_ABUS_INT() PIE1bits.SSPIE = 0
|
||||
#define CLEAR_ABUS_FLAG() PIR1bits.SSPIF = 0
|
||||
|
||||
#define SETUP_CCP1(x) CCP1CON = x
|
||||
#define SETUP_CCP2(x) CCP2CON = x
|
||||
|
||||
#define DISABLE_RX_INT() PIE1bits.RCIE = 0
|
||||
#define ENABLE_RX_INT() PIE1bits.RCIE = 1
|
||||
|
||||
#define DISABLE_TX_INT() PIE1bits.TXIE = 0
|
||||
#define ENABLE_TX_INT() PIE1bits.TXIE = 1
|
||||
|
||||
#if CLOCKSPEED == 20
|
||||
#define DELAY_US(x) { _asm \
|
||||
MOVLW x \
|
||||
LOOP: \
|
||||
NOP \
|
||||
NOP \
|
||||
DECFSZ WREG, 1, 0 \
|
||||
BRA LOOP \
|
||||
_endasm }
|
||||
#endif
|
||||
|
||||
#define setup_timer4(mode, period, postscale) \
|
||||
T4CON = (mode | (postscale - 1) << 3); \
|
||||
PR4 = period
|
||||
|
||||
#define setup_timer2(mode, period, postscale) \
|
||||
T2CON = (mode | (postscale - 1) << 3); \
|
||||
PR2 = period
|
||||
|
||||
|
||||
/* Global Vars */
|
||||
extern uint8_t Piezo_Timer;
|
||||
extern volatile bool DataPortLocked;
|
||||
|
||||
#endif /* HARDWARE_H */
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef HARDWARE_H
|
||||
#define HARDWARE_H
|
||||
|
||||
#include <p18f87j60.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* PORTA.0 Photocell Input PORTA.1 LED Row6 PORTA.2 LED Row5 PORTA.3 LED
|
||||
* Row4 PORTA.4 Square Wave input from RTC PORTA.5 LCD RW PORTB.0 Zero
|
||||
* Cross PORTB.1 USB RXF# PORTB.2 USB TXE# PORTB.3 Keypad Row Enable
|
||||
* (74HC373 Output Control) PORTB.4 Keypad Row Gate (74HC373 Gate)
|
||||
* PORTB.5 Switch Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6
|
||||
* ICD connection PORTB.7 ICD connection PORTC.0 Pilot Latch PORTC.1
|
||||
* Pilot Output Enable (low) PORTC.2 Piezo PORTC.3 I2C clock PORTC.4 I2C
|
||||
* data PORTC.5 RS232 enable (low) PORTC.6 RS232 Tx PORTC.7 RS232 Rx
|
||||
* PORTD.0 Data bus PORTD.1 Data bus PORTD.2 Data bus PORTD.3 Data bus
|
||||
* PORTD.4 Data bus PORTD.5 Data bus PORTD.6 Data bus PORTD.7 Data bus
|
||||
* PORTE.0 USB RD PORTE.1 USB WR PORTE.2 LCD RS PORTE.3 485 transmit
|
||||
* enable PORTE.4 Relay data latch PORTE.5 Switch Input Clock PORTE.6
|
||||
* Switch Input High/Low PORTE.7 Switch Input Data PORTF.0 LED Row2
|
||||
* PORTF.1 LED Row1 PORTF.2 LED Col5 PORTF.3 LED Col4 PORTF.4 LED Col3
|
||||
* PORTF.5 LED Col2 PORTF.6 LED Col1 PORTF.7 LED Col0 PORTG.0 485 receive
|
||||
* enable PORTG.1 485 Tx PORTG.2 485 Rx PORTG.3 LCD E PORTG.4 LED Row0 */
|
||||
#define RS485_TX_ENABLE PORTEbits.RE3
|
||||
#define RS485_RX_DISABLE PORTGbits.RG0
|
||||
|
||||
#define LEDPORT PORTG
|
||||
#define LEDTRIS TRISG
|
||||
#define LED_ROW1 PORTGbits.RG1
|
||||
#define LED_ROW2 PORTGbits.RG2
|
||||
#define LED_ROW3 PORTGbits.RG3
|
||||
#define LED_ROW4 PORTGbits.RG4
|
||||
|
||||
#define TURN_OFF_COMPARATORS() CMCON = 0x07
|
||||
|
||||
enum INT_STATE { INT_DISABLED, INT_ENABLED, INT_RESTORE };
|
||||
|
||||
#define RESTART_WDT() { _asm CLRWDT _endasm }
|
||||
|
||||
/* *************************************************************************
|
||||
define ENABLE_GLOBAL_INT() INTCONbits.GIE = 1 £
|
||||
#define DISABLE_GLOBAL_INT() INTCONbits.GIE = 0 £
|
||||
#define ENABLE_PERIPHERAL_INT() INTCONbits.PEIE = 1 £
|
||||
#define DISABLE_PERIPHERAL_INT() INTCONbits.PEIE = 0
|
||||
*************************************************************************** */
|
||||
#define ENABLE_HIGH_INT() INTCONbits.GIE = 1
|
||||
#define DISABLE_HIGH_INT() INTCONbits.GIE = 0
|
||||
|
||||
#define ENABLE_LOW_INT() INTCONbits.PEIE = 1
|
||||
#define DISABLE_LOW_INT() INTCONbits.PEIE = 0
|
||||
|
||||
#define ENABLE_TIMER0_INT() INTCONbits.TMR0IE = 1
|
||||
#define DISABLE_TIMER0_INT() INTCONbits.TMR0IE = 0
|
||||
|
||||
#define ENABLE_TIMER2_INT() PIE1bits.TMR2IE = 1
|
||||
#define DISABLE_TIMER2_INT() PIE1bits.TMR2IE = 0
|
||||
|
||||
#define ENABLE_TIMER4_INT() PIE3bits.TMR4IE = 1
|
||||
#define DISABLE_TIMER4_INT() PIE3bits.TMR4IE = 0
|
||||
|
||||
#define ENABLE_CCP2_INT() PIE2bits.CCP2IE = 1
|
||||
#define DISABLE_CCP2_INT() PIE2bits.CCP2IE = 0
|
||||
|
||||
#define ENABLE_CCP1_INT() PIE1bits.CCP1IE = 1
|
||||
#define DISABLE_CCP1_INT() PIE1bits.CCP1IE = 0
|
||||
|
||||
#define ENABLE_ABUS_INT() PIE1bits.SSPIE = 1
|
||||
#define DISABLE_ABUS_INT() PIE1bits.SSPIE = 0
|
||||
#define CLEAR_ABUS_FLAG() PIR1bits.SSPIF = 0
|
||||
|
||||
#define SETUP_CCP1(x) CCP1CON = x
|
||||
#define SETUP_CCP2(x) CCP2CON = x
|
||||
|
||||
#define DISABLE_RX_INT() PIE1bits.RCIE = 0
|
||||
#define ENABLE_RX_INT() PIE1bits.RCIE = 1
|
||||
|
||||
#define DISABLE_TX_INT() PIE1bits.TXIE = 0
|
||||
#define ENABLE_TX_INT() PIE1bits.TXIE = 1
|
||||
|
||||
#if CLOCKSPEED == 20
|
||||
#define DELAY_US(x) { _asm \
|
||||
MOVLW x \
|
||||
LOOP: \
|
||||
NOP \
|
||||
NOP \
|
||||
DECFSZ WREG, 1, 0 \
|
||||
BRA LOOP \
|
||||
_endasm }
|
||||
#endif
|
||||
|
||||
#define setup_timer4(mode, period, postscale) \
|
||||
T4CON = (mode | (postscale - 1) << 3); \
|
||||
PR4 = period
|
||||
|
||||
#define setup_timer2(mode, period, postscale) \
|
||||
T2CON = (mode | (postscale - 1) << 3); \
|
||||
PR2 = period
|
||||
|
||||
|
||||
/* Global Vars */
|
||||
extern uint8_t Piezo_Timer;
|
||||
extern volatile bool DataPortLocked;
|
||||
|
||||
#endif /* HARDWARE_H */
|
||||
|
||||
@@ -1,206 +1,206 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include "stdint.h"
|
||||
#include "hardware.h"
|
||||
#include "rs485.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
/* from main.c */
|
||||
extern volatile uint8_t Milliseconds;
|
||||
|
||||
void InterruptHandlerHigh(
|
||||
void);
|
||||
void InterruptHandlerLow(
|
||||
void);
|
||||
void Interrupt_Timer2(
|
||||
void);
|
||||
void Interrupt_Timer3(
|
||||
void);
|
||||
void Interrupt_Timer4(
|
||||
void);
|
||||
void Interrupt_USART_Rx(
|
||||
void);
|
||||
void Interrupt_USART_Tx(
|
||||
void);
|
||||
void Interrupt_CCP2(
|
||||
void);
|
||||
void INT0_Interrupt(
|
||||
void);
|
||||
|
||||
#pragma code InterruptVectorHigh = 0x08
|
||||
void InterruptVectorHigh(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerHigh _endasm}
|
||||
#pragma code
|
||||
#pragma code InterruptVectorLow = 0x18
|
||||
void InterruptVectorLow(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerLow _endasm}
|
||||
#pragma code
|
||||
#pragma interrupt InterruptHandlerHigh
|
||||
void InterruptHandlerHigh(
|
||||
void)
|
||||
{
|
||||
#if 0
|
||||
/* check for USART Rx int */
|
||||
if ((PIR1bits.RCIF) && (PIE1bits.RCIE)) {
|
||||
if ((RCSTA1bits.FERR) || (RCSTA1bits.OERR)) {
|
||||
Comstat.Rx_Bufferoverrun = TRUE;
|
||||
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
|
||||
} else if (Comstat.Rx_Bytes++ < RX_BUFFER_SIZE - 1) {
|
||||
Rx_Buffer[Comstat.RxHead++] = RCREG1;
|
||||
|
||||
/* Stick a Null on the end to let us use str functions on our
|
||||
* buffer */
|
||||
Rx_Buffer[Comstat.RxHead] = 0;
|
||||
} else {
|
||||
Comstat.Rx_Bufferoverrun = TRUE;
|
||||
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check for timer0 int */
|
||||
if ((INTCONbits.TMR0IF) && (INTCONbits.TMR0IE)) {
|
||||
INTCONbits.TMR0IF = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma interruptlow InterruptHandlerLow save = PROD, section(".tmpdata"), TABLAT, TBLPTR, section \
|
||||
("MATH_DATA")
|
||||
|
||||
void InterruptHandlerLow(
|
||||
void)
|
||||
{
|
||||
/* check for timer2 int */
|
||||
if ((PIR1bits.TMR2IF) && (PIE1bits.TMR2IE)) {
|
||||
PIR1bits.TMR2IF = 0;
|
||||
Interrupt_Timer2();
|
||||
}
|
||||
|
||||
/* check for timer3 int */
|
||||
if ((PIR2bits.TMR3IF) && (PIE2bits.TMR3IE)) {
|
||||
PIR2bits.TMR3IF = 0;
|
||||
Interrupt_Timer3();
|
||||
}
|
||||
|
||||
/* check for timer4 int */
|
||||
if ((PIR3bits.TMR4IF) && (PIE3bits.TMR4IE)) {
|
||||
PIR3bits.TMR4IF = 0;
|
||||
dlmstp_millisecond_timer();
|
||||
Interrupt_Timer4();
|
||||
}
|
||||
|
||||
/* check for compare int */
|
||||
if ((PIR2bits.CCP2IF) && (PIE2bits.CCP2IE)) {
|
||||
PIR2bits.CCP2IF = 0;
|
||||
Interrupt_CCP2();
|
||||
}
|
||||
|
||||
/* check for USART Tx int */
|
||||
if ((PIR3bits.TX2IF) && (PIE3bits.TX2IE)) {
|
||||
RS485_Interrupt_Tx();
|
||||
}
|
||||
|
||||
/* check for USART Rx int */
|
||||
if ((PIR3bits.RC2IF) && (PIE3bits.RC2IE)) {
|
||||
RS485_Interrupt_Rx();
|
||||
}
|
||||
|
||||
/* Unused Interrupts
|
||||
//check for timer1 int
|
||||
if ((PIR1bits.TMR1IF) && (PIE1bits.TMR1IE))
|
||||
{
|
||||
PIR1bits.TMR1IF = 0;
|
||||
Interrupt_Timer1();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR1bits.CCP1IF) && (PIE1bits.CCP1IE))
|
||||
{
|
||||
PIR1bits.CCP1IF = 0;
|
||||
Interrupt_CCP1();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR3bits.CCP3IF) && (PIE3bits.CCP3IE))
|
||||
{
|
||||
PIR3bits.CCP3IF = 0;
|
||||
Interrupt_CCP3();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR3bits.CCP4IF) && (PIE3bits.CCP4IE))
|
||||
{
|
||||
PIR3bits.CCP4IF = 0;
|
||||
|
||||
Interrupt_CCP4();
|
||||
}
|
||||
|
||||
//check for AD int
|
||||
if ((PIR1bits.ADIF) && (PIE1bits.ADIE))
|
||||
{
|
||||
PIR1bits.ADIF = 0;
|
||||
Interrupt_ADC();
|
||||
}
|
||||
|
||||
//check for MSSP int
|
||||
if ((PIR1bits.SSPIF) && (PIE1bits.SSPIE))
|
||||
{
|
||||
PIR1bits.SSPIF = 0;
|
||||
Interrupt_SSP();
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
void Interrupt_Timer2(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
void Interrupt_Timer3(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Timer4 is set to go off every 1ms. This is our system tick */
|
||||
void Interrupt_Timer4(
|
||||
void)
|
||||
{
|
||||
/* Milisecond is our system tick */
|
||||
if (Milliseconds < 0xFF)
|
||||
++Milliseconds;
|
||||
}
|
||||
|
||||
void Interrupt_CCP2(
|
||||
void)
|
||||
{
|
||||
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include "stdint.h"
|
||||
#include "hardware.h"
|
||||
#include "rs485.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
/* from main.c */
|
||||
extern volatile uint8_t Milliseconds;
|
||||
|
||||
void InterruptHandlerHigh(
|
||||
void);
|
||||
void InterruptHandlerLow(
|
||||
void);
|
||||
void Interrupt_Timer2(
|
||||
void);
|
||||
void Interrupt_Timer3(
|
||||
void);
|
||||
void Interrupt_Timer4(
|
||||
void);
|
||||
void Interrupt_USART_Rx(
|
||||
void);
|
||||
void Interrupt_USART_Tx(
|
||||
void);
|
||||
void Interrupt_CCP2(
|
||||
void);
|
||||
void INT0_Interrupt(
|
||||
void);
|
||||
|
||||
#pragma code InterruptVectorHigh = 0x08
|
||||
void InterruptVectorHigh(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerHigh _endasm}
|
||||
#pragma code
|
||||
#pragma code InterruptVectorLow = 0x18
|
||||
void InterruptVectorLow(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerLow _endasm}
|
||||
#pragma code
|
||||
#pragma interrupt InterruptHandlerHigh
|
||||
void InterruptHandlerHigh(
|
||||
void)
|
||||
{
|
||||
#if 0
|
||||
/* check for USART Rx int */
|
||||
if ((PIR1bits.RCIF) && (PIE1bits.RCIE)) {
|
||||
if ((RCSTA1bits.FERR) || (RCSTA1bits.OERR)) {
|
||||
Comstat.Rx_Bufferoverrun = TRUE;
|
||||
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
|
||||
} else if (Comstat.Rx_Bytes++ < RX_BUFFER_SIZE - 1) {
|
||||
Rx_Buffer[Comstat.RxHead++] = RCREG1;
|
||||
|
||||
/* Stick a Null on the end to let us use str functions on our
|
||||
* buffer */
|
||||
Rx_Buffer[Comstat.RxHead] = 0;
|
||||
} else {
|
||||
Comstat.Rx_Bufferoverrun = TRUE;
|
||||
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check for timer0 int */
|
||||
if ((INTCONbits.TMR0IF) && (INTCONbits.TMR0IE)) {
|
||||
INTCONbits.TMR0IF = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma interruptlow InterruptHandlerLow save = PROD, section(".tmpdata"), TABLAT, TBLPTR, section \
|
||||
("MATH_DATA")
|
||||
|
||||
void InterruptHandlerLow(
|
||||
void)
|
||||
{
|
||||
/* check for timer2 int */
|
||||
if ((PIR1bits.TMR2IF) && (PIE1bits.TMR2IE)) {
|
||||
PIR1bits.TMR2IF = 0;
|
||||
Interrupt_Timer2();
|
||||
}
|
||||
|
||||
/* check for timer3 int */
|
||||
if ((PIR2bits.TMR3IF) && (PIE2bits.TMR3IE)) {
|
||||
PIR2bits.TMR3IF = 0;
|
||||
Interrupt_Timer3();
|
||||
}
|
||||
|
||||
/* check for timer4 int */
|
||||
if ((PIR3bits.TMR4IF) && (PIE3bits.TMR4IE)) {
|
||||
PIR3bits.TMR4IF = 0;
|
||||
dlmstp_millisecond_timer();
|
||||
Interrupt_Timer4();
|
||||
}
|
||||
|
||||
/* check for compare int */
|
||||
if ((PIR2bits.CCP2IF) && (PIE2bits.CCP2IE)) {
|
||||
PIR2bits.CCP2IF = 0;
|
||||
Interrupt_CCP2();
|
||||
}
|
||||
|
||||
/* check for USART Tx int */
|
||||
if ((PIR3bits.TX2IF) && (PIE3bits.TX2IE)) {
|
||||
RS485_Interrupt_Tx();
|
||||
}
|
||||
|
||||
/* check for USART Rx int */
|
||||
if ((PIR3bits.RC2IF) && (PIE3bits.RC2IE)) {
|
||||
RS485_Interrupt_Rx();
|
||||
}
|
||||
|
||||
/* Unused Interrupts
|
||||
//check for timer1 int
|
||||
if ((PIR1bits.TMR1IF) && (PIE1bits.TMR1IE))
|
||||
{
|
||||
PIR1bits.TMR1IF = 0;
|
||||
Interrupt_Timer1();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR1bits.CCP1IF) && (PIE1bits.CCP1IE))
|
||||
{
|
||||
PIR1bits.CCP1IF = 0;
|
||||
Interrupt_CCP1();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR3bits.CCP3IF) && (PIE3bits.CCP3IE))
|
||||
{
|
||||
PIR3bits.CCP3IF = 0;
|
||||
Interrupt_CCP3();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR3bits.CCP4IF) && (PIE3bits.CCP4IE))
|
||||
{
|
||||
PIR3bits.CCP4IF = 0;
|
||||
|
||||
Interrupt_CCP4();
|
||||
}
|
||||
|
||||
//check for AD int
|
||||
if ((PIR1bits.ADIF) && (PIE1bits.ADIE))
|
||||
{
|
||||
PIR1bits.ADIF = 0;
|
||||
Interrupt_ADC();
|
||||
}
|
||||
|
||||
//check for MSSP int
|
||||
if ((PIR1bits.SSPIF) && (PIE1bits.SSPIE))
|
||||
{
|
||||
PIR1bits.SSPIF = 0;
|
||||
Interrupt_SSP();
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
void Interrupt_Timer2(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
void Interrupt_Timer3(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Timer4 is set to go off every 1ms. This is our system tick */
|
||||
void Interrupt_Timer4(
|
||||
void)
|
||||
{
|
||||
/* Milisecond is our system tick */
|
||||
if (Milliseconds < 0xFF)
|
||||
++Milliseconds;
|
||||
}
|
||||
|
||||
void Interrupt_CCP2(
|
||||
void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,223 +1,223 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memmove */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "stdint.h"
|
||||
#include "hardware.h"
|
||||
/* BACnet */
|
||||
#include "apdu.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
#include "rs485.h"
|
||||
|
||||
/* chip configuration data */
|
||||
/* define this to enable ICD */
|
||||
/* #define USE_ICD */
|
||||
|
||||
/* Configuration Bits */
|
||||
#pragma config FOSC = HSPLL
|
||||
#pragma config FOSC2 = ON
|
||||
#pragma config FCMEN = OFF
|
||||
#pragma config XINST = OFF
|
||||
#pragma config IESO = OFF
|
||||
#pragma config CCP2MX = ON
|
||||
#pragma config ECCPMX = ON
|
||||
#pragma config STVR = OFF
|
||||
#pragma config CP0 = OFF
|
||||
#pragma config ETHLED = ON
|
||||
|
||||
volatile uint8_t Milliseconds = 0;
|
||||
volatile uint8_t Zero_Cross_Timeout = 0;
|
||||
|
||||
void Reinitialize(
|
||||
void)
|
||||
{
|
||||
uint8_t i;
|
||||
char name = 0;
|
||||
|
||||
_asm reset _endasm return;
|
||||
}
|
||||
|
||||
void Global_Int(
|
||||
enum INT_STATE state)
|
||||
{
|
||||
static uint8_t intstate = 0;
|
||||
|
||||
switch (state) {
|
||||
case INT_DISABLED:
|
||||
intstate >>= 2;
|
||||
intstate |= (INTCON & 0xC0);
|
||||
break;
|
||||
case INT_ENABLED:
|
||||
INTCONbits.GIE = 1;
|
||||
INTCONbits.PEIE = 1;
|
||||
intstate <<= 2;
|
||||
break;
|
||||
case INT_RESTORE:
|
||||
INTCON |= (intstate & 0xC0);
|
||||
intstate <<= 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hardware_Initialize(
|
||||
void)
|
||||
{
|
||||
/* PORTA.0 Input - Photocell PORTA.1 Output - LED Row6 PORTA.2 Output
|
||||
* - LED Row5 PORTA.3 Output - LED Row4 PORTA.4 Input - Square Wave
|
||||
* input from RTC PORTA.5 Output - LCD RW */
|
||||
TRISA = 0xD1;
|
||||
|
||||
/* PORTB.0 Input - Zero Cross PORTB.1 Input - USB RXF# PORTB.2 Input
|
||||
* USB TXE# PORTB.3 Output - Keypad Row Enable (74HC373 Output Control)
|
||||
* PORTB.4 Output Keypad Row Gate (74HC373 Gate) PORTB.5 Output Switch
|
||||
* Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6 Input - ICD
|
||||
* connection PORTB.7 Input - ICD connection */
|
||||
TRISB = 0xC7;
|
||||
|
||||
/* PORTC.0 Output - Pilot Latch PORTC.1 Output - Pilot Output Enable
|
||||
* (low) PORTC.2 I/O - Piezo PORTC.3 Input - I2C clock PORTC.4 Input
|
||||
* I2C data PORTC.5 Output RS232 enable (low) PORTC.6 Output - RS232 Tx
|
||||
* PORTC.7 Input - RS232 Rx */
|
||||
TRISC = 0x9C;
|
||||
|
||||
/* PORTD.0 I/O - Data bus PORTD.1 I/O - Data bus PORTD.2 I/O - Data
|
||||
* bus PORTD.3 I/O - Data bus PORTD.4 I/O - Data bus PORTD.5 I/O - Data
|
||||
* bus PORTD.6 I/O - Data bus PORTD.7 I/O - Data bus */
|
||||
TRISD = 0xFF;
|
||||
|
||||
/* PORTE.0 Input - USB RD PORTE.1 Input - USB WR PORTE.2 Output - LCD
|
||||
* RS PORTE.3 Output - 485 transmit enable PORTE.4 Output - Relay data
|
||||
* latch PORTE.5 Output Switch Input Clock PORTE.6 Output - Switch
|
||||
* Input High/Low PORTE.7 Input Switch Input Data */
|
||||
TRISE = 0x83;
|
||||
|
||||
/* PORTF.0 Output - LED Row2 PORTF.1 Output - LED Row1 PORTF.2 Output
|
||||
* - LED Col5 PORTF.3 Output - LED Col4 PORTF.4 Output - LED Col3
|
||||
* PORTF.5 Output - LED Col2 PORTF.6 Output - LED Col1 PORTF.7 Output
|
||||
* LED Col0 */
|
||||
TRISF = 0x00;
|
||||
|
||||
/* PORTG.0 Output - 485 receive enable PORTG.1 Output - 485 Tx PORTG.2
|
||||
* Input 485 Rx PORTG.3 Output - LCD E PORTG.4 Output - LED Row0 */
|
||||
TRISG = 0xE6;
|
||||
|
||||
/* Turn all leds off. These are the hardware pins */
|
||||
LED_ROW1 = 1;
|
||||
LED_ROW2 = 1;
|
||||
LED_ROW3 = 1;
|
||||
LED_ROW4 = 1;
|
||||
LEDPORT = 0x03;
|
||||
|
||||
/* The following gives us a PWM frequency of 1.990KHz with a 50% duty
|
||||
* cycle It also serves to multiplex the LEDs. */
|
||||
CCPR1L = 0x4E;
|
||||
CCP1CON = 0x2F;
|
||||
setup_timer2(6, 156, 2);
|
||||
PIE1bits.TMR2IE = 1;
|
||||
|
||||
/* We will use Timer4 as our system tick timer. Our system tick is set
|
||||
* to 1ms. Hold off on enabling the int. */
|
||||
setup_timer4(5, 250, 5);
|
||||
|
||||
/* Setup our interrupt priorities */
|
||||
RCONbits.IPEN = 1;
|
||||
IPR1 = 0;
|
||||
IPR2 = 0;
|
||||
IPR3 = 0;
|
||||
|
||||
/* Setup TMR0 to be high priority */
|
||||
INTCON2 = 0xFC;
|
||||
INTCON3 = 0;
|
||||
|
||||
/* USART 1 high priority */
|
||||
IPR1bits.RC1IP = 1;
|
||||
IPR1bits.TX1IP = 1;
|
||||
|
||||
/* Finally enable our ints */
|
||||
Global_Int(INT_ENABLED);
|
||||
}
|
||||
|
||||
void Initialize_Variables(
|
||||
void)
|
||||
{
|
||||
/* Check to see if we need to initialize our eeproms */
|
||||
ENABLE_TIMER4_INT();
|
||||
/* interrupts must be enabled before we read our inputs */
|
||||
Global_Int(INT_ENABLED);
|
||||
/* Start our time from now */
|
||||
Milliseconds = 0;
|
||||
}
|
||||
|
||||
void MainTasks(
|
||||
void)
|
||||
{
|
||||
static uint16_t millisecond_counter = 0;
|
||||
/* Handle our millisecond counters */
|
||||
while (Milliseconds) {
|
||||
millisecond_counter++;
|
||||
--Milliseconds;
|
||||
}
|
||||
/* Handle our seconds counters */
|
||||
if (millisecond_counter > 1000) {
|
||||
millisecond_counter -= 1000;
|
||||
dcc_timer_seconds(1);
|
||||
}
|
||||
}
|
||||
|
||||
void main(
|
||||
void)
|
||||
{
|
||||
RCONbits.NOT_POR = 1;
|
||||
RCONbits.NOT_RI = 1;
|
||||
Hardware_Initialize();
|
||||
Initialize_Variables();
|
||||
/* initialize BACnet Data Link Layer */
|
||||
dlmstp_set_my_address(42);
|
||||
dlmstp_set_max_info_frames(1);
|
||||
dlmstp_set_max_master(127);
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
dlmstp_init();
|
||||
/* Handle anything that needs to be done on powerup */
|
||||
/* Greet the BACnet world! */
|
||||
Send_I_Am(&Handler_Transmit_Buffer[0]);
|
||||
/* Main loop */
|
||||
while (TRUE) {
|
||||
RESTART_WDT();
|
||||
dlmstp_task();
|
||||
MainTasks();
|
||||
Global_Int(INT_ENABLED);
|
||||
ENABLE_TIMER4_INT();
|
||||
}
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memmove */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "stdint.h"
|
||||
#include "hardware.h"
|
||||
/* BACnet */
|
||||
#include "apdu.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
#include "rs485.h"
|
||||
|
||||
/* chip configuration data */
|
||||
/* define this to enable ICD */
|
||||
/* #define USE_ICD */
|
||||
|
||||
/* Configuration Bits */
|
||||
#pragma config FOSC = HSPLL
|
||||
#pragma config FOSC2 = ON
|
||||
#pragma config FCMEN = OFF
|
||||
#pragma config XINST = OFF
|
||||
#pragma config IESO = OFF
|
||||
#pragma config CCP2MX = ON
|
||||
#pragma config ECCPMX = ON
|
||||
#pragma config STVR = OFF
|
||||
#pragma config CP0 = OFF
|
||||
#pragma config ETHLED = ON
|
||||
|
||||
volatile uint8_t Milliseconds = 0;
|
||||
volatile uint8_t Zero_Cross_Timeout = 0;
|
||||
|
||||
void Reinitialize(
|
||||
void)
|
||||
{
|
||||
uint8_t i;
|
||||
char name = 0;
|
||||
|
||||
_asm reset _endasm return;
|
||||
}
|
||||
|
||||
void Global_Int(
|
||||
enum INT_STATE state)
|
||||
{
|
||||
static uint8_t intstate = 0;
|
||||
|
||||
switch (state) {
|
||||
case INT_DISABLED:
|
||||
intstate >>= 2;
|
||||
intstate |= (INTCON & 0xC0);
|
||||
break;
|
||||
case INT_ENABLED:
|
||||
INTCONbits.GIE = 1;
|
||||
INTCONbits.PEIE = 1;
|
||||
intstate <<= 2;
|
||||
break;
|
||||
case INT_RESTORE:
|
||||
INTCON |= (intstate & 0xC0);
|
||||
intstate <<= 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hardware_Initialize(
|
||||
void)
|
||||
{
|
||||
/* PORTA.0 Input - Photocell PORTA.1 Output - LED Row6 PORTA.2 Output
|
||||
* - LED Row5 PORTA.3 Output - LED Row4 PORTA.4 Input - Square Wave
|
||||
* input from RTC PORTA.5 Output - LCD RW */
|
||||
TRISA = 0xD1;
|
||||
|
||||
/* PORTB.0 Input - Zero Cross PORTB.1 Input - USB RXF# PORTB.2 Input
|
||||
* USB TXE# PORTB.3 Output - Keypad Row Enable (74HC373 Output Control)
|
||||
* PORTB.4 Output Keypad Row Gate (74HC373 Gate) PORTB.5 Output Switch
|
||||
* Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6 Input - ICD
|
||||
* connection PORTB.7 Input - ICD connection */
|
||||
TRISB = 0xC7;
|
||||
|
||||
/* PORTC.0 Output - Pilot Latch PORTC.1 Output - Pilot Output Enable
|
||||
* (low) PORTC.2 I/O - Piezo PORTC.3 Input - I2C clock PORTC.4 Input
|
||||
* I2C data PORTC.5 Output RS232 enable (low) PORTC.6 Output - RS232 Tx
|
||||
* PORTC.7 Input - RS232 Rx */
|
||||
TRISC = 0x9C;
|
||||
|
||||
/* PORTD.0 I/O - Data bus PORTD.1 I/O - Data bus PORTD.2 I/O - Data
|
||||
* bus PORTD.3 I/O - Data bus PORTD.4 I/O - Data bus PORTD.5 I/O - Data
|
||||
* bus PORTD.6 I/O - Data bus PORTD.7 I/O - Data bus */
|
||||
TRISD = 0xFF;
|
||||
|
||||
/* PORTE.0 Input - USB RD PORTE.1 Input - USB WR PORTE.2 Output - LCD
|
||||
* RS PORTE.3 Output - 485 transmit enable PORTE.4 Output - Relay data
|
||||
* latch PORTE.5 Output Switch Input Clock PORTE.6 Output - Switch
|
||||
* Input High/Low PORTE.7 Input Switch Input Data */
|
||||
TRISE = 0x83;
|
||||
|
||||
/* PORTF.0 Output - LED Row2 PORTF.1 Output - LED Row1 PORTF.2 Output
|
||||
* - LED Col5 PORTF.3 Output - LED Col4 PORTF.4 Output - LED Col3
|
||||
* PORTF.5 Output - LED Col2 PORTF.6 Output - LED Col1 PORTF.7 Output
|
||||
* LED Col0 */
|
||||
TRISF = 0x00;
|
||||
|
||||
/* PORTG.0 Output - 485 receive enable PORTG.1 Output - 485 Tx PORTG.2
|
||||
* Input 485 Rx PORTG.3 Output - LCD E PORTG.4 Output - LED Row0 */
|
||||
TRISG = 0xE6;
|
||||
|
||||
/* Turn all leds off. These are the hardware pins */
|
||||
LED_ROW1 = 1;
|
||||
LED_ROW2 = 1;
|
||||
LED_ROW3 = 1;
|
||||
LED_ROW4 = 1;
|
||||
LEDPORT = 0x03;
|
||||
|
||||
/* The following gives us a PWM frequency of 1.990KHz with a 50% duty
|
||||
* cycle It also serves to multiplex the LEDs. */
|
||||
CCPR1L = 0x4E;
|
||||
CCP1CON = 0x2F;
|
||||
setup_timer2(6, 156, 2);
|
||||
PIE1bits.TMR2IE = 1;
|
||||
|
||||
/* We will use Timer4 as our system tick timer. Our system tick is set
|
||||
* to 1ms. Hold off on enabling the int. */
|
||||
setup_timer4(5, 250, 5);
|
||||
|
||||
/* Setup our interrupt priorities */
|
||||
RCONbits.IPEN = 1;
|
||||
IPR1 = 0;
|
||||
IPR2 = 0;
|
||||
IPR3 = 0;
|
||||
|
||||
/* Setup TMR0 to be high priority */
|
||||
INTCON2 = 0xFC;
|
||||
INTCON3 = 0;
|
||||
|
||||
/* USART 1 high priority */
|
||||
IPR1bits.RC1IP = 1;
|
||||
IPR1bits.TX1IP = 1;
|
||||
|
||||
/* Finally enable our ints */
|
||||
Global_Int(INT_ENABLED);
|
||||
}
|
||||
|
||||
void Initialize_Variables(
|
||||
void)
|
||||
{
|
||||
/* Check to see if we need to initialize our eeproms */
|
||||
ENABLE_TIMER4_INT();
|
||||
/* interrupts must be enabled before we read our inputs */
|
||||
Global_Int(INT_ENABLED);
|
||||
/* Start our time from now */
|
||||
Milliseconds = 0;
|
||||
}
|
||||
|
||||
void MainTasks(
|
||||
void)
|
||||
{
|
||||
static uint16_t millisecond_counter = 0;
|
||||
/* Handle our millisecond counters */
|
||||
while (Milliseconds) {
|
||||
millisecond_counter++;
|
||||
--Milliseconds;
|
||||
}
|
||||
/* Handle our seconds counters */
|
||||
if (millisecond_counter > 1000) {
|
||||
millisecond_counter -= 1000;
|
||||
dcc_timer_seconds(1);
|
||||
}
|
||||
}
|
||||
|
||||
void main(
|
||||
void)
|
||||
{
|
||||
RCONbits.NOT_POR = 1;
|
||||
RCONbits.NOT_RI = 1;
|
||||
Hardware_Initialize();
|
||||
Initialize_Variables();
|
||||
/* initialize BACnet Data Link Layer */
|
||||
dlmstp_set_my_address(42);
|
||||
dlmstp_set_max_info_frames(1);
|
||||
dlmstp_set_max_master(127);
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
dlmstp_init();
|
||||
/* Handle anything that needs to be done on powerup */
|
||||
/* Greet the BACnet world! */
|
||||
Send_I_Am(&Handler_Transmit_Buffer[0]);
|
||||
/* Main loop */
|
||||
while (TRUE) {
|
||||
RESTART_WDT();
|
||||
dlmstp_task();
|
||||
MainTasks();
|
||||
Global_Int(INT_ENABLED);
|
||||
ENABLE_TIMER4_INT();
|
||||
}
|
||||
}
|
||||
|
||||
+1250
-1250
File diff suppressed because it is too large
Load Diff
@@ -1,188 +1,188 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#ifndef MSTP_H
|
||||
#define MSTP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacdef.h"
|
||||
#include "mstpdef.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
struct mstp_port_struct_t {
|
||||
MSTP_RECEIVE_STATE receive_state;
|
||||
/* When a master node is powered up or reset, */
|
||||
/* it shall unconditionally enter the INITIALIZE state. */
|
||||
MSTP_MASTER_STATE master_state;
|
||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||
/* if an error is detected during the reception of a frame. */
|
||||
/* Set to FALSE by the main state machine. */
|
||||
unsigned ReceiveError:1;
|
||||
/* There is data in the buffer */
|
||||
unsigned DataAvailable:1;
|
||||
unsigned ReceivedInvalidFrame:1;
|
||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||
/* if a valid frame is received. */
|
||||
/* Set to FALSE by the main state machine. */
|
||||
unsigned ReceivedValidFrame:1;
|
||||
/* A Boolean flag set to TRUE by the master machine if this node is the */
|
||||
/* only known master node. */
|
||||
unsigned SoleMaster:1;
|
||||
/* stores the latest received data */
|
||||
uint8_t DataRegister;
|
||||
/* Used to accumulate the CRC on the data field of a frame. */
|
||||
uint16_t DataCRC;
|
||||
/* Used to store the data length of a received frame. */
|
||||
unsigned DataLength;
|
||||
/* Used to store the destination address of a received frame. */
|
||||
uint8_t DestinationAddress;
|
||||
/* Used to count the number of received octets or errors. */
|
||||
/* This is used in the detection of link activity. */
|
||||
/* Compared to Nmin_octets */
|
||||
uint8_t EventCount;
|
||||
/* Used to store the frame type of a received frame. */
|
||||
uint8_t FrameType;
|
||||
/* The number of frames sent by this node during a single token hold. */
|
||||
/* When this counter reaches the value Nmax_info_frames, the node must */
|
||||
/* pass the token. */
|
||||
unsigned FrameCount;
|
||||
/* Used to accumulate the CRC on the header of a frame. */
|
||||
uint8_t HeaderCRC;
|
||||
/* Used as an index by the Receive State Machine, up to a maximum value of */
|
||||
/* InputBufferSize. */
|
||||
unsigned Index;
|
||||
/* An array of octets, used to store octets as they are received. */
|
||||
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
|
||||
/* The maximum size of a frame is 501 octets. */
|
||||
uint8_t *InputBuffer;
|
||||
/* "Next Station," the MAC address of the node to which This Station passes */
|
||||
/* the token. If the Next_Station is unknown, Next_Station shall be equal to */
|
||||
/* This_Station. */
|
||||
uint8_t Next_Station;
|
||||
/* "Poll Station," the MAC address of the node to which This Station last */
|
||||
/* sent a Poll For Master. This is used during token maintenance. */
|
||||
uint8_t Poll_Station;
|
||||
/* A counter of transmission retries used for Token and Poll For Master */
|
||||
/* transmission. */
|
||||
unsigned RetryCount;
|
||||
/* A timer with nominal 5 millisecond resolution used to measure and */
|
||||
/* generate silence on the medium between octets. It is incremented by a */
|
||||
/* timer process and is cleared by the Receive State Machine when activity */
|
||||
/* is detected and by the SendFrame procedure as each octet is transmitted. */
|
||||
/* Since the timer resolution is limited and the timer is not necessarily */
|
||||
/* synchronized to other machine events, a timer value of N will actually */
|
||||
/* denote intervals between N-1 and N */
|
||||
uint16_t SilenceTimer;
|
||||
|
||||
/* A timer used to measure and generate Reply Postponed frames. It is */
|
||||
/* incremented by a timer process and is cleared by the Master Node State */
|
||||
/* Machine when a Data Expecting Reply Answer activity is completed. */
|
||||
/* note: we always send a reply postponed since a message other than
|
||||
the reply may be in the transmit queue */
|
||||
/* uint16_t ReplyPostponedTimer; */
|
||||
|
||||
/* Used to store the Source Address of a received frame. */
|
||||
uint8_t SourceAddress;
|
||||
|
||||
/* The number of tokens received by this node. When this counter reaches the */
|
||||
/* value Npoll, the node polls the address range between TS and NS for */
|
||||
/* additional master nodes. TokenCount is set to zero at the end of the */
|
||||
/* polling process. */
|
||||
unsigned TokenCount;
|
||||
|
||||
/* "This Station," the MAC address of this node. TS is generally read from a */
|
||||
/* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */
|
||||
/* 0 to 254. The value 255 is used to denote broadcast when used as a */
|
||||
/* destination address but is not allowed as a value for TS. */
|
||||
uint8_t This_Station;
|
||||
|
||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||
/* maximum number of information frames the node may send before it must */
|
||||
/* pass the token. Max_Info_Frames may have different values on different */
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
unsigned Nmax_info_frames;
|
||||
|
||||
/* This parameter represents the value of the Max_Master property of the */
|
||||
/* node's Device object. The value of Max_Master specifies the highest */
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
unsigned Nmax_master;
|
||||
|
||||
/* An array of octets, used to store PDU octets prior to being transmitted. */
|
||||
/* This array is only used for APDU messages */
|
||||
uint8_t TxBuffer[MAX_MPDU];
|
||||
unsigned TxLength;
|
||||
uint8_t TxDestination;
|
||||
bool TxReady; /* true if ready to be sent or received */
|
||||
uint8_t TxFrameType; /* type of message - needed by MS/TP */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void MSTP_Init(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
bool MSTP_Master_Node_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
|
||||
/* returns true if line is active */
|
||||
bool MSTP_Line_Active(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
unsigned MSTP_Create_Frame(
|
||||
uint8_t * buffer, /* where frame is loaded */
|
||||
unsigned buffer_len, /* amount of space available */
|
||||
uint8_t frame_type, /* type of frame to send - see defines */
|
||||
uint8_t destination, /* destination address */
|
||||
uint8_t source, /* source address */
|
||||
uint8_t * data, /* any data to be sent - may be null */
|
||||
unsigned data_len); /* number of bytes of data (up to 501) */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#ifndef MSTP_H
|
||||
#define MSTP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacdef.h"
|
||||
#include "mstpdef.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
struct mstp_port_struct_t {
|
||||
MSTP_RECEIVE_STATE receive_state;
|
||||
/* When a master node is powered up or reset, */
|
||||
/* it shall unconditionally enter the INITIALIZE state. */
|
||||
MSTP_MASTER_STATE master_state;
|
||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||
/* if an error is detected during the reception of a frame. */
|
||||
/* Set to FALSE by the main state machine. */
|
||||
unsigned ReceiveError:1;
|
||||
/* There is data in the buffer */
|
||||
unsigned DataAvailable:1;
|
||||
unsigned ReceivedInvalidFrame:1;
|
||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||
/* if a valid frame is received. */
|
||||
/* Set to FALSE by the main state machine. */
|
||||
unsigned ReceivedValidFrame:1;
|
||||
/* A Boolean flag set to TRUE by the master machine if this node is the */
|
||||
/* only known master node. */
|
||||
unsigned SoleMaster:1;
|
||||
/* stores the latest received data */
|
||||
uint8_t DataRegister;
|
||||
/* Used to accumulate the CRC on the data field of a frame. */
|
||||
uint16_t DataCRC;
|
||||
/* Used to store the data length of a received frame. */
|
||||
unsigned DataLength;
|
||||
/* Used to store the destination address of a received frame. */
|
||||
uint8_t DestinationAddress;
|
||||
/* Used to count the number of received octets or errors. */
|
||||
/* This is used in the detection of link activity. */
|
||||
/* Compared to Nmin_octets */
|
||||
uint8_t EventCount;
|
||||
/* Used to store the frame type of a received frame. */
|
||||
uint8_t FrameType;
|
||||
/* The number of frames sent by this node during a single token hold. */
|
||||
/* When this counter reaches the value Nmax_info_frames, the node must */
|
||||
/* pass the token. */
|
||||
unsigned FrameCount;
|
||||
/* Used to accumulate the CRC on the header of a frame. */
|
||||
uint8_t HeaderCRC;
|
||||
/* Used as an index by the Receive State Machine, up to a maximum value of */
|
||||
/* InputBufferSize. */
|
||||
unsigned Index;
|
||||
/* An array of octets, used to store octets as they are received. */
|
||||
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
|
||||
/* The maximum size of a frame is 501 octets. */
|
||||
uint8_t *InputBuffer;
|
||||
/* "Next Station," the MAC address of the node to which This Station passes */
|
||||
/* the token. If the Next_Station is unknown, Next_Station shall be equal to */
|
||||
/* This_Station. */
|
||||
uint8_t Next_Station;
|
||||
/* "Poll Station," the MAC address of the node to which This Station last */
|
||||
/* sent a Poll For Master. This is used during token maintenance. */
|
||||
uint8_t Poll_Station;
|
||||
/* A counter of transmission retries used for Token and Poll For Master */
|
||||
/* transmission. */
|
||||
unsigned RetryCount;
|
||||
/* A timer with nominal 5 millisecond resolution used to measure and */
|
||||
/* generate silence on the medium between octets. It is incremented by a */
|
||||
/* timer process and is cleared by the Receive State Machine when activity */
|
||||
/* is detected and by the SendFrame procedure as each octet is transmitted. */
|
||||
/* Since the timer resolution is limited and the timer is not necessarily */
|
||||
/* synchronized to other machine events, a timer value of N will actually */
|
||||
/* denote intervals between N-1 and N */
|
||||
uint16_t SilenceTimer;
|
||||
|
||||
/* A timer used to measure and generate Reply Postponed frames. It is */
|
||||
/* incremented by a timer process and is cleared by the Master Node State */
|
||||
/* Machine when a Data Expecting Reply Answer activity is completed. */
|
||||
/* note: we always send a reply postponed since a message other than
|
||||
the reply may be in the transmit queue */
|
||||
/* uint16_t ReplyPostponedTimer; */
|
||||
|
||||
/* Used to store the Source Address of a received frame. */
|
||||
uint8_t SourceAddress;
|
||||
|
||||
/* The number of tokens received by this node. When this counter reaches the */
|
||||
/* value Npoll, the node polls the address range between TS and NS for */
|
||||
/* additional master nodes. TokenCount is set to zero at the end of the */
|
||||
/* polling process. */
|
||||
unsigned TokenCount;
|
||||
|
||||
/* "This Station," the MAC address of this node. TS is generally read from a */
|
||||
/* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */
|
||||
/* 0 to 254. The value 255 is used to denote broadcast when used as a */
|
||||
/* destination address but is not allowed as a value for TS. */
|
||||
uint8_t This_Station;
|
||||
|
||||
/* This parameter represents the value of the Max_Info_Frames property of */
|
||||
/* the node's Device object. The value of Max_Info_Frames specifies the */
|
||||
/* maximum number of information frames the node may send before it must */
|
||||
/* pass the token. Max_Info_Frames may have different values on different */
|
||||
/* nodes. This may be used to allocate more or less of the available link */
|
||||
/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */
|
||||
/* node, its value shall be 1. */
|
||||
unsigned Nmax_info_frames;
|
||||
|
||||
/* This parameter represents the value of the Max_Master property of the */
|
||||
/* node's Device object. The value of Max_Master specifies the highest */
|
||||
/* allowable address for master nodes. The value of Max_Master shall be */
|
||||
/* less than or equal to 127. If Max_Master is not writable in a node, */
|
||||
/* its value shall be 127. */
|
||||
unsigned Nmax_master;
|
||||
|
||||
/* An array of octets, used to store PDU octets prior to being transmitted. */
|
||||
/* This array is only used for APDU messages */
|
||||
uint8_t TxBuffer[MAX_MPDU];
|
||||
unsigned TxLength;
|
||||
uint8_t TxDestination;
|
||||
bool TxReady; /* true if ready to be sent or received */
|
||||
uint8_t TxFrameType; /* type of message - needed by MS/TP */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void MSTP_Init(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
bool MSTP_Master_Node_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
|
||||
/* returns true if line is active */
|
||||
bool MSTP_Line_Active(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
unsigned MSTP_Create_Frame(
|
||||
uint8_t * buffer, /* where frame is loaded */
|
||||
unsigned buffer_len, /* amount of space available */
|
||||
uint8_t frame_type, /* type of frame to send - see defines */
|
||||
uint8_t destination, /* destination address */
|
||||
uint8_t source, /* source address */
|
||||
uint8_t * data, /* any data to be sent - may be null */
|
||||
unsigned data_len); /* number of bytes of data (up to 501) */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
BACnet Stack - SourceForge.net
|
||||
Build for MPLAB IDE
|
||||
|
||||
These are some settings that are important when building
|
||||
the BACnet Stack using MPLAB IDE and MCC18 Compiler,
|
||||
|
||||
1. Add the files to the project that you need:
|
||||
abort.c, apdu.c, bacapp.c, bacdcode.c, bacerror.c,
|
||||
bacstr.c, crc.c, datetime.c, dcc.c, iam.c,
|
||||
npdu.c, rd.c, reject.c, rp.c, whois.c, wp.c
|
||||
|
||||
From ports/picxx: isr.c, main.c, rs485.c, mstp.c, dlmstp.c
|
||||
|
||||
From demo/object/: device.c or dev_tiny.c
|
||||
objects as needed: ai.c, ao.c, etc.
|
||||
|
||||
From demo/handler/: txbuf.c, h_dcc.c, h_rd.c, h_rp.c or h_rp_tiny.c
|
||||
Additional handlers as needed: h_wp.c
|
||||
|
||||
2. Project->Options->Project
|
||||
|
||||
General Tab: Include Path:
|
||||
C:\code\bacnet-stack\;C:\code\bacnet-stack\demo\handler\;C:\code\bacnet-stack\demo\object\;C:\code\bacnet-stack\ports\pic18f6720\
|
||||
|
||||
MPLAB C18 Tab: Memory Model:
|
||||
Code: Large Code Model
|
||||
Data: Large Data Model
|
||||
Stack: Multi-bank Model
|
||||
|
||||
MPLAB C18 Tab: General: Macro Definitions:
|
||||
PRINT_ENABLED=0
|
||||
BACDL_MSTP=1
|
||||
TSM_ENABLED=0
|
||||
BIG_ENDIAN=0
|
||||
|
||||
3. The linker script must reserve some extra stack space.
|
||||
|
||||
//DATABANK NAME=gpr12 START=0xC00 END=0xCFF
|
||||
//DATABANK NAME=gpr13 START=0xD00 END=0xDFF
|
||||
DATABANK NAME=stackreg START=0xC00 END=0xDFF PROTECTED
|
||||
|
||||
//STACK SIZE=0x100 RAM=gpr13
|
||||
STACK SIZE=0x200 RAM=stackreg
|
||||
|
||||
BACnet Stack - SourceForge.net
|
||||
Build for MPLAB IDE
|
||||
|
||||
These are some settings that are important when building
|
||||
the BACnet Stack using MPLAB IDE and MCC18 Compiler,
|
||||
|
||||
1. Add the files to the project that you need:
|
||||
abort.c, apdu.c, bacapp.c, bacdcode.c, bacerror.c,
|
||||
bacstr.c, crc.c, datetime.c, dcc.c, iam.c,
|
||||
npdu.c, rd.c, reject.c, rp.c, whois.c, wp.c
|
||||
|
||||
From ports/picxx: isr.c, main.c, rs485.c, mstp.c, dlmstp.c
|
||||
|
||||
From demo/object/: device.c or dev_tiny.c
|
||||
objects as needed: ai.c, ao.c, etc.
|
||||
|
||||
From demo/handler/: txbuf.c, h_dcc.c, h_rd.c, h_rp.c or h_rp_tiny.c
|
||||
Additional handlers as needed: h_wp.c
|
||||
|
||||
2. Project->Options->Project
|
||||
|
||||
General Tab: Include Path:
|
||||
C:\code\bacnet-stack\;C:\code\bacnet-stack\demo\handler\;C:\code\bacnet-stack\demo\object\;C:\code\bacnet-stack\ports\pic18f6720\
|
||||
|
||||
MPLAB C18 Tab: Memory Model:
|
||||
Code: Large Code Model
|
||||
Data: Large Data Model
|
||||
Stack: Multi-bank Model
|
||||
|
||||
MPLAB C18 Tab: General: Macro Definitions:
|
||||
PRINT_ENABLED=0
|
||||
BACDL_MSTP=1
|
||||
TSM_ENABLED=0
|
||||
BIG_ENDIAN=0
|
||||
|
||||
3. The linker script must reserve some extra stack space.
|
||||
|
||||
//DATABANK NAME=gpr12 START=0xC00 END=0xCFF
|
||||
//DATABANK NAME=gpr13 START=0xD00 END=0xDFF
|
||||
DATABANK NAME=stackreg START=0xC00 END=0xDFF PROTECTED
|
||||
|
||||
//STACK SIZE=0x100 RAM=gpr13
|
||||
STACK SIZE=0x200 RAM=stackreg
|
||||
|
||||
|
||||
@@ -1,353 +1,353 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* The module handles sending data out the RS-485 port */
|
||||
/* and handles receiving data from the RS-485 port. */
|
||||
/* Customize this file for your specific hardware */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "hardware.h"
|
||||
#include "mstp.h"
|
||||
#include "rs485.h"
|
||||
#include "fifo.h"
|
||||
|
||||
/* public port info */
|
||||
extern volatile struct mstp_port_struct_t MSTP_Port;
|
||||
|
||||
/* the baud rate is adjustable */
|
||||
uint32_t RS485_Baud_Rate = 38400;
|
||||
|
||||
/* the FIFO structures for sending and receiving */
|
||||
FIFO_BUFFER FIFO_Rx;
|
||||
FIFO_BUFFER FIFO_Tx;
|
||||
#pragma udata MSTPPortData
|
||||
/* the buffer for receiving data (size must be a power of 2) */
|
||||
volatile uint8_t RS485_Rx_Buffer[128];
|
||||
/* the buffer for sending data (size must be a power of 2) */
|
||||
volatile uint8_t RS485_Tx_Buffer[128];
|
||||
#pragma udata
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Transmits a frame using the UART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
uint16_t i = 0; /* loop counter */
|
||||
uint8_t turnaround_time;
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
while (!FIFO_Empty(&FIFO_Tx)) {
|
||||
/* buffer is not empty. Wait for ISR to transmit. */
|
||||
};
|
||||
|
||||
/* wait 40 bit times since reception */
|
||||
if (RS485_Baud_Rate == 9600)
|
||||
turnaround_time = 4;
|
||||
else if (RS485_Baud_Rate == 19200)
|
||||
turnaround_time = 2;
|
||||
else
|
||||
turnaround_time = 2;
|
||||
|
||||
while (mstp_port->SilenceTimer < turnaround_time) {
|
||||
/* The line has not been silent long enough, so wait. */
|
||||
};
|
||||
|
||||
if (FIFO_Add(&FIFO_Tx, buffer, nbytes)) {
|
||||
/* disable the receiver */
|
||||
PIE3bits.RC2IE = 0;
|
||||
RCSTA2bits.CREN = 0;
|
||||
/* enable the transceiver */
|
||||
RS485_TX_ENABLE = 1;
|
||||
RS485_RX_DISABLE = 1;
|
||||
/* enable the transmitter */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
PIE3bits.TX2IE = 1;
|
||||
/* reset the silence timer per MSTP spec, sort of */
|
||||
mstp_port->SilenceTimer = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Checks for data on the receive UART, and handles errors
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t * mstp_port)
|
||||
{
|
||||
/* check for data */
|
||||
if (!FIFO_Empty(&FIFO_Rx)) {
|
||||
mstp_port->DataRegister = FIFO_Get(&FIFO_Rx);
|
||||
mstp_port->DataAvailable = TRUE;
|
||||
}
|
||||
|
||||
return (!FIFO_Empty(&FIFO_Rx));
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Receives RS485 data stream
|
||||
|
||||
RETURN: none
|
||||
|
||||
ALGORITHM: none
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Rx(
|
||||
void)
|
||||
{
|
||||
uint8_t data_byte;
|
||||
|
||||
if ((RCSTA2bits.FERR) || (RCSTA2bits.OERR)) {
|
||||
/* Clear the error */
|
||||
RCSTA2bits.CREN = 0;
|
||||
RCSTA2bits.CREN = 1;
|
||||
/* FIXME: flag the MS/TP state machine on buffer overrun */
|
||||
data_byte = RCREG2;
|
||||
} else {
|
||||
data_byte = RCREG2;
|
||||
FIFO_Put(&FIFO_Rx, data_byte);
|
||||
}
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Transmits a byte using the UART out the RS485 port
|
||||
|
||||
RETURN: none
|
||||
|
||||
ALGORITHM: none
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Tx(
|
||||
void)
|
||||
{
|
||||
if (!FIFO_Empty(&FIFO_Tx)) {
|
||||
TXREG2 = FIFO_Get(&FIFO_Tx);
|
||||
} else {
|
||||
/* wait for the USART to be empty */
|
||||
while (!TXSTA2bits.TRMT);
|
||||
/* disable this interrupt */
|
||||
PIE3bits.TX2IE = 0;
|
||||
/* enable the receiver */
|
||||
RS485_TX_ENABLE = 0;
|
||||
RS485_RX_DISABLE = 0;
|
||||
/* enable the this interrupt */
|
||||
PIE3bits.RC2IE = 1;
|
||||
RCSTA2bits.CREN = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Returns the baud rate that we are currently running at
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Baud_Rate;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Sets the baud rate for the chip USART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 76800:
|
||||
case 115200:
|
||||
RS485_Baud_Rate = baud;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
/* FIXME: store the baud rate */
|
||||
/* I2C_Write_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&RS485_Baud_Rate,
|
||||
sizeof(RS485_Baud_Rate),
|
||||
EEPROM_MSTP_BAUD_RATE_ADDR); */
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in
|
||||
* receive mode.
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize_Port(
|
||||
void)
|
||||
{
|
||||
|
||||
/* Reset USART registers to POR state */
|
||||
TXSTA2 = 0;
|
||||
RCSTA2 = 0;
|
||||
/* configure USART for receiving */
|
||||
/* since the TX will handle setting up for transmit */
|
||||
RCSTA2bits.CREN = 1;
|
||||
/* Interrupt on receipt */
|
||||
PIE3bits.RC2IE = 1;
|
||||
/* enable the transmitter, disable its interrupt */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
PIE3bits.TX2IE = 0;
|
||||
/* setup USART Baud Rate Generator */
|
||||
/* see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book */
|
||||
/* Fosc=20MHz
|
||||
BRGH=1 BRGH=0
|
||||
Rate SPBRG Rate SPBRG
|
||||
------- ----- ------- -----
|
||||
9615 129 9469 32
|
||||
19230 64 19530 15
|
||||
37878 32 78130 3
|
||||
56818 21 104200 2
|
||||
113630 10 312500 0
|
||||
250000 4
|
||||
625000 1
|
||||
1250000 0
|
||||
*/
|
||||
switch (RS485_Baud_Rate) {
|
||||
case 19200:
|
||||
SPBRG2 = 64;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 38400:
|
||||
SPBRG2 = 32;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 57600:
|
||||
SPBRG2 = 21;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 76800:
|
||||
SPBRG2 = 3;
|
||||
TXSTA2bits.BRGH = 0;
|
||||
break;
|
||||
case 115200:
|
||||
SPBRG2 = 10;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 9600:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
default:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
RS485_Set_Baud_Rate(9600);
|
||||
break;
|
||||
}
|
||||
/* select async mode */
|
||||
TXSTA2bits.SYNC = 0;
|
||||
/* enable transmitter */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
/* serial port enable */
|
||||
RCSTA2bits.SPEN = 1;
|
||||
/* since we are using RS485,
|
||||
we need to explicitly say
|
||||
transmit enable or not */
|
||||
RS485_RX_DISABLE = 0;
|
||||
RS485_TX_ENABLE = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Disables the RS485 hardware
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Disable_Port(
|
||||
void)
|
||||
{
|
||||
RCSTA2 &= 0x4F; /* Disable the receiver */
|
||||
TXSTA2bits.TXEN = 0; /* and transmitter */
|
||||
PIE3 &= 0xCF; /* Disable both interrupts */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Reinitializes the port
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the data and the port
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
/* Init the Rs485 buffers */
|
||||
FIFO_Init(&FIFO_Rx, RS485_Rx_Buffer, sizeof(RS485_Rx_Buffer));
|
||||
FIFO_Init(&FIFO_Tx, RS485_Tx_Buffer, sizeof(RS485_Tx_Buffer));
|
||||
|
||||
/* FIXME: read the stored baud rate */
|
||||
/* I2C_Read_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&RS485_Baud_Rate,
|
||||
sizeof(RS485_Baud_Rate),
|
||||
EEPROM_MSTP_BAUD_RATE_ADDR); */
|
||||
|
||||
RS485_Initialize_Port();
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* The module handles sending data out the RS-485 port */
|
||||
/* and handles receiving data from the RS-485 port. */
|
||||
/* Customize this file for your specific hardware */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "hardware.h"
|
||||
#include "mstp.h"
|
||||
#include "rs485.h"
|
||||
#include "fifo.h"
|
||||
|
||||
/* public port info */
|
||||
extern volatile struct mstp_port_struct_t MSTP_Port;
|
||||
|
||||
/* the baud rate is adjustable */
|
||||
uint32_t RS485_Baud_Rate = 38400;
|
||||
|
||||
/* the FIFO structures for sending and receiving */
|
||||
FIFO_BUFFER FIFO_Rx;
|
||||
FIFO_BUFFER FIFO_Tx;
|
||||
#pragma udata MSTPPortData
|
||||
/* the buffer for receiving data (size must be a power of 2) */
|
||||
volatile uint8_t RS485_Rx_Buffer[128];
|
||||
/* the buffer for sending data (size must be a power of 2) */
|
||||
volatile uint8_t RS485_Tx_Buffer[128];
|
||||
#pragma udata
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Transmits a frame using the UART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
uint16_t i = 0; /* loop counter */
|
||||
uint8_t turnaround_time;
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
while (!FIFO_Empty(&FIFO_Tx)) {
|
||||
/* buffer is not empty. Wait for ISR to transmit. */
|
||||
};
|
||||
|
||||
/* wait 40 bit times since reception */
|
||||
if (RS485_Baud_Rate == 9600)
|
||||
turnaround_time = 4;
|
||||
else if (RS485_Baud_Rate == 19200)
|
||||
turnaround_time = 2;
|
||||
else
|
||||
turnaround_time = 2;
|
||||
|
||||
while (mstp_port->SilenceTimer < turnaround_time) {
|
||||
/* The line has not been silent long enough, so wait. */
|
||||
};
|
||||
|
||||
if (FIFO_Add(&FIFO_Tx, buffer, nbytes)) {
|
||||
/* disable the receiver */
|
||||
PIE3bits.RC2IE = 0;
|
||||
RCSTA2bits.CREN = 0;
|
||||
/* enable the transceiver */
|
||||
RS485_TX_ENABLE = 1;
|
||||
RS485_RX_DISABLE = 1;
|
||||
/* enable the transmitter */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
PIE3bits.TX2IE = 1;
|
||||
/* reset the silence timer per MSTP spec, sort of */
|
||||
mstp_port->SilenceTimer = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Checks for data on the receive UART, and handles errors
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t * mstp_port)
|
||||
{
|
||||
/* check for data */
|
||||
if (!FIFO_Empty(&FIFO_Rx)) {
|
||||
mstp_port->DataRegister = FIFO_Get(&FIFO_Rx);
|
||||
mstp_port->DataAvailable = TRUE;
|
||||
}
|
||||
|
||||
return (!FIFO_Empty(&FIFO_Rx));
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Receives RS485 data stream
|
||||
|
||||
RETURN: none
|
||||
|
||||
ALGORITHM: none
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Rx(
|
||||
void)
|
||||
{
|
||||
uint8_t data_byte;
|
||||
|
||||
if ((RCSTA2bits.FERR) || (RCSTA2bits.OERR)) {
|
||||
/* Clear the error */
|
||||
RCSTA2bits.CREN = 0;
|
||||
RCSTA2bits.CREN = 1;
|
||||
/* FIXME: flag the MS/TP state machine on buffer overrun */
|
||||
data_byte = RCREG2;
|
||||
} else {
|
||||
data_byte = RCREG2;
|
||||
FIFO_Put(&FIFO_Rx, data_byte);
|
||||
}
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Transmits a byte using the UART out the RS485 port
|
||||
|
||||
RETURN: none
|
||||
|
||||
ALGORITHM: none
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Tx(
|
||||
void)
|
||||
{
|
||||
if (!FIFO_Empty(&FIFO_Tx)) {
|
||||
TXREG2 = FIFO_Get(&FIFO_Tx);
|
||||
} else {
|
||||
/* wait for the USART to be empty */
|
||||
while (!TXSTA2bits.TRMT);
|
||||
/* disable this interrupt */
|
||||
PIE3bits.TX2IE = 0;
|
||||
/* enable the receiver */
|
||||
RS485_TX_ENABLE = 0;
|
||||
RS485_RX_DISABLE = 0;
|
||||
/* enable the this interrupt */
|
||||
PIE3bits.RC2IE = 1;
|
||||
RCSTA2bits.CREN = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Returns the baud rate that we are currently running at
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Baud_Rate;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Sets the baud rate for the chip USART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 76800:
|
||||
case 115200:
|
||||
RS485_Baud_Rate = baud;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
/* FIXME: store the baud rate */
|
||||
/* I2C_Write_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&RS485_Baud_Rate,
|
||||
sizeof(RS485_Baud_Rate),
|
||||
EEPROM_MSTP_BAUD_RATE_ADDR); */
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in
|
||||
* receive mode.
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize_Port(
|
||||
void)
|
||||
{
|
||||
|
||||
/* Reset USART registers to POR state */
|
||||
TXSTA2 = 0;
|
||||
RCSTA2 = 0;
|
||||
/* configure USART for receiving */
|
||||
/* since the TX will handle setting up for transmit */
|
||||
RCSTA2bits.CREN = 1;
|
||||
/* Interrupt on receipt */
|
||||
PIE3bits.RC2IE = 1;
|
||||
/* enable the transmitter, disable its interrupt */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
PIE3bits.TX2IE = 0;
|
||||
/* setup USART Baud Rate Generator */
|
||||
/* see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book */
|
||||
/* Fosc=20MHz
|
||||
BRGH=1 BRGH=0
|
||||
Rate SPBRG Rate SPBRG
|
||||
------- ----- ------- -----
|
||||
9615 129 9469 32
|
||||
19230 64 19530 15
|
||||
37878 32 78130 3
|
||||
56818 21 104200 2
|
||||
113630 10 312500 0
|
||||
250000 4
|
||||
625000 1
|
||||
1250000 0
|
||||
*/
|
||||
switch (RS485_Baud_Rate) {
|
||||
case 19200:
|
||||
SPBRG2 = 64;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 38400:
|
||||
SPBRG2 = 32;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 57600:
|
||||
SPBRG2 = 21;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 76800:
|
||||
SPBRG2 = 3;
|
||||
TXSTA2bits.BRGH = 0;
|
||||
break;
|
||||
case 115200:
|
||||
SPBRG2 = 10;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 9600:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
default:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
RS485_Set_Baud_Rate(9600);
|
||||
break;
|
||||
}
|
||||
/* select async mode */
|
||||
TXSTA2bits.SYNC = 0;
|
||||
/* enable transmitter */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
/* serial port enable */
|
||||
RCSTA2bits.SPEN = 1;
|
||||
/* since we are using RS485,
|
||||
we need to explicitly say
|
||||
transmit enable or not */
|
||||
RS485_RX_DISABLE = 0;
|
||||
RS485_TX_ENABLE = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Disables the RS485 hardware
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Disable_Port(
|
||||
void)
|
||||
{
|
||||
RCSTA2 &= 0x4F; /* Disable the receiver */
|
||||
TXSTA2bits.TXEN = 0; /* and transmitter */
|
||||
PIE3 &= 0xCF; /* Disable both interrupts */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Reinitializes the port
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the data and the port
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
/* Init the Rs485 buffers */
|
||||
FIFO_Init(&FIFO_Rx, RS485_Rx_Buffer, sizeof(RS485_Rx_Buffer));
|
||||
FIFO_Init(&FIFO_Tx, RS485_Tx_Buffer, sizeof(RS485_Tx_Buffer));
|
||||
|
||||
/* FIXME: read the stored baud rate */
|
||||
/* I2C_Read_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&RS485_Baud_Rate,
|
||||
sizeof(RS485_Baud_Rate),
|
||||
EEPROM_MSTP_BAUD_RATE_ADDR); */
|
||||
|
||||
RS485_Initialize_Port();
|
||||
}
|
||||
|
||||
@@ -1,80 +1,80 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#ifndef RS485_H
|
||||
#define RS485_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mstp.h"
|
||||
|
||||
extern uint32_t RS485_Baud_Rate;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Reinit(
|
||||
void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Disable(
|
||||
void);
|
||||
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
/* returns true if there is more data waiting */
|
||||
bool RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
|
||||
void RS485_Interrupt_Rx(
|
||||
void);
|
||||
|
||||
void RS485_Interrupt_Tx(
|
||||
void);
|
||||
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#ifndef RS485_H
|
||||
#define RS485_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mstp.h"
|
||||
|
||||
extern uint32_t RS485_Baud_Rate;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Reinit(
|
||||
void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Disable(
|
||||
void);
|
||||
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
/* returns true if there is more data waiting */
|
||||
bool RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
|
||||
void RS485_Interrupt_Rx(
|
||||
void);
|
||||
|
||||
void RS485_Interrupt_Tx(
|
||||
void);
|
||||
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef char _Bool;
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef char _Bool;
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
/* Defines the standard integer types that are used in code */
|
||||
|
||||
#ifndef STDINT_H
|
||||
#define STDINT_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t; /* 1 byte 0 to 255 */
|
||||
typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */
|
||||
typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
/* Defines the standard integer types that are used in code */
|
||||
|
||||
#ifndef STDINT_H
|
||||
#define STDINT_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t; /* 1 byte 0 to 255 */
|
||||
typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */
|
||||
typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,320 +1,320 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>CMSIS Changes</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 6.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<style>
|
||||
<!--
|
||||
/*-----------------------------------------------------------
|
||||
Keil Software CHM Style Sheet
|
||||
-----------------------------------------------------------*/
|
||||
body { color: #000000; background-color: #FFFFFF; font-size: 75%; font-family:
|
||||
Verdana, Arial, 'Sans Serif' }
|
||||
a:link { color: #0000FF; text-decoration: underline }
|
||||
a:visited { color: #0000FF; text-decoration: underline }
|
||||
a:active { color: #FF0000; text-decoration: underline }
|
||||
a:hover { color: #FF0000; text-decoration: underline }
|
||||
h1 { font-family: Verdana; font-size: 18pt; color: #000080; font-weight: bold;
|
||||
text-align: Center; margin-right: 3 }
|
||||
h2 { font-family: Verdana; font-size: 14pt; color: #000080; font-weight: bold;
|
||||
background-color: #CCCCCC; margin-top: 24; margin-bottom: 3;
|
||||
padding: 6 }
|
||||
h3 { font-family: Verdana; font-size: 10pt; font-weight: bold; background-color:
|
||||
#CCCCCC; margin-top: 24; margin-bottom: 3; padding: 6 }
|
||||
pre { font-family: Courier New; font-size: 10pt; background-color: #CCFFCC;
|
||||
margin-left: 24; margin-right: 24 }
|
||||
ul { list-style-type: square; margin-top: 6pt; margin-bottom: 0 }
|
||||
ol { margin-top: 6pt; margin-bottom: 0 }
|
||||
li { clear: both; margin-bottom: 6pt }
|
||||
table { font-size: 100%; border-width: 0; padding: 0 }
|
||||
th { color: #FFFFFF; background-color: #000080; text-align: left; vertical-align:
|
||||
bottom; padding-right: 6pt }
|
||||
tr { text-align: left; vertical-align: top }
|
||||
td { text-align: left; vertical-align: top; padding-right: 6pt }
|
||||
.ToolT { font-size: 8pt; color: #808080 }
|
||||
.TinyT { font-size: 8pt; text-align: Center }
|
||||
code { color: #000000; background-color: #E0E0E0; font-family: 'Courier New', Courier;
|
||||
line-height: 120%; font-style: normal }
|
||||
/*-----------------------------------------------------------
|
||||
Notes
|
||||
-----------------------------------------------------------*/
|
||||
p.note { font-weight: bold; clear: both; margin-bottom: 3pt; padding-top: 6pt }
|
||||
/*-----------------------------------------------------------
|
||||
Expanding/Contracting Divisions
|
||||
-----------------------------------------------------------*/
|
||||
#expand { text-decoration: none; margin-bottom: 3pt }
|
||||
img.expand { border-style: none; border-width: medium }
|
||||
div.expand { display: none; margin-left: 9pt; margin-top: 0 }
|
||||
/*-----------------------------------------------------------
|
||||
Where List Tags
|
||||
-----------------------------------------------------------*/
|
||||
p.wh { font-weight: bold; clear: both; margin-top: 6pt; margin-bottom: 3pt }
|
||||
table.wh { width: 100% }
|
||||
td.whItem { white-space: nowrap; font-style: italic; padding-right: 6pt; padding-bottom:
|
||||
6pt }
|
||||
td.whDesc { padding-bottom: 6pt }
|
||||
/*-----------------------------------------------------------
|
||||
Keil Table Tags
|
||||
-----------------------------------------------------------*/
|
||||
table.kt { border: 1pt solid #000000 }
|
||||
th.kt { white-space: nowrap; border-bottom: 1pt solid #000000; padding-left: 6pt;
|
||||
padding-right: 6pt; padding-top: 4pt; padding-bottom: 4pt }
|
||||
tr.kt { }
|
||||
td.kt { color: #000000; background-color: #E0E0E0; border-top: 1pt solid #A0A0A0;
|
||||
padding-left: 6pt; padding-right: 6pt; padding-top: 2pt;
|
||||
padding-bottom: 2pt }
|
||||
/*-----------------------------------------------------------
|
||||
-----------------------------------------------------------*/
|
||||
-->
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Changes to CMSIS version V1.20</h1>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>1. Removed CMSIS Middelware packages</h2>
|
||||
<p>
|
||||
CMSIS Middleware is on hold from ARM side until a agreement between all CMSIS partners is found.
|
||||
</p>
|
||||
|
||||
<h2>2. SystemFrequency renamed to SystemCoreClock</h2>
|
||||
<p>
|
||||
The variable name <strong>SystemCoreClock</strong> is more precise than <strong>SystemFrequency</strong>
|
||||
because the variable holds the clock value at which the core is running.
|
||||
</p>
|
||||
|
||||
<h2>3. Changed startup concept</h2>
|
||||
<p>
|
||||
The old startup concept (calling SystemInit_ExtMemCtl from startup file and calling SystemInit
|
||||
from main) has the weakness that it does not work for controllers which need a already
|
||||
configuerd clock system to configure the external memory controller.
|
||||
</p>
|
||||
|
||||
<h3>Changed startup concept</h3>
|
||||
<ul>
|
||||
<li>
|
||||
SystemInit() is called from startup file before <strong>premain</strong>.
|
||||
</li>
|
||||
<li>
|
||||
<strong>SystemInit()</strong> configures the clock system and also configures
|
||||
an existing external memory controller.
|
||||
</li>
|
||||
<li>
|
||||
<strong>SystemInit()</strong> must not use global variables.
|
||||
</li>
|
||||
<li>
|
||||
<strong>SystemCoreClock</strong> is initialized with a correct predefined value.
|
||||
</li>
|
||||
<li>
|
||||
Additional function <strong>void SystemCoreClockUpdate (void)</strong> is provided.<br>
|
||||
<strong>SystemCoreClockUpdate()</strong> updates the variable <strong>SystemCoreClock</strong>
|
||||
and must be called whenever the core clock is changed.<br>
|
||||
<strong>SystemCoreClockUpdate()</strong> evaluates the clock register settings and calculates
|
||||
the current core clock.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>4. Advanced Debug Functions</h2>
|
||||
<p>
|
||||
ITM communication channel is only capable for OUT direction. To allow also communication for
|
||||
IN direction a simple concept is provided.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Global variable <strong>volatile int ITM_RxBuffer</strong> used for IN data.
|
||||
</li>
|
||||
<li>
|
||||
Function <strong>int ITM_CheckChar (void)</strong> checks if a new character is available.
|
||||
</li>
|
||||
<li>
|
||||
Function <strong>int ITM_ReceiveChar (void)</strong> retrieves the new character.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
For detailed explanation see file <strong>CMSIS debug support.htm</strong>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2>5. Core Register Bit Definitions</h2>
|
||||
<p>
|
||||
Files core_cm3.h and core_cm0.h contain now bit definitions for Core Registers. The name for the
|
||||
defines correspond with the Cortex-M Technical Reference Manual.
|
||||
</p>
|
||||
<p>
|
||||
e.g. SysTick structure with bit definitions
|
||||
</p>
|
||||
<pre>
|
||||
/** @addtogroup CMSIS_CM3_SysTick CMSIS CM3 SysTick
|
||||
memory mapped structure for SysTick
|
||||
@{
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */
|
||||
__IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */
|
||||
__IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */
|
||||
__I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */
|
||||
} SysTick_Type;
|
||||
|
||||
/* SysTick Control / Status Register Definitions */
|
||||
#define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */
|
||||
#define SysTick_CTRL_COUNTFLAG_Msk (1ul << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
|
||||
|
||||
#define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */
|
||||
#define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
|
||||
|
||||
#define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */
|
||||
#define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
|
||||
|
||||
#define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */
|
||||
#define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */
|
||||
|
||||
/* SysTick Reload Register Definitions */
|
||||
#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
|
||||
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
|
||||
|
||||
/* SysTick Current Register Definitions */
|
||||
#define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */
|
||||
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */
|
||||
|
||||
/* SysTick Calibration Register Definitions */
|
||||
#define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */
|
||||
#define SysTick_CALIB_NOREF_Msk (1ul << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
|
||||
|
||||
#define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */
|
||||
#define SysTick_CALIB_SKEW_Msk (1ul << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
|
||||
|
||||
#define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */
|
||||
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */
|
||||
/*@}*/ /* end of group CMSIS_CM3_SysTick */</pre>
|
||||
|
||||
<h2>7. DoxyGen Tags</h2>
|
||||
<p>
|
||||
DoxyGen tags in files core_cm3.[c,h] and core_cm0.[c,h] are reworked to create proper documentation
|
||||
using DoxyGen.
|
||||
</p>
|
||||
|
||||
<h2>8. Folder Structure</h2>
|
||||
<p>
|
||||
The folder structure is changed to differentiate the single support packages.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>CM0</li>
|
||||
<li>CM3
|
||||
<ul>
|
||||
<li>CoreSupport</li>
|
||||
<li>DeviceSupport</li>
|
||||
<ul>
|
||||
<li>Vendor
|
||||
<ul>
|
||||
<li>Device
|
||||
<ul>
|
||||
<li>Startup
|
||||
<ul>
|
||||
<li>Toolchain</li>
|
||||
<li>Toolchain</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Device</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Vendor</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Example
|
||||
<ul>
|
||||
<li>Toolchain
|
||||
<ul>
|
||||
<li>Device</li>
|
||||
<li>Device</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Toolchain</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Documentation</li>
|
||||
</ul>
|
||||
|
||||
<h2>9. Open Points</h2>
|
||||
<p>
|
||||
Following points need to be clarified and solved:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
Equivalent C and Assembler startup files.
|
||||
</p>
|
||||
<p>
|
||||
Is there a need for having C startup files although assembler startup files are
|
||||
very efficient and do not need to be changed?
|
||||
<p/>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Placing of HEAP in external RAM.
|
||||
</p>
|
||||
<p>
|
||||
It must be possible to place HEAP in external RAM if the device supports an
|
||||
external memory controller.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Placing of STACK /HEAP.
|
||||
</p>
|
||||
<p>
|
||||
STACK should always be placed at the end of internal RAM.
|
||||
</p>
|
||||
<p>
|
||||
If HEAP is placed in internal RAM than it should be placed after RW ZI section.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Removing core_cm3.c and core_cm0.c.
|
||||
</p>
|
||||
<p>
|
||||
On a long term the functions in core_cm3.c and core_cm0.c must be replaced with
|
||||
appropriate compiler intrinsics.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>10. Limitations</h2>
|
||||
<p>
|
||||
The following limitations are not covered with the current CMSIS version:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
No <strong>C startup files</strong> for ARM toolchain are provided.
|
||||
</li>
|
||||
<li>
|
||||
No <strong>C startup files</strong> for GNU toolchain are provided.
|
||||
</li>
|
||||
<li>
|
||||
No <strong>C startup files</strong> for IAR toolchain are provided.
|
||||
</li>
|
||||
<li>
|
||||
No <strong>Tasking</strong> projects are provided yet.
|
||||
</li>
|
||||
</ul>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>CMSIS Changes</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 6.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<style>
|
||||
<!--
|
||||
/*-----------------------------------------------------------
|
||||
Keil Software CHM Style Sheet
|
||||
-----------------------------------------------------------*/
|
||||
body { color: #000000; background-color: #FFFFFF; font-size: 75%; font-family:
|
||||
Verdana, Arial, 'Sans Serif' }
|
||||
a:link { color: #0000FF; text-decoration: underline }
|
||||
a:visited { color: #0000FF; text-decoration: underline }
|
||||
a:active { color: #FF0000; text-decoration: underline }
|
||||
a:hover { color: #FF0000; text-decoration: underline }
|
||||
h1 { font-family: Verdana; font-size: 18pt; color: #000080; font-weight: bold;
|
||||
text-align: Center; margin-right: 3 }
|
||||
h2 { font-family: Verdana; font-size: 14pt; color: #000080; font-weight: bold;
|
||||
background-color: #CCCCCC; margin-top: 24; margin-bottom: 3;
|
||||
padding: 6 }
|
||||
h3 { font-family: Verdana; font-size: 10pt; font-weight: bold; background-color:
|
||||
#CCCCCC; margin-top: 24; margin-bottom: 3; padding: 6 }
|
||||
pre { font-family: Courier New; font-size: 10pt; background-color: #CCFFCC;
|
||||
margin-left: 24; margin-right: 24 }
|
||||
ul { list-style-type: square; margin-top: 6pt; margin-bottom: 0 }
|
||||
ol { margin-top: 6pt; margin-bottom: 0 }
|
||||
li { clear: both; margin-bottom: 6pt }
|
||||
table { font-size: 100%; border-width: 0; padding: 0 }
|
||||
th { color: #FFFFFF; background-color: #000080; text-align: left; vertical-align:
|
||||
bottom; padding-right: 6pt }
|
||||
tr { text-align: left; vertical-align: top }
|
||||
td { text-align: left; vertical-align: top; padding-right: 6pt }
|
||||
.ToolT { font-size: 8pt; color: #808080 }
|
||||
.TinyT { font-size: 8pt; text-align: Center }
|
||||
code { color: #000000; background-color: #E0E0E0; font-family: 'Courier New', Courier;
|
||||
line-height: 120%; font-style: normal }
|
||||
/*-----------------------------------------------------------
|
||||
Notes
|
||||
-----------------------------------------------------------*/
|
||||
p.note { font-weight: bold; clear: both; margin-bottom: 3pt; padding-top: 6pt }
|
||||
/*-----------------------------------------------------------
|
||||
Expanding/Contracting Divisions
|
||||
-----------------------------------------------------------*/
|
||||
#expand { text-decoration: none; margin-bottom: 3pt }
|
||||
img.expand { border-style: none; border-width: medium }
|
||||
div.expand { display: none; margin-left: 9pt; margin-top: 0 }
|
||||
/*-----------------------------------------------------------
|
||||
Where List Tags
|
||||
-----------------------------------------------------------*/
|
||||
p.wh { font-weight: bold; clear: both; margin-top: 6pt; margin-bottom: 3pt }
|
||||
table.wh { width: 100% }
|
||||
td.whItem { white-space: nowrap; font-style: italic; padding-right: 6pt; padding-bottom:
|
||||
6pt }
|
||||
td.whDesc { padding-bottom: 6pt }
|
||||
/*-----------------------------------------------------------
|
||||
Keil Table Tags
|
||||
-----------------------------------------------------------*/
|
||||
table.kt { border: 1pt solid #000000 }
|
||||
th.kt { white-space: nowrap; border-bottom: 1pt solid #000000; padding-left: 6pt;
|
||||
padding-right: 6pt; padding-top: 4pt; padding-bottom: 4pt }
|
||||
tr.kt { }
|
||||
td.kt { color: #000000; background-color: #E0E0E0; border-top: 1pt solid #A0A0A0;
|
||||
padding-left: 6pt; padding-right: 6pt; padding-top: 2pt;
|
||||
padding-bottom: 2pt }
|
||||
/*-----------------------------------------------------------
|
||||
-----------------------------------------------------------*/
|
||||
-->
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>Changes to CMSIS version V1.20</h1>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>1. Removed CMSIS Middelware packages</h2>
|
||||
<p>
|
||||
CMSIS Middleware is on hold from ARM side until a agreement between all CMSIS partners is found.
|
||||
</p>
|
||||
|
||||
<h2>2. SystemFrequency renamed to SystemCoreClock</h2>
|
||||
<p>
|
||||
The variable name <strong>SystemCoreClock</strong> is more precise than <strong>SystemFrequency</strong>
|
||||
because the variable holds the clock value at which the core is running.
|
||||
</p>
|
||||
|
||||
<h2>3. Changed startup concept</h2>
|
||||
<p>
|
||||
The old startup concept (calling SystemInit_ExtMemCtl from startup file and calling SystemInit
|
||||
from main) has the weakness that it does not work for controllers which need a already
|
||||
configuerd clock system to configure the external memory controller.
|
||||
</p>
|
||||
|
||||
<h3>Changed startup concept</h3>
|
||||
<ul>
|
||||
<li>
|
||||
SystemInit() is called from startup file before <strong>premain</strong>.
|
||||
</li>
|
||||
<li>
|
||||
<strong>SystemInit()</strong> configures the clock system and also configures
|
||||
an existing external memory controller.
|
||||
</li>
|
||||
<li>
|
||||
<strong>SystemInit()</strong> must not use global variables.
|
||||
</li>
|
||||
<li>
|
||||
<strong>SystemCoreClock</strong> is initialized with a correct predefined value.
|
||||
</li>
|
||||
<li>
|
||||
Additional function <strong>void SystemCoreClockUpdate (void)</strong> is provided.<br>
|
||||
<strong>SystemCoreClockUpdate()</strong> updates the variable <strong>SystemCoreClock</strong>
|
||||
and must be called whenever the core clock is changed.<br>
|
||||
<strong>SystemCoreClockUpdate()</strong> evaluates the clock register settings and calculates
|
||||
the current core clock.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>4. Advanced Debug Functions</h2>
|
||||
<p>
|
||||
ITM communication channel is only capable for OUT direction. To allow also communication for
|
||||
IN direction a simple concept is provided.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Global variable <strong>volatile int ITM_RxBuffer</strong> used for IN data.
|
||||
</li>
|
||||
<li>
|
||||
Function <strong>int ITM_CheckChar (void)</strong> checks if a new character is available.
|
||||
</li>
|
||||
<li>
|
||||
Function <strong>int ITM_ReceiveChar (void)</strong> retrieves the new character.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
For detailed explanation see file <strong>CMSIS debug support.htm</strong>.
|
||||
</p>
|
||||
|
||||
|
||||
<h2>5. Core Register Bit Definitions</h2>
|
||||
<p>
|
||||
Files core_cm3.h and core_cm0.h contain now bit definitions for Core Registers. The name for the
|
||||
defines correspond with the Cortex-M Technical Reference Manual.
|
||||
</p>
|
||||
<p>
|
||||
e.g. SysTick structure with bit definitions
|
||||
</p>
|
||||
<pre>
|
||||
/** @addtogroup CMSIS_CM3_SysTick CMSIS CM3 SysTick
|
||||
memory mapped structure for SysTick
|
||||
@{
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
__IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */
|
||||
__IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */
|
||||
__IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */
|
||||
__I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */
|
||||
} SysTick_Type;
|
||||
|
||||
/* SysTick Control / Status Register Definitions */
|
||||
#define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */
|
||||
#define SysTick_CTRL_COUNTFLAG_Msk (1ul << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
|
||||
|
||||
#define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */
|
||||
#define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
|
||||
|
||||
#define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */
|
||||
#define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
|
||||
|
||||
#define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */
|
||||
#define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */
|
||||
|
||||
/* SysTick Reload Register Definitions */
|
||||
#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
|
||||
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
|
||||
|
||||
/* SysTick Current Register Definitions */
|
||||
#define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */
|
||||
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */
|
||||
|
||||
/* SysTick Calibration Register Definitions */
|
||||
#define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */
|
||||
#define SysTick_CALIB_NOREF_Msk (1ul << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
|
||||
|
||||
#define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */
|
||||
#define SysTick_CALIB_SKEW_Msk (1ul << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
|
||||
|
||||
#define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */
|
||||
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */
|
||||
/*@}*/ /* end of group CMSIS_CM3_SysTick */</pre>
|
||||
|
||||
<h2>7. DoxyGen Tags</h2>
|
||||
<p>
|
||||
DoxyGen tags in files core_cm3.[c,h] and core_cm0.[c,h] are reworked to create proper documentation
|
||||
using DoxyGen.
|
||||
</p>
|
||||
|
||||
<h2>8. Folder Structure</h2>
|
||||
<p>
|
||||
The folder structure is changed to differentiate the single support packages.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>CM0</li>
|
||||
<li>CM3
|
||||
<ul>
|
||||
<li>CoreSupport</li>
|
||||
<li>DeviceSupport</li>
|
||||
<ul>
|
||||
<li>Vendor
|
||||
<ul>
|
||||
<li>Device
|
||||
<ul>
|
||||
<li>Startup
|
||||
<ul>
|
||||
<li>Toolchain</li>
|
||||
<li>Toolchain</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Device</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Vendor</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Example
|
||||
<ul>
|
||||
<li>Toolchain
|
||||
<ul>
|
||||
<li>Device</li>
|
||||
<li>Device</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Toolchain</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li>Documentation</li>
|
||||
</ul>
|
||||
|
||||
<h2>9. Open Points</h2>
|
||||
<p>
|
||||
Following points need to be clarified and solved:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>
|
||||
Equivalent C and Assembler startup files.
|
||||
</p>
|
||||
<p>
|
||||
Is there a need for having C startup files although assembler startup files are
|
||||
very efficient and do not need to be changed?
|
||||
<p/>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Placing of HEAP in external RAM.
|
||||
</p>
|
||||
<p>
|
||||
It must be possible to place HEAP in external RAM if the device supports an
|
||||
external memory controller.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Placing of STACK /HEAP.
|
||||
</p>
|
||||
<p>
|
||||
STACK should always be placed at the end of internal RAM.
|
||||
</p>
|
||||
<p>
|
||||
If HEAP is placed in internal RAM than it should be placed after RW ZI section.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>
|
||||
Removing core_cm3.c and core_cm0.c.
|
||||
</p>
|
||||
<p>
|
||||
On a long term the functions in core_cm3.c and core_cm0.c must be replaced with
|
||||
appropriate compiler intrinsics.
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>10. Limitations</h2>
|
||||
<p>
|
||||
The following limitations are not covered with the current CMSIS version:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
No <strong>C startup files</strong> for ARM toolchain are provided.
|
||||
</li>
|
||||
<li>
|
||||
No <strong>C startup files</strong> for GNU toolchain are provided.
|
||||
</li>
|
||||
<li>
|
||||
No <strong>C startup files</strong> for IAR toolchain are provided.
|
||||
</li>
|
||||
<li>
|
||||
No <strong>Tasking</strong> projects are provided yet.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,97 +1,97 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f10x.h
|
||||
* @author MCD Application Team
|
||||
* @version V3.4.0
|
||||
* @date 10/15/2010
|
||||
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Header File.
|
||||
******************************************************************************
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2010 STMicroelectronics</center></h2>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f10x_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Define to prevent recursive inclusion
|
||||
*/
|
||||
#ifndef __SYSTEM_STM32F10X_H
|
||||
#define __SYSTEM_STM32F10X_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @addtogroup STM32F10x_System_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_types
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Constants
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern void SystemInit(void);
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__SYSTEM_STM32F10X_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f10x.h
|
||||
* @author MCD Application Team
|
||||
* @version V3.4.0
|
||||
* @date 10/15/2010
|
||||
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Header File.
|
||||
******************************************************************************
|
||||
*
|
||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||
*
|
||||
* <h2><center>© COPYRIGHT 2010 STMicroelectronics</center></h2>
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f10x_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Define to prevent recursive inclusion
|
||||
*/
|
||||
#ifndef __SYSTEM_STM32F10X_H
|
||||
#define __SYSTEM_STM32F10X_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @addtogroup STM32F10x_System_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_types
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Constants
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern void SystemInit(void);
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__SYSTEM_STM32F10X_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user