Changed WhoHas and I-Have to use CharacterString instead of forcing ANSI X34 and C Strings. Affected all demos and ports object name, so I changed the object name function name to make sure it was noticed.
This commit is contained in:
@@ -22,8 +22,12 @@ BACNET_FLAGS += -DCRC_USE_TABLE
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_DEMO = ../../demo
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_OBJECT = ../../demo/object
|
||||
BACNET_HANDLER = ../../demo/handler
|
||||
INCLUDES = -I.
|
||||
INCLUDES += -I$(BACNET_INCLUDE)
|
||||
INCLUDES += -I$(BACNET_OBJECT)
|
||||
INCLUDES += -I$(BACNET_HANDLER)
|
||||
#OPTIMIZATION = -O0
|
||||
OPTIMIZATION = -Os
|
||||
CFLAGS = -fno-common $(INCLUDES) $(BACNET_FLAGS) -Wall -g
|
||||
|
||||
@@ -107,17 +107,19 @@ uint32_t Analog_Input_Index_To_Instance(
|
||||
return index;
|
||||
}
|
||||
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance)
|
||||
bool Analog_Input_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[16] = "AI-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
float Analog_Input_Present_Value(
|
||||
@@ -165,8 +167,7 @@ int Analog_Input_Read_Property(
|
||||
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));
|
||||
Analog_Input_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
@@ -165,18 +165,19 @@ float Analog_Value_Present_Value(
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
bool Analog_Value_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[16] = "AV-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ANALOG_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
@@ -208,8 +209,7 @@ int Analog_Value_Read_Property(
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(rpdata->object_instance));
|
||||
Analog_Value_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
@@ -144,17 +144,19 @@ BACNET_BINARY_PV Binary_Input_Present_Value(
|
||||
return value;
|
||||
}
|
||||
|
||||
char *Binary_Input_Name(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Input_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[16] = "BI-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
@@ -182,9 +184,7 @@ int Binary_Input_Read_Property(
|
||||
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));
|
||||
Binary_Input_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
@@ -139,17 +139,19 @@ static BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Value_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[16] = "BV-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
@@ -179,8 +181,7 @@ int Binary_Value_Read_Property(
|
||||
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));
|
||||
Binary_Value_Object_Name(rpdata->object_instance, &char_string);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
|
||||
@@ -25,13 +25,15 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacstr.h"
|
||||
#include "bacenum.h"
|
||||
#include "apdu.h"
|
||||
#include "dlmstp.h"
|
||||
#include "dcc.h"
|
||||
#include "datalink.h"
|
||||
#include "rs485.h"
|
||||
#include "version.h"
|
||||
#include "handlers.h"
|
||||
@@ -44,16 +46,7 @@
|
||||
#include "wp.h"
|
||||
#include "dcc.h"
|
||||
|
||||
/* note: you really only need to define variables for
|
||||
properties that are writable or that may change.
|
||||
The properties that are constant can be hard coded
|
||||
into the read-property encoding. */
|
||||
static uint32_t Object_Instance_Number = 12345;
|
||||
static char My_Object_Name[32] = "ARM7 Device";
|
||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
|
||||
|
||||
/* forward prototypes */
|
||||
/* forward prototype */
|
||||
int Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Device_Write_Property_Local(
|
||||
@@ -73,28 +66,38 @@ static struct my_object_functions {
|
||||
{
|
||||
OBJECT_DEVICE, NULL, /* don't init - recursive! */
|
||||
Device_Count, Device_Index_To_Instance,
|
||||
Device_Valid_Object_Instance_Number, Device_Name,
|
||||
Device_Valid_Object_Instance_Number, Device_Object_Name,
|
||||
Device_Read_Property_Local, Device_Write_Property_Local,
|
||||
Device_Property_Lists}, {
|
||||
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
|
||||
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
|
||||
Analog_Input_Name, Analog_Input_Read_Property, NULL,
|
||||
Analog_Input_Object_Name, Analog_Input_Read_Property, NULL,
|
||||
Analog_Input_Property_Lists}, {
|
||||
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,
|
||||
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance,
|
||||
Analog_Value_Name, Analog_Value_Read_Property,
|
||||
Analog_Value_Object_Name, Analog_Value_Read_Property,
|
||||
Analog_Value_Write_Property, Analog_Value_Property_Lists}, {
|
||||
OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count,
|
||||
Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance,
|
||||
Binary_Input_Name, Binary_Input_Read_Property, NULL,
|
||||
Binary_Input_Object_Name, Binary_Input_Read_Property, NULL,
|
||||
Binary_Input_Property_Lists}, {
|
||||
OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count,
|
||||
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance,
|
||||
Binary_Value_Name, Binary_Value_Read_Property,
|
||||
Binary_Value_Object_Name, Binary_Value_Read_Property,
|
||||
Binary_Value_Write_Property, Binary_Value_Property_Lists}, {
|
||||
MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/* note: you really only need to define variables for
|
||||
properties that are writable or that may change.
|
||||
The properties that are constant can be hard coded
|
||||
into the read-property encoding. */
|
||||
static uint32_t Object_Instance_Number;
|
||||
static BACNET_CHARACTER_STRING My_Object_Name;
|
||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||
static uint32_t Database_Revision;
|
||||
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Device_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
@@ -132,54 +135,92 @@ static const int Device_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Device_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
static struct my_object_functions *Device_Objects_Find_Functions(
|
||||
BACNET_OBJECT_TYPE Object_Type)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Device_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Device_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Device_Properties_Proprietary;
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
return;
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
/* handle each object type */
|
||||
if (pObject->Object_Type == Object_Type) {
|
||||
return (pObject);
|
||||
}
|
||||
|
||||
pObject++;
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int Read_Property_Common(
|
||||
struct my_object_functions *pObject,
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = BACNET_STATUS_ERROR;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
/* Device Object exception: requested instance
|
||||
may not match our instance if a wildcard */
|
||||
if (rpdata->object_type == OBJECT_DEVICE) {
|
||||
rpdata->object_instance = Object_Instance_Number;
|
||||
}
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], rpdata->object_type,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (pObject->Object_Name) {
|
||||
(void)pObject->Object_Name(
|
||||
rpdata->object_instance,
|
||||
&char_string);
|
||||
} else {
|
||||
characterstring_init_ansi(&char_string, "");
|
||||
}
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], rpdata->object_type);
|
||||
break;
|
||||
default:
|
||||
if (pObject->Object_Read_Property) {
|
||||
apdu_len = pObject->Object_Read_Property(rpdata);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* Encodes the property APDU and returns the length,
|
||||
or sets the error, and returns -1 */
|
||||
or sets the error, and returns BACNET_STATUS_ERROR */
|
||||
int Device_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = BACNET_STATUS_ERROR;
|
||||
unsigned index = 0;
|
||||
struct my_object_functions *pObject = NULL;
|
||||
bool found = false;
|
||||
|
||||
/* initialize the default return values */
|
||||
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
/* handle each object type */
|
||||
if (pObject->Object_Type == rpdata->object_type) {
|
||||
found = true;
|
||||
pObject = Device_Objects_Find_Functions(rpdata->object_type);
|
||||
if (pObject) {
|
||||
if (pObject->Object_Valid_Instance &&
|
||||
pObject->Object_Valid_Instance(rpdata->object_instance)) {
|
||||
if (pObject->Object_Read_Property) {
|
||||
apdu_len = pObject->Object_Read_Property(rpdata);
|
||||
}
|
||||
apdu_len = Read_Property_Common(pObject, rpdata);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
pObject = &Object_Table[index];
|
||||
}
|
||||
if (!found) {
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||
rpdata->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
|
||||
}
|
||||
@@ -191,18 +232,11 @@ bool Device_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned index = 0;
|
||||
struct my_object_functions *pObject = NULL;
|
||||
bool found = false;
|
||||
|
||||
/* initialize the default return values */
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
/* handle each object type */
|
||||
if (pObject->Object_Type == wp_data->object_type) {
|
||||
found = true;
|
||||
pObject = Device_Objects_Find_Functions(wp_data->object_type);
|
||||
if (pObject) {
|
||||
if (pObject->Object_Valid_Instance &&
|
||||
pObject->Object_Valid_Instance(wp_data->object_instance)) {
|
||||
if (pObject->Object_Write_Property) {
|
||||
@@ -215,12 +249,7 @@ bool Device_Write_Property(
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
pObject = &Object_Table[index];
|
||||
}
|
||||
if (!found) {
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
|
||||
}
|
||||
@@ -248,59 +277,222 @@ void Device_Objects_Property_List(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
struct special_property_list_t *pPropertyList)
|
||||
{
|
||||
rpm_property_lists_function object_property_list = NULL;
|
||||
unsigned index = 0;
|
||||
struct my_object_functions *pObject = NULL;
|
||||
bool found = false;
|
||||
|
||||
pPropertyList->Required.pList = NULL;
|
||||
pPropertyList->Optional.pList = NULL;
|
||||
pPropertyList->Proprietary.pList = NULL;
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
/* handle each object type */
|
||||
if (pObject->Object_Type == object_type) {
|
||||
found = true;
|
||||
object_property_list = pObject->Object_RPM_List;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
pObject = &Object_Table[index];
|
||||
}
|
||||
if (found && object_property_list) {
|
||||
object_property_list(&pPropertyList->Required.pList,
|
||||
|
||||
/* If we can find an entry for the required object type
|
||||
* and there is an Object_List_RPM fn ptr then call it
|
||||
* to populate the pointers to the individual list counters.
|
||||
*/
|
||||
|
||||
pObject = Device_Objects_Find_Functions(object_type);
|
||||
if ((pObject != NULL) && (pObject->Object_RPM_List != NULL)) {
|
||||
pObject->Object_RPM_List(&pPropertyList->Required.pList,
|
||||
&pPropertyList->Optional.pList, &pPropertyList->Proprietary.pList);
|
||||
}
|
||||
/* fill the count */
|
||||
if (pPropertyList->Required.pList) {
|
||||
pPropertyList->Required.count =
|
||||
property_list_count(pPropertyList->Required.pList);
|
||||
} else {
|
||||
pPropertyList->Required.count = 0;
|
||||
}
|
||||
if (pPropertyList->Optional.pList) {
|
||||
pPropertyList->Optional.count =
|
||||
property_list_count(pPropertyList->Optional.pList);
|
||||
} else {
|
||||
pPropertyList->Optional.count = 0;
|
||||
}
|
||||
if (pPropertyList->Proprietary.pList) {
|
||||
pPropertyList->Proprietary.count =
|
||||
property_list_count(pPropertyList->Proprietary.pList);
|
||||
} else {
|
||||
pPropertyList->Proprietary.count = 0;
|
||||
}
|
||||
|
||||
/* Fetch the counts if available otherwise zero them */
|
||||
pPropertyList->Required.count =
|
||||
pPropertyList->Required.pList ==
|
||||
NULL ? 0 : property_list_count(pPropertyList->Required.pList);
|
||||
|
||||
pPropertyList->Optional.count =
|
||||
pPropertyList->Optional.pList ==
|
||||
NULL ? 0 : property_list_count(pPropertyList->Optional.pList);
|
||||
|
||||
pPropertyList->Proprietary.count =
|
||||
pPropertyList->Proprietary.pList ==
|
||||
NULL ? 0 : property_list_count(pPropertyList->Proprietary.pList);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Device_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Device_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Device_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Device_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned Device_Count(
|
||||
void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t Device_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
index = index;
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
bool Device_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (object_instance == Object_Instance_Number) {
|
||||
status = characterstring_copy(object_name, &My_Object_Name);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Name(
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
|
||||
if (!characterstring_same(&My_Object_Name, object_name)) {
|
||||
/* Make the change and update the database revision */
|
||||
status = characterstring_copy(&My_Object_Name, object_name);
|
||||
Device_Inc_Database_Revision();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Reinitialize(
|
||||
BACNET_REINITIALIZE_DEVICE_DATA * rd_data)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (characterstring_ansi_same(&rd_data->password, "rehmite")) {
|
||||
Reinitialize_State = rd_data->state;
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
/* Note: you could use a mix of state
|
||||
and password to multiple things */
|
||||
/* note: you probably want to restart *after* the
|
||||
simple ack has been sent from the return handler
|
||||
so just set a flag from here */
|
||||
status = true;
|
||||
} else {
|
||||
rd_data->error_class = ERROR_CLASS_SECURITY;
|
||||
rd_data->error_code = ERROR_CODE_PASSWORD_FAILURE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BACNET_REINITIALIZED_STATE Device_Reinitialized_State(
|
||||
void)
|
||||
{
|
||||
return Reinitialize_State;
|
||||
}
|
||||
|
||||
void Device_Init(
|
||||
object_functions_t * object_table)
|
||||
{
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
/* we don't use the object table passed in
|
||||
since there is extra stuff we don't need in there. */
|
||||
(void)object_table;
|
||||
/* our local object table */
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
if (pObject->Object_Init) {
|
||||
pObject->Object_Init();
|
||||
}
|
||||
pObject++;
|
||||
}
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
Object_Instance_Number = 12345;
|
||||
characterstring_init_ansi(&My_Object_Name, "ARM7 Demo Device");
|
||||
}
|
||||
|
||||
/* methods to manipulate the data */
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void)
|
||||
{
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
bool status = true; /* return value */
|
||||
|
||||
if (object_id <= BACNET_MAX_INSTANCE) {
|
||||
Object_Instance_Number = object_id;
|
||||
} else
|
||||
status = false;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
/* BACnet allows for a wildcard instance number */
|
||||
return ((Object_Instance_Number == object_id) ||
|
||||
(object_id == BACNET_MAX_INSTANCE));
|
||||
}
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(
|
||||
void)
|
||||
{
|
||||
return System_Status;
|
||||
}
|
||||
|
||||
int Device_Set_System_Status(
|
||||
BACNET_DEVICE_STATUS status,
|
||||
bool local)
|
||||
{
|
||||
/*return value - 0 = ok, -1 = bad value, -2 = not allowed */
|
||||
int result = -1;
|
||||
|
||||
if (status < MAX_DEVICE_STATUS) {
|
||||
System_Status = status;
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void)
|
||||
{
|
||||
return BACNET_VENDOR_ID;
|
||||
}
|
||||
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||
void)
|
||||
{
|
||||
return SEGMENTATION_NONE;
|
||||
}
|
||||
|
||||
uint32_t Device_Database_Revision(
|
||||
void)
|
||||
{
|
||||
return Database_Revision;
|
||||
}
|
||||
|
||||
void Device_Inc_Database_Revision(
|
||||
void)
|
||||
{
|
||||
Database_Revision++;
|
||||
}
|
||||
|
||||
/* Since many network clients depend on the object list */
|
||||
/* for discovery, it must be consistent! */
|
||||
unsigned Device_Object_List_Count(
|
||||
void)
|
||||
{
|
||||
unsigned count = 0; /* number of objects */
|
||||
unsigned index = 0; /* loop counter */
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
/* initialize the default return values */
|
||||
@@ -309,8 +501,7 @@ unsigned Device_Object_List_Count(
|
||||
if (pObject->Object_Count) {
|
||||
count += pObject->Object_Count();
|
||||
}
|
||||
index++;
|
||||
pObject = &Object_Table[index];
|
||||
pObject++;
|
||||
}
|
||||
|
||||
return count;
|
||||
@@ -324,7 +515,6 @@ bool Device_Object_List_Identifier(
|
||||
bool status = false;
|
||||
unsigned count = 0;
|
||||
unsigned object_index = 0;
|
||||
unsigned index = 0; /* loop counter */
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
/* array index zero is length - so invalid */
|
||||
@@ -345,15 +535,14 @@ bool Device_Object_List_Identifier(
|
||||
break;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
pObject = &Object_Table[index];
|
||||
pObject++;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Name(
|
||||
const char *object_name,
|
||||
BACNET_CHARACTER_STRING *object_name1,
|
||||
int *object_type,
|
||||
uint32_t * object_instance)
|
||||
{
|
||||
@@ -362,14 +551,17 @@ bool Device_Valid_Object_Name(
|
||||
uint32_t instance;
|
||||
unsigned max_objects = 0, i = 0;
|
||||
bool check_id = false;
|
||||
char *name = NULL;
|
||||
BACNET_CHARACTER_STRING object_name2;
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
max_objects = Device_Object_List_Count();
|
||||
for (i = 0; i < max_objects; i++) {
|
||||
check_id = Device_Object_List_Identifier(i, &type, &instance);
|
||||
if (check_id) {
|
||||
name = Device_Valid_Object_Id(type, instance);
|
||||
if (strcmp(name, object_name) == 0) {
|
||||
pObject = Device_Objects_Find_Functions(type);
|
||||
if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
|
||||
(pObject->Object_Name(instance, &object_name2) &&
|
||||
characterstring_same(object_name1, &object_name2))) {
|
||||
found = true;
|
||||
if (object_type) {
|
||||
*object_type = type;
|
||||
@@ -385,179 +577,49 @@ bool Device_Valid_Object_Name(
|
||||
return found;
|
||||
}
|
||||
|
||||
/* returns the name or NULL if not found */
|
||||
char *Device_Valid_Object_Id(
|
||||
bool Device_Valid_Object_Id(
|
||||
int object_type,
|
||||
uint32_t object_instance)
|
||||
{
|
||||
char *name = NULL; /* return value */
|
||||
unsigned index = 0; /* loop counter */
|
||||
bool status = false; /* return value */
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
if ((pObject->Object_Type == object_type) && (pObject->Object_Name)) {
|
||||
name = pObject->Object_Name(object_instance);
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
pObject = &Object_Table[index];
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
unsigned Device_Count(
|
||||
void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t Device_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
char *Device_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance == Object_Instance_Number) {
|
||||
return My_Object_Name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Device_Reinitialize(
|
||||
BACNET_REINITIALIZE_DEVICE_DATA * rd_data)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (characterstring_ansi_same(&rd_data->password, "filister")) {
|
||||
Reinitialize_State = rd_data->state;
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
/* Note: you could use a mix of state
|
||||
and password to multiple things */
|
||||
/* note: you probably want to restart *after* the
|
||||
simple ack has been sent from the return handler
|
||||
so just set a flag from here */
|
||||
status = true;
|
||||
} else {
|
||||
rd_data->error_class = ERROR_CLASS_SECURITY;
|
||||
rd_data->error_code = ERROR_CODE_PASSWORD_FAILURE;
|
||||
pObject = Device_Objects_Find_Functions(object_type);
|
||||
if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
|
||||
status = pObject->Object_Valid_Instance(object_instance);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void Device_Init(
|
||||
void)
|
||||
bool Device_Object_Name_Copy(
|
||||
int object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
unsigned index = 0; /* loop counter */
|
||||
struct my_object_functions *pObject = NULL;
|
||||
bool found = false;
|
||||
int type = 0;
|
||||
uint32_t instance;
|
||||
unsigned max_objects = 0, i = 0;
|
||||
bool check_id = false;
|
||||
|
||||
Reinitialize_State = BACNET_REINIT_IDLE;
|
||||
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
|
||||
/* FIXME: Get the data from the eeprom */
|
||||
/* I2C_Read_Block(EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&Object_Instance_Number,
|
||||
sizeof(Object_Instance_Number),
|
||||
EEPROM_BACNET_ID_ADDR); */
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
if (pObject->Object_Init) {
|
||||
pObject->Object_Init();
|
||||
max_objects = Device_Object_List_Count();
|
||||
for (i = 0; i < max_objects; i++) {
|
||||
check_id = Device_Object_List_Identifier(i, &type, &instance);
|
||||
if (check_id) {
|
||||
pObject = Device_Objects_Find_Functions(type);
|
||||
if ((pObject != NULL) && (pObject->Object_Name != NULL)) {
|
||||
found = pObject->Object_Name(instance, object_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
pObject = &Object_Table[index];
|
||||
}
|
||||
}
|
||||
|
||||
/* methods to manipulate the data */
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void)
|
||||
{
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
bool status = true; /* return value */
|
||||
|
||||
if (object_id <= BACNET_MAX_INSTANCE) {
|
||||
Object_Instance_Number = object_id;
|
||||
/* FIXME: Write the data to the eeprom */
|
||||
/* I2C_Write_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&Object_Instance_Number,
|
||||
sizeof(Object_Instance_Number),
|
||||
EEPROM_BACNET_ID_ADDR); */
|
||||
} else
|
||||
status = false;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
/* BACnet allows for a wildcard instance number */
|
||||
return ((Object_Instance_Number == object_id) ||
|
||||
(object_id == BACNET_MAX_INSTANCE));
|
||||
}
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(
|
||||
void)
|
||||
{
|
||||
return System_Status;
|
||||
}
|
||||
|
||||
int Device_Set_System_Status(
|
||||
BACNET_DEVICE_STATUS status,
|
||||
bool local)
|
||||
{
|
||||
int result = 0; /*return value - 0 = ok, -1 = bad value, -2 = not allowed */
|
||||
|
||||
if (status < MAX_DEVICE_STATUS) {
|
||||
System_Status = status;
|
||||
}
|
||||
|
||||
return result;
|
||||
return found;
|
||||
}
|
||||
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void)
|
||||
{
|
||||
return BACNET_VENDOR_ID;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Version(
|
||||
void)
|
||||
{
|
||||
return BACNET_PROTOCOL_VERSION;
|
||||
}
|
||||
|
||||
uint8_t Device_Protocol_Revision(
|
||||
void)
|
||||
{
|
||||
return BACNET_PROTOCOL_REVISION;
|
||||
}
|
||||
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||
void)
|
||||
{
|
||||
return SEGMENTATION_NONE;
|
||||
}
|
||||
|
||||
uint32_t Device_Database_Revision(
|
||||
void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return the length of the apdu encoded or -1 for error */
|
||||
/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */
|
||||
int Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
@@ -569,18 +631,13 @@ int Device_Read_Property_Local(
|
||||
int object_type = 0;
|
||||
uint32_t instance = 0;
|
||||
unsigned count = 0;
|
||||
BACNET_TIME local_time;
|
||||
BACNET_DATE local_date;
|
||||
uint8_t *apdu = NULL;
|
||||
struct my_object_functions *pObject = NULL;
|
||||
bool found = false;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
if ((rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
/* requested instance may have been the wildcard instance */
|
||||
rpdata->object_instance = Object_Instance_Number;
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
@@ -588,19 +645,23 @@ int Device_Read_Property_Local(
|
||||
encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string, My_Object_Name);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &My_Object_Name);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string, "BACnet Demo");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
characterstring_init_ansi(&char_string, "USA");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
@@ -612,9 +673,7 @@ int Device_Read_Property_Local(
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Vendor_Identifier());
|
||||
apdu_len = encode_application_unsigned(&apdu[0], BACNET_VENDOR_ID);
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
characterstring_init_ansi(&char_string, "GNU Demo");
|
||||
@@ -631,20 +690,14 @@ int Device_Read_Property_Local(
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
characterstring_init_ansi(&char_string, "USA");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_PROTOCOL_VERSION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Version());
|
||||
encode_application_unsigned(&apdu[0], BACNET_PROTOCOL_VERSION);
|
||||
break;
|
||||
case PROP_PROTOCOL_REVISION:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Protocol_Revision());
|
||||
BACNET_PROTOCOL_REVISION);
|
||||
break;
|
||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||
/* Note: list of services that are executed, not initiated. */
|
||||
@@ -652,7 +705,7 @@ int Device_Read_Property_Local(
|
||||
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||
/* automatic lookup based on handlers set */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||
apdu_service_supported(i));
|
||||
apdu_service_supported((BACNET_SERVICES_SUPPORTED) i));
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
@@ -671,8 +724,7 @@ int Device_Read_Property_Local(
|
||||
if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) {
|
||||
bitstring_set_bit(&bit_string, pObject->Object_Type, true);
|
||||
}
|
||||
i++;
|
||||
pObject = &Object_Table[i];
|
||||
pObject++;
|
||||
}
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
@@ -687,10 +739,8 @@ int Device_Read_Property_Local(
|
||||
/* your maximum APDU size. */
|
||||
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
found =
|
||||
Device_Object_List_Identifier(i, &object_type,
|
||||
&instance);
|
||||
if (found) {
|
||||
if (Device_Object_List_Identifier(i, &object_type,
|
||||
&instance)) {
|
||||
len =
|
||||
encode_application_object_id(&apdu[apdu_len],
|
||||
object_type, instance);
|
||||
@@ -756,31 +806,6 @@ int Device_Read_Property_Local(
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||
break;
|
||||
case PROP_LOCAL_TIME:
|
||||
/* FIXME: if you support time */
|
||||
local_time.hour = 0;
|
||||
local_time.min = 0;
|
||||
local_time.sec = 0;
|
||||
local_time.hundredths = 0;
|
||||
apdu_len = encode_application_time(&apdu[0], &local_time);
|
||||
break;
|
||||
case PROP_UTC_OFFSET:
|
||||
/* Note: BACnet Time Zone is offset of local time and UTC,
|
||||
rather than offset of GMT. It is expressed in minutes */
|
||||
apdu_len = encode_application_signed(&apdu[0], 5 * 60 /* EST */ );
|
||||
break;
|
||||
case PROP_LOCAL_DATE:
|
||||
/* FIXME: if you support date */
|
||||
local_date.year = 2006; /* AD */
|
||||
local_date.month = 4; /* Jan=1..Dec=12 */
|
||||
local_date.day = 11; /* 1..31 */
|
||||
local_date.wday = 0; /* 1=Mon..7=Sun */
|
||||
apdu_len = encode_application_date(&apdu[0], &local_date);
|
||||
break;
|
||||
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
||||
/* FIXME: if you support time/date */
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case 9600:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
||||
@@ -805,15 +830,12 @@ int Device_Read_Property_Local(
|
||||
bool Device_Write_Property_Local(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
bool status = false; /* return value - false=error */
|
||||
int len = 0;
|
||||
uint8_t encoding = 0;
|
||||
size_t length = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Device_Valid_Object_Instance_Number(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,
|
||||
@@ -873,29 +895,32 @@ bool Device_Write_Property_Local(
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
size_t len;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
len = characterstring_length(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (len <= 20) {
|
||||
/* FIXME: set the name */
|
||||
/* Display_Set_Name(
|
||||
characterstring_value(&value.type.Character_String)); */
|
||||
/* FIXME: All the object names in a device must be unique.
|
||||
Disallow setting the Device Object Name to any objects in
|
||||
the device. */
|
||||
length = characterstring_length(
|
||||
&value.type.Character_String);
|
||||
if (length < characterstring_capacity(&My_Object_Name)) {
|
||||
encoding = characterstring_encoding(
|
||||
&value.type.Character_String);
|
||||
if (encoding < MAX_CHARACTER_STRING_ENCODING) {
|
||||
/* All the object names in a device must be unique. */
|
||||
if (Device_Valid_Object_Name(
|
||||
&value.type.Character_String,
|
||||
NULL, NULL)) {
|
||||
status = false;
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_DUPLICATE_NAME;
|
||||
} else {
|
||||
Device_Set_Object_Name(
|
||||
&value.type.Character_String);
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code =
|
||||
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code =
|
||||
ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
|
||||
@@ -143,7 +143,7 @@ static inline void bacnet_init(
|
||||
#endif
|
||||
Device_Set_Object_Instance_Number(22222);
|
||||
/* initialize objects */
|
||||
Device_Init();
|
||||
Device_Init(NULL);
|
||||
/* set up our confirmed service unrecognized service handler - required! */
|
||||
apdu_set_unrecognized_service_handler_handler
|
||||
(handler_unrecognized_service);
|
||||
|
||||
@@ -31,6 +31,8 @@ AVRDUDE_PORT = /dev/ttyUSB0
|
||||
# Source locations
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_HANDLER = ../../demo/handler
|
||||
BACNET_OBJECT = ../../demo/object
|
||||
BACNET_DEMO = ../../demo
|
||||
|
||||
# local files for this project
|
||||
@@ -93,6 +95,8 @@ CORESRC = \
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE)
|
||||
INCLUDES += -I$(BACNET_OBJECT)
|
||||
INCLUDES += -I$(BACNET_HANDLER)
|
||||
|
||||
# Source to Object conversion
|
||||
COBJ = $(CSRC:.c=.o)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 AI_H
|
||||
#define AI_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
void Analog_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
|
||||
bool Analog_Input_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Analog_Input_Count(
|
||||
void);
|
||||
uint32_t Analog_Input_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Analog_Input_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Analog_Input_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance);
|
||||
bool Analog_Input_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
char *Analog_Input_Description(
|
||||
uint32_t instance);
|
||||
bool Analog_Input_Description_Set(
|
||||
uint32_t instance,
|
||||
char *new_name);
|
||||
|
||||
bool Analog_Input_Units_Set(
|
||||
uint32_t instance,
|
||||
uint16_t units);
|
||||
uint16_t Analog_Input_Units(
|
||||
uint32_t instance);
|
||||
|
||||
int Analog_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Analog_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
float Analog_Input_Present_Value(
|
||||
uint32_t object_instance);
|
||||
void Analog_Input_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value);
|
||||
|
||||
void Analog_Input_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAnalogInput(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#define ANALOG_INPUT_OBJ_FUNCTIONS \
|
||||
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, \
|
||||
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, \
|
||||
Analog_Input_Name, Analog_Input_Read_Property, NULL, \
|
||||
Analog_Input_Property_Lists, NULL, NULL
|
||||
#endif
|
||||
@@ -45,6 +45,8 @@ AVRDUDE_PORT = usb
|
||||
# Source locations
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_HANDLER = ../../demo/handler
|
||||
BACNET_OBJECT = ../../demo/object
|
||||
BACNET_DEMO = ../../demo
|
||||
|
||||
# local files for this project
|
||||
@@ -65,6 +67,7 @@ CSRC = main.c \
|
||||
dlmstp.c \
|
||||
test.c \
|
||||
bacnet.c \
|
||||
bname.c \
|
||||
device.c \
|
||||
ai.c \
|
||||
av.c \
|
||||
@@ -130,7 +133,7 @@ CORESRC = \
|
||||
# $(BACNET_CORE)/address.c \
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE)
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE) -I$(BACNET_HANDLER) -I$(BACNET_OBJECT)
|
||||
|
||||
# Source to Object conversion
|
||||
COBJ = $(CSRC:%.c=%.o)
|
||||
|
||||
@@ -109,17 +109,19 @@ uint32_t Analog_Input_Index_To_Instance(
|
||||
return index;
|
||||
}
|
||||
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance)
|
||||
bool Analog_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_ANALOG_INPUTS) {
|
||||
sprintf(text_string, "AI-%lu", object_instance);
|
||||
return text_string;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
float Analog_Input_Present_Value(
|
||||
|
||||
@@ -175,19 +175,21 @@ bool Analog_Value_Present_Value_Set(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
bool Analog_Value_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
unsigned index = 0;
|
||||
bool status = false;
|
||||
|
||||
index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ANALOG_VALUES) {
|
||||
sprintf(text_string, "AV-%lu", object_instance);
|
||||
return text_string;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
|
||||
@@ -85,10 +85,10 @@ void bacnet_init(
|
||||
dlmstp_init(NULL);
|
||||
|
||||
if (!seeprom_version_test()) {
|
||||
/* invalid version data */
|
||||
/* do something when SEEPROM is invalid - i.e. init to defaults */
|
||||
}
|
||||
/* initialize objects */
|
||||
Device_Init();
|
||||
Device_Init(NULL);
|
||||
|
||||
/* set up our confirmed service unrecognized service handler - required! */
|
||||
apdu_set_unrecognized_service_handler_handler
|
||||
|
||||
@@ -157,17 +157,19 @@ bool Binary_Input_Present_Value_Set(
|
||||
return false;
|
||||
}
|
||||
|
||||
char *Binary_Input_Name(
|
||||
uint32_t object_instance)
|
||||
bool Binary_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_BINARY_INPUTS) {
|
||||
sprintf(text_string, "BI-%lu", object_instance);
|
||||
return text_string;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "hardware.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacstr.h"
|
||||
#include "nvdata.h"
|
||||
#include "seeprom.h"
|
||||
#include "device.h"
|
||||
#include "bname.h"
|
||||
|
||||
/* Basic UTF-8 manipulation routines
|
||||
by Jeff Bezanson
|
||||
placed in the public domain Fall 2005 */
|
||||
static const char trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
/* based on the valid_utf8 routine from the PCRE library by Philip Hazel
|
||||
length is in bytes, since without knowing whether the string is valid
|
||||
it's hard to know how many characters there are! */
|
||||
static int utf8_isvalid(const char *str, int length)
|
||||
{
|
||||
const unsigned char *p, *pend = (unsigned char*)str + length;
|
||||
unsigned char c;
|
||||
int ab;
|
||||
|
||||
for (p = (unsigned char*)str; p < pend; p++) {
|
||||
c = *p;
|
||||
/* null in middle of string */
|
||||
if (c == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* ASCII character */
|
||||
if (c < 128) {
|
||||
continue;
|
||||
}
|
||||
if ((c & 0xc0) != 0xc0) {
|
||||
return 0;
|
||||
}
|
||||
ab = trailingBytesForUTF8[c];
|
||||
if (length < ab) {
|
||||
return 0;
|
||||
}
|
||||
length -= ab;
|
||||
|
||||
p++;
|
||||
/* Check top bits in the second byte */
|
||||
if ((*p & 0xc0) != 0x80) {
|
||||
return 0;
|
||||
}
|
||||
/* Check for overlong sequences for each different length */
|
||||
switch (ab) {
|
||||
/* Check for xx00 000x */
|
||||
case 1:
|
||||
if ((c & 0x3e) == 0) return 0;
|
||||
continue; /* We know there aren't any more bytes to check */
|
||||
|
||||
/* Check for 1110 0000, xx0x xxxx */
|
||||
case 2:
|
||||
if (c == 0xe0 && (*p & 0x20) == 0) return 0;
|
||||
break;
|
||||
|
||||
/* Check for 1111 0000, xx00 xxxx */
|
||||
case 3:
|
||||
if (c == 0xf0 && (*p & 0x30) == 0) return 0;
|
||||
break;
|
||||
|
||||
/* Check for 1111 1000, xx00 0xxx */
|
||||
case 4:
|
||||
if (c == 0xf8 && (*p & 0x38) == 0) return 0;
|
||||
break;
|
||||
|
||||
/* Check for leading 0xfe or 0xff,
|
||||
and then for 1111 1100, xx00 00xx */
|
||||
case 5:
|
||||
if (c == 0xfe || c == 0xff ||
|
||||
(c == 0xfc && (*p & 0x3c) == 0)) return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for valid bytes after the 2nd, if any; all must start 10 */
|
||||
while (--ab > 0) {
|
||||
if ((*(++p) & 0xc0) != 0x80) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool bacnet_name_isvalid(
|
||||
uint8_t encoding,
|
||||
uint8_t length,
|
||||
char *str)
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
if ((encoding < MAX_CHARACTER_STRING_ENCODING) &&
|
||||
(length <= NV_EEPROM_NAME_SIZE)) {
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (utf8_isvalid(str, length)) {
|
||||
valid = true;
|
||||
}
|
||||
} else {
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool bacnet_name_set(
|
||||
uint16_t offset,
|
||||
BACNET_CHARACTER_STRING *char_string)
|
||||
{
|
||||
uint8_t encoding = 0;
|
||||
uint8_t length = 0;
|
||||
char *str = NULL;
|
||||
|
||||
length = characterstring_length(char_string);
|
||||
encoding = characterstring_encoding(char_string);
|
||||
str = characterstring_value(char_string);
|
||||
if (bacnet_name_isvalid(encoding, length, str)) {
|
||||
seeprom_bytes_write(
|
||||
NV_EEPROM_NAME_LENGTH(offset),
|
||||
&length, 1);
|
||||
seeprom_bytes_write(
|
||||
NV_EEPROM_NAME_ENCODING(offset),
|
||||
&encoding, 1);
|
||||
seeprom_bytes_write(
|
||||
NV_EEPROM_NAME_STRING(offset),
|
||||
(uint8_t *)str,
|
||||
length);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bacnet_name_write(
|
||||
uint16_t offset,
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code)
|
||||
{
|
||||
bool status = false;
|
||||
size_t length = 0;
|
||||
uint8_t encoding = 0;
|
||||
|
||||
length = characterstring_length(char_string);
|
||||
|
||||
if (length < 1) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
} else if (length <= NV_EEPROM_NAME_SIZE) {
|
||||
encoding = characterstring_encoding(char_string);
|
||||
if (encoding < MAX_CHARACTER_STRING_ENCODING) {
|
||||
if (Device_Valid_Object_Name(char_string, NULL, NULL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_DUPLICATE_NAME;
|
||||
} else {
|
||||
status = bacnet_name_set(offset, char_string);
|
||||
if (status) {
|
||||
Device_Inc_Database_Revision();
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* no required minumum length or duplicate checking */
|
||||
bool bacnet_name_write_other(
|
||||
uint16_t offset,
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code)
|
||||
{
|
||||
bool status = false;
|
||||
size_t length = 0;
|
||||
uint8_t encoding = 0;
|
||||
|
||||
length = characterstring_length(char_string);
|
||||
|
||||
if (length <= NV_EEPROM_NAME_SIZE) {
|
||||
encoding = characterstring_encoding(char_string);
|
||||
if (encoding < MAX_CHARACTER_STRING_ENCODING) {
|
||||
status = bacnet_name_set(offset, char_string);
|
||||
if (!status) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void bacnet_name_init(
|
||||
uint16_t offset,
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
char *default_string)
|
||||
{
|
||||
characterstring_init_ansi(char_string, default_string);
|
||||
(void)bacnet_name_set(offset, char_string);
|
||||
}
|
||||
|
||||
void bacnet_name(
|
||||
uint16_t offset,
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
char *default_string)
|
||||
{
|
||||
uint8_t encoding = 0;
|
||||
uint8_t length = 0;
|
||||
char name[NV_EEPROM_NAME_SIZE + 1] = "";
|
||||
|
||||
seeprom_bytes_read(NV_EEPROM_NAME_ENCODING(offset), &encoding, 1);
|
||||
seeprom_bytes_read(NV_EEPROM_NAME_LENGTH(offset), &length, 1);
|
||||
seeprom_bytes_read(NV_EEPROM_NAME_STRING(offset), (uint8_t *) & name,
|
||||
NV_EEPROM_NAME_SIZE);
|
||||
if (bacnet_name_isvalid(length, encoding, name)) {
|
||||
characterstring_init(char_string, encoding, &name[0], length);
|
||||
} else if (default_string) {
|
||||
bacnet_name_init(offset, char_string, default_string);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2010 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
#ifndef BACNET_NAME_H
|
||||
#define BACNET_NAME_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bacstr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
bool bacnet_name_set(
|
||||
uint16_t eeprom_offset,
|
||||
BACNET_CHARACTER_STRING *char_string);
|
||||
void bacnet_name_init(
|
||||
uint16_t eeprom_offset,
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
char *default_string);
|
||||
void bacnet_name(
|
||||
uint16_t eeprom_offset,
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
char *default_string);
|
||||
bool bacnet_name_write(
|
||||
uint16_t offset,
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code);
|
||||
/* no required minumum length or duplicate checking */
|
||||
bool bacnet_name_write_other(
|
||||
uint16_t offset,
|
||||
BACNET_CHARACTER_STRING *char_string,
|
||||
BACNET_ERROR_CLASS *error_class,
|
||||
BACNET_ERROR_CODE *error_code);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -229,17 +229,19 @@ bool Binary_Output_Out_Of_Service(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Output_Name(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Output_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_BINARY_OUTPUTS) {
|
||||
sprintf(text_string, "BO-%lu", object_instance);
|
||||
return text_string;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "nvdata.h"
|
||||
#include "stack.h"
|
||||
#include "handlers.h"
|
||||
#include "bname.h"
|
||||
/* objects */
|
||||
#include "device.h"
|
||||
#include "ai.h"
|
||||
@@ -66,24 +67,24 @@ static struct my_object_functions {
|
||||
{
|
||||
OBJECT_DEVICE, NULL, /* don't init - recursive! */
|
||||
Device_Count, Device_Index_To_Instance,
|
||||
Device_Valid_Object_Instance_Number, Device_Name,
|
||||
Device_Valid_Object_Instance_Number, Device_Object_Name,
|
||||
Device_Read_Property_Local, Device_Write_Property_Local,
|
||||
Device_Property_Lists}, {
|
||||
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
|
||||
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
|
||||
Analog_Input_Name, Analog_Input_Read_Property, NULL,
|
||||
Analog_Input_Object_Name, Analog_Input_Read_Property, NULL,
|
||||
Analog_Input_Property_Lists}, {
|
||||
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,
|
||||
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance,
|
||||
Analog_Value_Name, Analog_Value_Read_Property,
|
||||
Analog_Value_Object_Name, Analog_Value_Read_Property,
|
||||
Analog_Value_Write_Property, Analog_Value_Property_Lists}, {
|
||||
OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count,
|
||||
Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance,
|
||||
Binary_Input_Name, Binary_Input_Read_Property, NULL,
|
||||
Binary_Input_Object_Name, Binary_Input_Read_Property, NULL,
|
||||
Binary_Input_Property_Lists}, {
|
||||
OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count,
|
||||
Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance,
|
||||
Binary_Output_Name, Binary_Output_Read_Property,
|
||||
Binary_Output_Object_Name, Binary_Output_Read_Property,
|
||||
Binary_Output_Write_Property, Binary_Output_Property_Lists}, {
|
||||
MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
@@ -94,7 +95,7 @@ static struct my_object_functions {
|
||||
into the read-property encoding. */
|
||||
static uint32_t Object_Instance_Number;
|
||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||
|
||||
static uint32_t Database_Revision;
|
||||
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
@@ -130,6 +131,9 @@ static const int Device_Properties_Optional[] = {
|
||||
};
|
||||
|
||||
static const int Device_Properties_Proprietary[] = {
|
||||
512,
|
||||
513,
|
||||
9600,
|
||||
-1
|
||||
};
|
||||
|
||||
@@ -157,7 +161,6 @@ static int Read_Property_Common(
|
||||
{
|
||||
int apdu_len = BACNET_STATUS_ERROR;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
char *pString = "";
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata->application_data == NULL) ||
|
||||
@@ -178,9 +181,12 @@ static int Read_Property_Common(
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (pObject->Object_Name) {
|
||||
pString = pObject->Object_Name(rpdata->object_instance);
|
||||
(void)pObject->Object_Name(
|
||||
rpdata->object_instance,
|
||||
&char_string);
|
||||
} else {
|
||||
characterstring_init_ansi(&char_string, "");
|
||||
}
|
||||
characterstring_init_ansi(&char_string, pString);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
@@ -334,38 +340,30 @@ uint32_t Device_Index_To_Instance(
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
char *Device_Name(
|
||||
uint32_t object_instance)
|
||||
static char *Device_Name_Default(void)
|
||||
{
|
||||
uint8_t encoding = 0;
|
||||
uint8_t length = 0;
|
||||
static char name[NV_EEPROM_DEVICE_NAME_SIZE + 1] = "";
|
||||
char *pName = NULL;
|
||||
static char text_string[32]; /* okay for single thread */
|
||||
|
||||
sprintf(text_string, "DEVICE-%lu", Object_Instance_Number);
|
||||
|
||||
return text_string;
|
||||
}
|
||||
|
||||
bool Device_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (object_instance == Object_Instance_Number) {
|
||||
eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_ENCODING, &encoding, 1);
|
||||
eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_LENGTH, &length, 1);
|
||||
eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_0, (uint8_t *) & name,
|
||||
NV_EEPROM_DEVICE_NAME_SIZE);
|
||||
if ((encoding >= MAX_CHARACTER_STRING_ENCODING) ||
|
||||
(length > NV_EEPROM_DEVICE_NAME_SIZE) || (length < 1)) {
|
||||
encoding = CHARACTER_ANSI_X34;
|
||||
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_ENCODING, &encoding, 1);
|
||||
sprintf(name, "DEVICE-%lu", Object_Instance_Number);
|
||||
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_0, (uint8_t *) & name[0],
|
||||
NV_EEPROM_DEVICE_NAME_SIZE);
|
||||
length = strlen(name);
|
||||
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_LENGTH, &length, 1);
|
||||
}
|
||||
if (length < NV_EEPROM_DEVICE_NAME_SIZE) {
|
||||
name[length] = 0;
|
||||
} else {
|
||||
name[NV_EEPROM_DEVICE_NAME_SIZE] = 0;
|
||||
}
|
||||
pName = &name[0];
|
||||
bacnet_name(
|
||||
NV_EEPROM_DEVICE_NAME,
|
||||
object_name,
|
||||
Device_Name_Default());
|
||||
status = true;
|
||||
}
|
||||
|
||||
return pName;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Reinitialize(
|
||||
@@ -397,10 +395,14 @@ BACNET_REINITIALIZED_STATE Device_Reinitialized_State(
|
||||
}
|
||||
|
||||
void Device_Init(
|
||||
void)
|
||||
object_functions_t * object_table)
|
||||
{
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
/* we don't use the object table passed in
|
||||
since there is extra stuff we don't need in there. */
|
||||
(void)object_table;
|
||||
/* our local object table */
|
||||
pObject = &Object_Table[0];
|
||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||
if (pObject->Object_Init) {
|
||||
@@ -418,7 +420,6 @@ void Device_Init(
|
||||
(uint8_t *) & Object_Instance_Number,
|
||||
sizeof(Object_Instance_Number));
|
||||
}
|
||||
(void) Device_Name(Object_Instance_Number);
|
||||
}
|
||||
|
||||
/* methods to manipulate the data */
|
||||
@@ -488,7 +489,13 @@ BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||
uint32_t Device_Database_Revision(
|
||||
void)
|
||||
{
|
||||
return 0;
|
||||
return Database_Revision;
|
||||
}
|
||||
|
||||
void Device_Inc_Database_Revision(
|
||||
void)
|
||||
{
|
||||
Database_Revision++;
|
||||
}
|
||||
|
||||
/* Since many network clients depend on the object list */
|
||||
@@ -546,7 +553,7 @@ bool Device_Object_List_Identifier(
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Name(
|
||||
const char *object_name,
|
||||
BACNET_CHARACTER_STRING *object_name1,
|
||||
int *object_type,
|
||||
uint32_t * object_instance)
|
||||
{
|
||||
@@ -555,14 +562,17 @@ bool Device_Valid_Object_Name(
|
||||
uint32_t instance;
|
||||
unsigned max_objects = 0, i = 0;
|
||||
bool check_id = false;
|
||||
char *name = NULL;
|
||||
BACNET_CHARACTER_STRING object_name2;
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
max_objects = Device_Object_List_Count();
|
||||
for (i = 0; i < max_objects; i++) {
|
||||
check_id = Device_Object_List_Identifier(i, &type, &instance);
|
||||
if (check_id) {
|
||||
name = Device_Valid_Object_Id(type, instance);
|
||||
if (strcmp(name, object_name) == 0) {
|
||||
pObject = Device_Objects_Find_Functions(type);
|
||||
if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
|
||||
(pObject->Object_Name(instance, &object_name2) &&
|
||||
characterstring_same(object_name1, &object_name2))) {
|
||||
found = true;
|
||||
if (object_type) {
|
||||
*object_type = type;
|
||||
@@ -578,20 +588,46 @@ bool Device_Valid_Object_Name(
|
||||
return found;
|
||||
}
|
||||
|
||||
/* returns the name or NULL if not found */
|
||||
char *Device_Valid_Object_Id(
|
||||
bool Device_Valid_Object_Id(
|
||||
int object_type,
|
||||
uint32_t object_instance)
|
||||
{
|
||||
char *name = NULL; /* return value */
|
||||
bool status = false; /* return value */
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE) object_type);
|
||||
if ((pObject) && (pObject->Object_Name)) {
|
||||
name = pObject->Object_Name(object_instance);
|
||||
pObject = Device_Objects_Find_Functions(object_type);
|
||||
if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
|
||||
status = pObject->Object_Valid_Instance(object_instance);
|
||||
}
|
||||
|
||||
return name;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Object_Name_Copy(
|
||||
int object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
struct my_object_functions *pObject = NULL;
|
||||
bool found = false;
|
||||
int type = 0;
|
||||
uint32_t instance;
|
||||
unsigned max_objects = 0, i = 0;
|
||||
bool check_id = false;
|
||||
|
||||
max_objects = Device_Object_List_Count();
|
||||
for (i = 0; i < max_objects; i++) {
|
||||
check_id = Device_Object_List_Identifier(i, &type, &instance);
|
||||
if (check_id) {
|
||||
pObject = Device_Objects_Find_Functions(type);
|
||||
if ((pObject != NULL) && (pObject->Object_Name != NULL)) {
|
||||
found = pObject->Object_Name(instance, object_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */
|
||||
@@ -616,7 +652,18 @@ int Device_Read_Property_Local(
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string, "BACnet Development Kit");
|
||||
bacnet_name(
|
||||
NV_EEPROM_DEVICE_DESCRIPTION,
|
||||
&char_string,
|
||||
"BACnet Development Kit");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
bacnet_name(
|
||||
NV_EEPROM_DEVICE_LOCATION,
|
||||
&char_string,
|
||||
"default location");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
@@ -672,7 +719,6 @@ int Device_Read_Property_Local(
|
||||
not a list of objects that this device can access */
|
||||
bitstring_init(&bit_string);
|
||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||
/* FIXME: if ReadProperty used an array of Functions... */
|
||||
/* initialize all the object types to not-supported */
|
||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||
}
|
||||
@@ -858,38 +904,35 @@ bool Device_Write_Property_Local(
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
size_t length =
|
||||
characterstring_length(&value.type.Character_String);
|
||||
if (length < 1) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
} else if (length < NV_EEPROM_DEVICE_NAME_SIZE) {
|
||||
uint8_t encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
if (encoding < MAX_CHARACTER_STRING_ENCODING) {
|
||||
char *pCharString;
|
||||
uint8_t small_length;
|
||||
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_ENCODING,
|
||||
&encoding, 1);
|
||||
small_length = length;
|
||||
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_LENGTH,
|
||||
&small_length, 1);
|
||||
pCharString =
|
||||
characterstring_value(&value.type.
|
||||
Character_String);
|
||||
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_0,
|
||||
(uint8_t *) pCharString, length);
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code =
|
||||
ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code =
|
||||
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
status = bacnet_name_write(
|
||||
NV_EEPROM_DEVICE_NAME,
|
||||
&value.type.Character_String,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
status = bacnet_name_write_other(
|
||||
NV_EEPROM_DEVICE_DESCRIPTION,
|
||||
&value.type.Character_String,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
status = bacnet_name_write_other(
|
||||
NV_EEPROM_DEVICE_LOCATION,
|
||||
&value.type.Character_String,
|
||||
&wp_data->error_class,
|
||||
&wp_data->error_code);
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
|
||||
@@ -28,21 +28,8 @@
|
||||
#include "seeprom.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
/* data version - use to check valid version */
|
||||
#define SEEPROM_ID 0xBAC0
|
||||
#define SEEPROM_VERSION 0x0001
|
||||
|
||||
#define SEEPROM_BYTES_MAX (2*1024)
|
||||
|
||||
/* list of SEEPROM addresses */
|
||||
/* note to developers: define each byte,
|
||||
even if they are not used explicitly */
|
||||
#define NV_SEEPROM_TYPE_0 0
|
||||
#define NV_SEEPROM_TYPE_1 1
|
||||
#define NV_SEEPROM_VERSION_0 2
|
||||
#define NV_SEEPROM_VERSION_1 3
|
||||
/* --- */
|
||||
/* define the MAC, BAUD, MAX Master, Device Instance internal
|
||||
/*=============== EEPROM ================*/
|
||||
/* define the MAC, BAUD, MAX Master, Device Instance internal
|
||||
so that bootloader *could* use them. */
|
||||
/* note: MAC could come from DIP switch, or be in non-volatile memory */
|
||||
#define NV_EEPROM_MAC 0
|
||||
@@ -54,49 +41,44 @@
|
||||
#define NV_EEPROM_DEVICE_1 4
|
||||
#define NV_EEPROM_DEVICE_2 5
|
||||
#define NV_EEPROM_DEVICE_3 6
|
||||
/* Device Name */
|
||||
#define NV_EEPROM_DEVICE_NAME_LENGTH 8
|
||||
#define NV_EEPROM_DEVICE_NAME_ENCODING 9
|
||||
#define NV_EEPROM_DEVICE_NAME_0 10
|
||||
#define NV_EEPROM_DEVICE_NAME_1 11
|
||||
#define NV_EEPROM_DEVICE_NAME_2 12
|
||||
#define NV_EEPROM_DEVICE_NAME_3 13
|
||||
#define NV_EEPROM_DEVICE_NAME_4 14
|
||||
#define NV_EEPROM_DEVICE_NAME_5 15
|
||||
#define NV_EEPROM_DEVICE_NAME_6 16
|
||||
#define NV_EEPROM_DEVICE_NAME_7 17
|
||||
#define NV_EEPROM_DEVICE_NAME_8 18
|
||||
#define NV_EEPROM_DEVICE_NAME_9 19
|
||||
#define NV_EEPROM_DEVICE_NAME_10 20
|
||||
#define NV_EEPROM_DEVICE_NAME_11 21
|
||||
#define NV_EEPROM_DEVICE_NAME_12 22
|
||||
#define NV_EEPROM_DEVICE_NAME_13 23
|
||||
#define NV_EEPROM_DEVICE_NAME_14 24
|
||||
#define NV_EEPROM_DEVICE_NAME_15 25
|
||||
#define NV_EEPROM_DEVICE_NAME_16 26
|
||||
#define NV_EEPROM_DEVICE_NAME_17 27
|
||||
#define NV_EEPROM_DEVICE_NAME_18 28
|
||||
#define NV_EEPROM_DEVICE_NAME_19 29
|
||||
#define NV_EEPROM_DEVICE_NAME_20 30
|
||||
#define NV_EEPROM_DEVICE_NAME_21 31
|
||||
#define NV_EEPROM_DEVICE_NAME_22 32
|
||||
#define NV_EEPROM_DEVICE_NAME_23 33
|
||||
#define NV_EEPROM_DEVICE_NAME_24 34
|
||||
#define NV_EEPROM_DEVICE_NAME_25 35
|
||||
#define NV_EEPROM_DEVICE_NAME_26 36
|
||||
#define NV_EEPROM_DEVICE_NAME_27 37
|
||||
#define NV_EEPROM_DEVICE_NAME_28 38
|
||||
#define NV_EEPROM_DEVICE_NAME_29 39
|
||||
#define NV_EEPROM_DEVICE_NAME_30 40
|
||||
#define NV_EEPROM_DEVICE_NAME_31 41
|
||||
#define NV_EEPROM_DEVICE_NAME_SIZE 32
|
||||
|
||||
/* EEPROM free space - 7..31 */
|
||||
|
||||
/* BACnet Names - 32 bytes of data each */
|
||||
#define NV_EEPROM_NAME_LENGTH(n) ((n)+0)
|
||||
#define NV_EEPROM_NAME_ENCODING(n) ((n)+1)
|
||||
#define NV_EEPROM_NAME_STRING(n) ((n)+2)
|
||||
#define NV_EEPROM_NAME_SIZE 30
|
||||
#define NV_EEPROM_NAME_OFFSET (1+1+NV_EEPROM_NAME_SIZE)
|
||||
/* Device Name - starting offset */
|
||||
#define NV_EEPROM_DEVICE_NAME 32
|
||||
/* Device Description - starting offset */
|
||||
#define NV_EEPROM_DEVICE_DESCRIPTION \
|
||||
(NV_EEPROM_DEVICE_NAME+NV_EEPROM_NAME_OFFSET)
|
||||
/* Device Location - starting offset */
|
||||
#define NV_EEPROM_DEVICE_LOCATION \
|
||||
(NV_EEPROM_DEVICE_DESCRIPTION+NV_EEPROM_NAME_OFFSET)
|
||||
|
||||
/* EEPROM free space 128..1024 */
|
||||
|
||||
/*=============== SEEPROM ================*/
|
||||
#define NV_SEEPROM_BINARY_OUTPUT_OFFSET 32
|
||||
#define NV_SEEPROM_BINARY_OUTPUT_0 10
|
||||
#define NV_SEEPROM_BINARY_OUTPUT(n,p) \
|
||||
(NV_SEEPROM_BINARY_OUTPUT_0 + \
|
||||
(NV_SEEPROM_BINARY_OUTPUT_OFFSET * (n)) + (p))
|
||||
/* data version - use to check valid version */
|
||||
#define SEEPROM_ID 0xBAC0
|
||||
#define SEEPROM_VERSION 0x0001
|
||||
|
||||
#define SEEPROM_BYTES_MAX (2*1024)
|
||||
|
||||
/* list of SEEPROM addresses */
|
||||
/* note to developers: define each byte,
|
||||
even if they are not used explicitly */
|
||||
#define NV_SEEPROM_TYPE_0 0
|
||||
#define NV_SEEPROM_TYPE_1 1
|
||||
#define NV_SEEPROM_VERSION_0 2
|
||||
#define NV_SEEPROM_VERSION_1 3
|
||||
|
||||
/* SEEPROM free space - 4..31 */
|
||||
|
||||
#define NV_SEEPROM_BINARY_OUTPUT_0 32
|
||||
/* BO properties */
|
||||
#define NV_SEEPROM_BO_POLARITY 0
|
||||
#define NV_SEEPROM_BO_OUT_OF_SERVICE 1
|
||||
@@ -116,8 +98,13 @@
|
||||
#define NV_SEEPROM_BO_PRIORITY_ARRAY_14 15
|
||||
#define NV_SEEPROM_BO_PRIORITY_ARRAY_15 16
|
||||
#define NV_SEEPROM_BO_PRIORITY_ARRAY_16 17
|
||||
/* formula for paramters */
|
||||
#define NV_SEEPROM_BINARY_OUTPUT_SIZE 18
|
||||
#define NV_SEEPROM_BINARY_OUTPUT(n,p) \
|
||||
(NV_SEEPROM_BINARY_OUTPUT_0 + \
|
||||
(NV_SEEPROM_BINARY_OUTPUT_SIZE * (n)) + (p))
|
||||
|
||||
|
||||
/* SEEPROM free space - depends on number of BO */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -220,17 +220,19 @@ bool Binary_Output_Out_Of_Service(
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Output_Name(
|
||||
uint32_t object_instance)
|
||||
bool Binary_Output_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
static char text_string[32]; /* okay for single thread */
|
||||
static char text_string[16] = "BO-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_BINARY_OUTPUTS) {
|
||||
sprintf(text_string, "BO-%lu", object_instance);
|
||||
return text_string;
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
|
||||
@@ -61,12 +61,12 @@ static struct my_object_functions {
|
||||
{
|
||||
OBJECT_DEVICE, NULL, /* don't init - recursive! */
|
||||
Device_Count, Device_Index_To_Instance,
|
||||
Device_Valid_Object_Instance_Number, Device_Name,
|
||||
Device_Valid_Object_Instance_Number, Device_Object_Name,
|
||||
Device_Read_Property_Local, Device_Write_Property_Local,
|
||||
Device_Property_Lists}, {
|
||||
OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count,
|
||||
Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance,
|
||||
Binary_Output_Name, Binary_Output_Read_Property,
|
||||
Binary_Output_Object_Name, Binary_Output_Read_Property,
|
||||
Binary_Output_Write_Property, Binary_Output_Property_Lists}, {
|
||||
MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
@@ -162,9 +162,12 @@ static int Read_Property_Common(
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (pObject->Object_Name) {
|
||||
pString = pObject->Object_Name(rpdata->object_instance);
|
||||
(void)pObject->Object_Name(
|
||||
rpdata->object_instance,
|
||||
&char_string);
|
||||
} else {
|
||||
characterstring_init_ansi(&char_string, "");
|
||||
}
|
||||
characterstring_init_ansi(&char_string, pString);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
@@ -318,10 +321,17 @@ uint32_t Device_Index_To_Instance(
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
char *Device_Name(
|
||||
uint32_t object_instance)
|
||||
bool Device_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
return characterstring_value(&My_Object_Name);
|
||||
bool status = false;
|
||||
|
||||
if (object_instance == Object_Instance_Number) {
|
||||
status = characterstring_copy(object_name, &My_Object_Name);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Reinitialize(
|
||||
@@ -494,7 +504,7 @@ bool Device_Object_List_Identifier(
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Name(
|
||||
const char *object_name,
|
||||
BACNET_CHARACTER_STRING *object_name1,
|
||||
int *object_type,
|
||||
uint32_t * object_instance)
|
||||
{
|
||||
@@ -503,14 +513,17 @@ bool Device_Valid_Object_Name(
|
||||
uint32_t instance;
|
||||
unsigned max_objects = 0, i = 0;
|
||||
bool check_id = false;
|
||||
char *name = NULL;
|
||||
BACNET_CHARACTER_STRING object_name2;
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
max_objects = Device_Object_List_Count();
|
||||
for (i = 0; i < max_objects; i++) {
|
||||
check_id = Device_Object_List_Identifier(i, &type, &instance);
|
||||
if (check_id) {
|
||||
name = Device_Valid_Object_Id(type, instance);
|
||||
if (strcmp(name, object_name) == 0) {
|
||||
pObject = Device_Objects_Find_Functions(type);
|
||||
if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
|
||||
(pObject->Object_Name(instance, &object_name2) &&
|
||||
characterstring_same(object_name1, &object_name2))) {
|
||||
found = true;
|
||||
if (object_type) {
|
||||
*object_type = type;
|
||||
@@ -526,20 +539,46 @@ bool Device_Valid_Object_Name(
|
||||
return found;
|
||||
}
|
||||
|
||||
/* returns the name or NULL if not found */
|
||||
char *Device_Valid_Object_Id(
|
||||
bool Device_Valid_Object_Id(
|
||||
int object_type,
|
||||
uint32_t object_instance)
|
||||
{
|
||||
char *name = NULL; /* return value */
|
||||
bool status = false; /* return value */
|
||||
struct my_object_functions *pObject = NULL;
|
||||
|
||||
pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE) object_type);
|
||||
if ((pObject) && (pObject->Object_Name)) {
|
||||
name = pObject->Object_Name(object_instance);
|
||||
pObject = Device_Objects_Find_Functions(object_type);
|
||||
if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
|
||||
status = pObject->Object_Valid_Instance(object_instance);
|
||||
}
|
||||
|
||||
return name;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Object_Name_Copy(
|
||||
int object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING *object_name)
|
||||
{
|
||||
struct my_object_functions *pObject = NULL;
|
||||
bool found = false;
|
||||
int type = 0;
|
||||
uint32_t instance;
|
||||
unsigned max_objects = 0, i = 0;
|
||||
bool check_id = false;
|
||||
|
||||
max_objects = Device_Object_List_Count();
|
||||
for (i = 0; i < max_objects; i++) {
|
||||
check_id = Device_Object_List_Identifier(i, &type, &instance);
|
||||
if (check_id) {
|
||||
pObject = Device_Objects_Find_Functions(type);
|
||||
if ((pObject != NULL) && (pObject->Object_Name != NULL)) {
|
||||
found = pObject->Object_Name(instance, object_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */
|
||||
|
||||
Reference in New Issue
Block a user