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:
skarg
2011-03-24 16:53:02 +00:00
parent 75d88abf77
commit deab12a5e1
74 changed files with 1566 additions and 850 deletions
+1 -2
View File
@@ -122,8 +122,7 @@ void MyDeviceCommunicationControlSimpleAckHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -276,8 +276,7 @@ void MyReadPropertyMultipleAckHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
#if BAC_ROUTING #if BAC_ROUTING
uint32_t Object_Instance; uint32_t Object_Instance;
+1 -1
View File
@@ -153,7 +153,7 @@ void Devices_Init(
static void Init_Service_Handlers( static void Init_Service_Handlers(
uint32_t first_object_instance) uint32_t first_object_instance)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Routing_Device_Init(first_object_instance); Routing_Device_Init(first_object_instance);
/* we need to handle who-is to support dynamic device binding /* we need to handle who-is to support dynamic device binding
+17 -14
View File
@@ -40,36 +40,39 @@
/** Local function which responds with either the requested object name /** Local function which responds with either the requested object name
* or object ID, if the Device has a match. * or object ID, if the Device has a match.
* @param data [in] The decoded who-has payload from the request. * @param data [in] The decoded who-has payload from the request.
*/ */
static void match_name_or_object( static void match_name_or_object(
BACNET_WHO_HAS_DATA * data) BACNET_WHO_HAS_DATA * data)
{ {
char *object_name = NULL;
int object_type = 0; int object_type = 0;
uint32_t object_instance = 0; uint32_t object_instance = 0;
bool found = false; bool found = false;
BACNET_CHARACTER_STRING object_name;
/* do we have such an object? If so, send an I-Have. /* do we have such an object? If so, send an I-Have.
note: we should have only 1 of such an object */ note: we should have only 1 of such an object */
if (data->object_name) { if (data->is_object_name) {
/* valid name in my device? */ /* valid name in my device? */
object_name = characterstring_value(&data->object.name);
found = found =
Device_Valid_Object_Name(object_name, &object_type, Device_Valid_Object_Name(&data->object.name, &object_type,
&object_instance); &object_instance);
if (found) if (found) {
Send_I_Have(Device_Object_Instance_Number(), Send_I_Have(Device_Object_Instance_Number(),
(BACNET_OBJECT_TYPE) object_type, object_instance, (BACNET_OBJECT_TYPE) object_type, object_instance,
object_name); &data->object.name);
}
} else { } else {
/* valid object in my device? */ /* valid object_name copy in my device? */
object_name = found = Device_Object_Name_Copy(
Device_Valid_Object_Id(data->object.identifier.type, data->object.identifier.type,
data->object.identifier.instance); data->object.identifier.instance,
if (object_name) &object_name);
if (found) {
Send_I_Have(Device_Object_Instance_Number(), Send_I_Have(Device_Object_Instance_Number(),
(BACNET_OBJECT_TYPE) data->object.identifier.type, (BACNET_OBJECT_TYPE) data->object.identifier.type,
data->object.identifier.instance, object_name); data->object.identifier.instance, &object_name);
}
} }
} }
@@ -108,7 +111,7 @@ void handler_who_has(
#ifdef BAC_ROUTING #ifdef BAC_ROUTING
/** Handler for Who-Has requests in the virtual routing setup, /** Handler for Who-Has requests in the virtual routing setup,
* with broadcast I-Have response. * with broadcast I-Have response.
* Will respond if the device Object ID matches, and we have * Will respond if the device Object ID matches, and we have
* the Object or Object Name requested. * the Object or Object Name requested.
+2 -2
View File
@@ -57,7 +57,7 @@ void Send_I_Have(
uint32_t device_id, uint32_t device_id,
BACNET_OBJECT_TYPE object_type, BACNET_OBJECT_TYPE object_type,
uint32_t object_instance, uint32_t object_instance,
const char *object_name) BACNET_CHARACTER_STRING *object_name)
{ {
int len = 0; int len = 0;
int pdu_len = 0; int pdu_len = 0;
@@ -84,7 +84,7 @@ void Send_I_Have(
data.device_id.instance = device_id; data.device_id.instance = device_id;
data.object_id.type = object_type; data.object_id.type = object_type;
data.object_id.instance = object_instance; data.object_id.instance = object_instance;
characterstring_init_ansi(&data.object_name, object_name); characterstring_copy(&data.object_name, object_name);
len = ihave_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data); len = ihave_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data);
pdu_len += len; pdu_len += len;
/* send the data */ /* send the data */
+2 -2
View File
@@ -83,7 +83,7 @@ void Send_WhoHas_Name(
/* encode the APDU portion of the packet */ /* encode the APDU portion of the packet */
data.low_limit = low_limit; data.low_limit = low_limit;
data.high_limit = high_limit; data.high_limit = high_limit;
data.object_name = true; data.is_object_name = true;
characterstring_init_ansi(&data.object.name, object_name); characterstring_init_ansi(&data.object.name, object_name);
len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data); len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data);
pdu_len += len; pdu_len += len;
@@ -138,7 +138,7 @@ void Send_WhoHas_Object(
/* encode the APDU portion of the packet */ /* encode the APDU portion of the packet */
data.low_limit = low_limit; data.low_limit = low_limit;
data.high_limit = high_limit; data.high_limit = high_limit;
data.object_name = false; data.is_object_name = false;
data.object.identifier.type = object_type; data.object.identifier.type = object_type;
data.object.identifier.instance = object_instance; data.object.identifier.instance = object_instance;
len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data); len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data);
+1 -2
View File
@@ -90,8 +90,7 @@ void MyRejectHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -220,8 +220,7 @@ static void My_NPDU_Handler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+7 -6
View File
@@ -152,19 +152,21 @@ void Analog_Input_Present_Value_Set(
} }
} }
char *Analog_Input_Name( bool Analog_Input_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
unsigned int index; unsigned int index;
bool status = false;
index = Analog_Input_Instance_To_Index(object_instance); index = Analog_Input_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_INPUTS) { if (index < MAX_ANALOG_INPUTS) {
sprintf(text_string, "ANALOG INPUT %lu", (unsigned long) index); sprintf(text_string, "ANALOG INPUT %lu", (unsigned long) index);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
/* return apdu length, or BACNET_STATUS_ERROR on error */ /* return apdu length, or BACNET_STATUS_ERROR on error */
@@ -190,8 +192,7 @@ int Analog_Input_Read_Property(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Analog_Input_Object_Name(rpdata->object_instance, &char_string);
Analog_Input_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+4 -3
View File
@@ -50,8 +50,9 @@ extern "C" {
bool Analog_Input_Object_Instance_Add( bool Analog_Input_Object_Instance_Add(
uint32_t instance); uint32_t instance);
char *Analog_Input_Name( bool Analog_Input_Object_Name(
uint32_t object_instance); uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
bool Analog_Input_Name_Set( bool Analog_Input_Name_Set(
uint32_t object_instance, uint32_t object_instance,
char *new_name); char *new_name);
@@ -94,6 +95,6 @@ extern "C" {
#define ANALOG_INPUT_OBJ_FUNCTIONS \ #define ANALOG_INPUT_OBJ_FUNCTIONS \
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, \ OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, \
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, \ 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, NULL, NULL Analog_Input_Property_Lists, NULL, NULL
#endif #endif
+7 -6
View File
@@ -253,18 +253,20 @@ bool Analog_Output_Present_Value_Relinquish(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Analog_Output_Name( bool Analog_Output_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ANALOG_OUTPUTS) { if (object_instance < MAX_ANALOG_OUTPUTS) {
sprintf(text_string, "ANALOG OUTPUT %lu", sprintf(text_string, "ANALOG OUTPUT %lu",
(unsigned long) object_instance); (unsigned long) object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
/* return apdu len, or BACNET_STATUS_ERROR on error */ /* return apdu len, or BACNET_STATUS_ERROR on error */
@@ -294,8 +296,7 @@ int Analog_Output_Read_Property(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Analog_Output_Object_Name(rpdata->object_instance, &char_string);
Analog_Output_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+4 -3
View File
@@ -63,8 +63,9 @@ extern "C" {
uint32_t object_instance, uint32_t object_instance,
unsigned priority); unsigned priority);
char *Analog_Output_Name( bool Analog_Output_Object_Name(
uint32_t object_instance); uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
bool Analog_Output_Name_Set( bool Analog_Output_Name_Set(
uint32_t object_instance, uint32_t object_instance,
char *new_name); char *new_name);
@@ -102,7 +103,7 @@ extern "C" {
#define ANALOG_OUTPUT_OBJ_FUNCTIONS \ #define ANALOG_OUTPUT_OBJ_FUNCTIONS \
OBJECT_ANALOG_OUTPUT, Analog_Output_Init, Analog_Output_Count, \ OBJECT_ANALOG_OUTPUT, Analog_Output_Init, Analog_Output_Count, \
Analog_Output_Index_To_Instance, Analog_Output_Valid_Instance, \ Analog_Output_Index_To_Instance, Analog_Output_Valid_Instance, \
Analog_Output_Name, Analog_Output_Read_Property, \ Analog_Output_Object_Name, Analog_Output_Read_Property, \
Analog_Output_Write_Property, Analog_Output_Property_Lists, \ Analog_Output_Write_Property, Analog_Output_Property_Lists, \
NULL, NULL NULL, NULL
#endif #endif
+7 -6
View File
@@ -201,18 +201,20 @@ float Analog_Value_Present_Value(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Analog_Value_Name( bool Analog_Value_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ANALOG_VALUES) { if (object_instance < MAX_ANALOG_VALUES) {
sprintf(text_string, "ANALOG VALUE %lu", sprintf(text_string, "ANALOG VALUE %lu",
(unsigned long) object_instance); (unsigned long) object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
/* return apdu len, or BACNET_STATUS_ERROR on error */ /* return apdu len, or BACNET_STATUS_ERROR on error */
@@ -242,8 +244,7 @@ int Analog_Value_Read_Property(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Analog_Value_Object_Name(rpdata->object_instance, &char_string);
Analog_Value_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+5 -3
View File
@@ -47,8 +47,10 @@ extern "C" {
unsigned index); unsigned index);
unsigned Analog_Value_Instance_To_Index( unsigned Analog_Value_Instance_To_Index(
uint32_t object_instance); uint32_t object_instance);
char *Analog_Value_Name(
uint32_t object_instance); bool Analog_Value_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
int Analog_Value_Read_Property( int Analog_Value_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata); BACNET_READ_PROPERTY_DATA * rpdata);
@@ -78,7 +80,7 @@ extern "C" {
#define ANALOG_VALUE_OBJ_FUNCTIONS \ #define ANALOG_VALUE_OBJ_FUNCTIONS \
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, \ OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, \
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, \ 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, NULL, \ Analog_Value_Write_Property, Analog_Value_Property_Lists, NULL, \
NULL NULL
#endif #endif
+7 -6
View File
@@ -283,18 +283,20 @@ static void Binary_Input_Out_Of_Service_Set(
return; return;
} }
char *Binary_Input_Name( bool Binary_Input_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_INPUTS) { if (object_instance < MAX_BINARY_INPUTS) {
sprintf(text_string, "BINARY INPUT %lu", sprintf(text_string, "BINARY INPUT %lu",
(unsigned long) object_instance); (unsigned long) object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
BACNET_POLARITY Binary_Input_Polarity( BACNET_POLARITY Binary_Input_Polarity(
@@ -346,8 +348,7 @@ int Binary_Input_Read_Property(
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
/* note: object name must be unique in our device */ /* note: object name must be unique in our device */
characterstring_init_ansi(&char_string, Binary_Input_Object_Name(rpdata->object_instance, &char_string);
Binary_Input_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+4 -3
View File
@@ -52,8 +52,9 @@ extern "C" {
bool Binary_Input_Object_Instance_Add( bool Binary_Input_Object_Instance_Add(
uint32_t instance); uint32_t instance);
char *Binary_Input_Name( bool Binary_Input_Object_Name(
uint32_t object_instance); uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
bool Binary_Input_Name_Set( bool Binary_Input_Name_Set(
uint32_t object_instance, uint32_t object_instance,
char *new_name); char *new_name);
@@ -116,6 +117,6 @@ extern "C" {
#define BINARY_INPUT_OBJ_FUNCTIONS \ #define BINARY_INPUT_OBJ_FUNCTIONS \
OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, \ OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, \
Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance, \ 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, NULL, NULL Binary_Input_Property_Lists, NULL, NULL
#endif #endif
+7 -6
View File
@@ -177,18 +177,20 @@ BACNET_BINARY_PV Binary_Output_Present_Value(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Binary_Output_Name( bool Binary_Output_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_OUTPUTS) { if (object_instance < MAX_BINARY_OUTPUTS) {
sprintf(text_string, "BINARY OUTPUT %lu", sprintf(text_string, "BINARY OUTPUT %lu",
(unsigned long) object_instance); (unsigned long) object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
/* return apdu len, or BACNET_STATUS_ERROR on error */ /* return apdu len, or BACNET_STATUS_ERROR on error */
@@ -221,8 +223,7 @@ int Binary_Output_Read_Property(
You could make Description writable and different */ You could make Description writable and different */
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Binary_Output_Object_Name(rpdata->object_instance, &char_string);
Binary_Output_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+4 -3
View File
@@ -55,8 +55,9 @@ extern "C" {
bool Binary_Output_Object_Instance_Add( bool Binary_Output_Object_Instance_Add(
uint32_t instance); uint32_t instance);
char *Binary_Output_Name( bool Binary_Output_Object_Name(
uint32_t object_instance); uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
bool Binary_Output_Name_Set( bool Binary_Output_Name_Set(
uint32_t object_instance, uint32_t object_instance,
char *new_name); char *new_name);
@@ -111,7 +112,7 @@ extern "C" {
#define BINARY_OUTPUT_OBJ_FUNCTIONS \ #define BINARY_OUTPUT_OBJ_FUNCTIONS \
OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, \ OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, \
Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, \ 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, \ Binary_Output_Write_Property, Binary_Output_Property_Lists, \
NULL, NULL NULL, NULL
#endif #endif
+7 -6
View File
@@ -174,18 +174,20 @@ static BACNET_BINARY_PV Binary_Value_Present_Value(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Binary_Value_Name( bool Binary_Value_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_VALUES) { if (object_instance < MAX_BINARY_VALUES) {
sprintf(text_string, "BINARY VALUE %lu", sprintf(text_string, "BINARY VALUE %lu",
(unsigned long) object_instance); (unsigned long) object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
/* return apdu len, or BACNET_STATUS_ERROR on error */ /* return apdu len, or BACNET_STATUS_ERROR on error */
@@ -217,8 +219,7 @@ int Binary_Value_Read_Property(
You could make Description writable and different */ You could make Description writable and different */
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Binary_Value_Object_Name(rpdata->object_instance, &char_string);
Binary_Value_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+5 -3
View File
@@ -48,8 +48,10 @@ extern "C" {
unsigned index); unsigned index);
unsigned Binary_Value_Instance_To_Index( unsigned Binary_Value_Instance_To_Index(
uint32_t object_instance); uint32_t object_instance);
char *Binary_Value_Name(
uint32_t object_instance); bool Binary_Value_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
void Binary_Value_Init( void Binary_Value_Init(
void); void);
@@ -72,7 +74,7 @@ extern "C" {
#define BINARY_VALUE_OBJ_FUNCTIONS \ #define BINARY_VALUE_OBJ_FUNCTIONS \
OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count, \ OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count, \
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance, \ 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, NULL, \ Binary_Value_Write_Property, Binary_Value_Property_Lists, NULL, \
NULL NULL
#endif #endif
+80 -49
View File
@@ -289,7 +289,7 @@ void Device_Property_Lists(
into the read-property encoding. */ into the read-property encoding. */
static uint32_t Object_Instance_Number = 260001; static uint32_t Object_Instance_Number = 260001;
static char My_Object_Name[MAX_DEV_NAME_LEN + 1] = "SimpleServer"; static BACNET_CHARACTER_STRING My_Object_Name;
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
static char *Vendor_Name = BACNET_VENDOR_NAME; static char *Vendor_Name = BACNET_VENDOR_NAME;
static uint16_t Vendor_Identifier = BACNET_VENDOR_ID; static uint16_t Vendor_Identifier = BACNET_VENDOR_ID;
@@ -384,37 +384,28 @@ bool Device_Valid_Object_Instance_Number(
(object_id == BACNET_MAX_INSTANCE)); (object_id == BACNET_MAX_INSTANCE));
} }
char *Device_Name( bool Device_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
bool status = false;
if (object_instance == Object_Instance_Number) { if (object_instance == Object_Instance_Number) {
return My_Object_Name; status = characterstring_copy(object_name, &My_Object_Name);
} }
return NULL; return status;
}
const char *Device_Object_Name(
void)
{
return My_Object_Name;
} }
bool Device_Set_Object_Name( bool Device_Set_Object_Name(
const char *name, BACNET_CHARACTER_STRING *object_name)
size_t length)
{ {
bool status = false; /*return value */ bool status = false; /*return value */
/* FIXME: All the object names in a device must be unique. if (!characterstring_same(&My_Object_Name, object_name)) {
Disallow setting the Device Object Name to any objects in
the device. */
if (length < sizeof(My_Object_Name)) {
/* Make the change and update the database revision */ /* Make the change and update the database revision */
memmove(My_Object_Name, name, length); status = characterstring_copy(&My_Object_Name, object_name);
My_Object_Name[length] = 0;
Device_Inc_Database_Revision(); Device_Inc_Database_Revision();
status = true;
} }
return status; return status;
@@ -737,7 +728,7 @@ bool Device_Object_List_Identifier(
* @return True on success or else False if not found. * @return True on success or else False if not found.
*/ */
bool Device_Valid_Object_Name( bool Device_Valid_Object_Name(
const char *object_name, BACNET_CHARACTER_STRING *object_name1,
int *object_type, int *object_type,
uint32_t * object_instance) uint32_t * object_instance)
{ {
@@ -746,14 +737,17 @@ bool Device_Valid_Object_Name(
uint32_t instance; uint32_t instance;
unsigned max_objects = 0, i = 0; unsigned max_objects = 0, i = 0;
bool check_id = false; bool check_id = false;
char *name = NULL; BACNET_CHARACTER_STRING object_name2;
struct object_functions *pObject = NULL;
max_objects = Device_Object_List_Count(); max_objects = Device_Object_List_Count();
for (i = 0; i < max_objects; i++) { for (i = 0; i < max_objects; i++) {
check_id = Device_Object_List_Identifier(i, &type, &instance); check_id = Device_Object_List_Identifier(i, &type, &instance);
if (check_id) { if (check_id) {
name = Device_Valid_Object_Id(type, instance); pObject = Device_Objects_Find_Functions(type);
if (strcmp(name, object_name) == 0) { if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
(pObject->Object_Name(instance, &object_name2) &&
characterstring_same(object_name1, &object_name2))) {
found = true; found = true;
if (object_type) { if (object_type) {
*object_type = type; *object_type = type;
@@ -774,18 +768,52 @@ bool Device_Valid_Object_Name(
* @param object_instance [in] The object instance number to be looked up. * @param object_instance [in] The object instance number to be looked up.
* @return The Object Name or else NULL if not found * @return The Object Name or else NULL if not found
*/ */
char *Device_Valid_Object_Id( bool Device_Valid_Object_Id(
int object_type, int object_type,
uint32_t object_instance) uint32_t object_instance)
{ {
char *name = NULL; /* return value */ bool status = false; /* return value */
struct object_functions *pObject = NULL; struct object_functions *pObject = NULL;
pObject = Device_Objects_Find_Functions(object_type); pObject = Device_Objects_Find_Functions(object_type);
if ((pObject != NULL) && (pObject->Object_Name != NULL)) if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
name = pObject->Object_Name(object_instance); status = pObject->Object_Valid_Instance(object_instance);
}
return name; return status;
}
/** copy a child object object_name value.
* @param object_type [out] The BACNET_OBJECT_TYPE of the matching Object.
* @param object_instance [out] The object instance number of the matching Object.
* @param object_name [in] The desired Object Name to look for.
* @return True on success or else False if not found.
*/
bool Device_Object_Name_Copy(
int object_type,
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{
struct 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;
} }
static void Update_Current_Time( static void Update_Current_Time(
@@ -873,9 +901,8 @@ int Device_Read_Property_Local(
Object_Instance_Number); Object_Instance_Number);
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
characterstring_init_ansi(&char_string, My_Object_Name);
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &My_Object_Name);
break; break;
case PROP_OBJECT_TYPE: case PROP_OBJECT_TYPE:
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE); apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
@@ -1201,12 +1228,22 @@ bool Device_Write_Property_Local(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
status = status =
WPValidateString(&value, MAX_DEV_NAME_LEN, false, WPValidateString(&value,
&wp_data->error_class, &wp_data->error_code); characterstring_capacity(&My_Object_Name),
false,
&wp_data->error_class, &wp_data->error_code);
if (status) { if (status) {
Device_Set_Object_Name(characterstring_value(&value.type. /* All the object names in a device must be unique.
Character_String), Disallow setting the Device Object Name to any objects in
characterstring_length(&value.type.Character_String)); the device. */
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);
}
} }
break; break;
case PROP_LOCATION: case PROP_LOCATION:
@@ -1322,26 +1359,22 @@ bool Device_Write_Property(
return (status); return (status);
} }
/** Initialize the group of object helper functions for any supported Object. /** Initialize the Device Object.
Initialize the group of object helper functions for any supported Object.
Initialize each of the Device Object child Object instances.
* @ingroup ObjIntf * @ingroup ObjIntf
* @param object_table [in,out] array of structure with object functions. * @param object_table [in,out] array of structure with object functions.
* Each Child Object must provide some implementation of each of these * Each Child Object must provide some implementation of each of these
* functions in order to properly support the default handlers. * functions in order to properly support the default handlers.
*/ */
void Device_Initialize_Object_Functions(
object_functions_t * object_table)
{
Object_Table = object_table;
}
/** Initialize the Device Object and each of its child Object instances.
* @ingroup ObjIntf
*/
void Device_Init( void Device_Init(
void) object_functions_t * object_table)
{ {
struct object_functions *pObject = NULL; struct object_functions *pObject = NULL;
characterstring_init_ansi(&My_Object_Name, "SimpleServer");
/* call all the child objects initialization functions */
Object_Table = object_table;
pObject = &Object_Table[0]; pObject = &Object_Table[0];
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
if (pObject->Object_Init) { if (pObject->Object_Init) {
@@ -1412,8 +1445,6 @@ void Routing_Device_Init(
{ {
struct object_functions *pDevObject = NULL; struct object_functions *pDevObject = NULL;
/* First, do the usual Device_Init() functions: */
Device_Init();
/* Initialize with our preset strings */ /* Initialize with our preset strings */
Add_Routed_Device(first_object_instance, My_Object_Name, Description); Add_Routed_Device(first_object_instance, My_Object_Name, Description);
+17 -15
View File
@@ -71,10 +71,11 @@ typedef uint32_t(
* is temporary and should be copied upon the return. It is * is temporary and should be copied upon the return. It is
* allocated by the system and does not need to be freed. * allocated by the system and does not need to be freed.
*/ */
typedef char *( typedef bool(
*object_name_function) *object_name_function)
( (
uint32_t object_instance); uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
/** Look in the table of objects of this type, and see if this is a valid /** Look in the table of objects of this type, and see if this is a valid
* instance number. * instance number.
@@ -179,8 +180,6 @@ extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
void Device_Init( void Device_Init(
void);
void Device_Initialize_Object_Functions(
object_functions_t * object_table); object_functions_t * object_table);
bool Device_Reinitialize( bool Device_Reinitialize(
@@ -217,8 +216,17 @@ extern "C" {
void); void);
uint32_t Device_Index_To_Instance( uint32_t Device_Index_To_Instance(
unsigned index); unsigned index);
char *Device_Name(
uint32_t object_instance); bool Device_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
bool Device_Set_Object_Name(
BACNET_CHARACTER_STRING *object_name);
/* copy a child object name */
bool Device_Object_Name_Copy(
int object_type,
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
BACNET_DEVICE_STATUS Device_System_Status( BACNET_DEVICE_STATUS Device_System_Status(
void); void);
@@ -249,12 +257,6 @@ extern "C" {
const char *name, const char *name,
size_t length); size_t length);
bool Device_Set_Object_Name(
const char *name,
size_t length);
const char *Device_Object_Name(
void);
const char *Device_Description( const char *Device_Description(
void); void);
bool Device_Set_Description( bool Device_Set_Description(
@@ -283,10 +285,10 @@ extern "C" {
void); void);
bool Device_Valid_Object_Name( bool Device_Valid_Object_Name(
const char *object_name, BACNET_CHARACTER_STRING *object_name,
int *object_type, int *object_type,
uint32_t * object_instance); uint32_t * object_instance);
char *Device_Valid_Object_Id( bool Device_Valid_Object_Id(
int object_type, int object_type,
uint32_t object_instance); uint32_t object_instance);
@@ -362,7 +364,7 @@ extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
#define DEVICE_OBJ_FUNCTIONS \ #define DEVICE_OBJ_FUNCTIONS \
OBJECT_DEVICE, NULL, Device_Count, Device_Index_To_Instance, \ OBJECT_DEVICE, NULL, 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_Read_Property_Local, Device_Write_Property_Local, \
Device_Property_Lists, DeviceGetRRInfo, NULL Device_Property_Lists, DeviceGetRRInfo, NULL
/** @defgroup ObjFrmwk Object Framework /** @defgroup ObjFrmwk Object Framework
+53 -46
View File
@@ -85,7 +85,7 @@ bool Routed_Device_Write_Property_Local(
/**************************************************************************** /****************************************************************************
************* BACnet Routing Functionality (Optional) ********************** ************* BACnet Routing Functionality (Optional) **********************
**************************************************************************** ****************************************************************************
* It would be correct to view the routing functionality here as inheriting * It would be correct to view the routing functionality here as inheriting
* and extending the regular Device Object functionality. * and extending the regular Device Object functionality.
****************************************************************************/ ****************************************************************************/
@@ -96,8 +96,8 @@ DEVICE_OBJECT_DATA Devices[MAX_NUM_DEVICES];
/** Keep track of the number of managed devices, including the gateway */ /** Keep track of the number of managed devices, including the gateway */
uint16_t Num_Managed_Devices = 0; uint16_t Num_Managed_Devices = 0;
/** Which Device entry are we currently managing. /** Which Device entry are we currently managing.
* Since we are not using actual class objects here, the best we can do is * Since we are not using actual class objects here, the best we can do is
* keep this local variable which notes which of the Devices the current * keep this local variable which notes which of the Devices the current
* request is addressing. Should default to 0, the main gateway Device. * request is addressing. Should default to 0, the main gateway Device.
*/ */
uint16_t iCurrent_Device_Idx = 0; uint16_t iCurrent_Device_Idx = 0;
@@ -127,9 +127,15 @@ uint16_t Add_Routed_Device(
pDev->bacObj.mObject_Type = OBJECT_DEVICE; pDev->bacObj.mObject_Type = OBJECT_DEVICE;
pDev->bacObj.Object_Instance_Number = Object_Instance; pDev->bacObj.Object_Instance_Number = Object_Instance;
if (sObject_Name != NULL) if (sObject_Name != NULL)
Routed_Device_Set_Object_Name(sObject_Name, strlen(sObject_Name)); Routed_Device_Set_Object_Name(
CHARACTER_UTF8,
sObject_Name,
strlen(sObject_Name));
else else
Routed_Device_Set_Object_Name("No Name", strlen("No Name")); Routed_Device_Set_Object_Name(
CHARACTER_UTF8,
"No Name",
strlen("No Name"));
if (sDescription != NULL) if (sDescription != NULL)
Routed_Device_Set_Description(sDescription, strlen(sDescription)); Routed_Device_Set_Description(sDescription, strlen(sDescription));
else else
@@ -147,7 +153,7 @@ uint16_t Add_Routed_Device(
* -1 is a special case meaning "whichever iCurrent_Device_Idx * -1 is a special case meaning "whichever iCurrent_Device_Idx
* is currently set to" * is currently set to"
* If valid idx, will set iCurrent_Device_Idx with the idx * If valid idx, will set iCurrent_Device_Idx with the idx
* @return Pointer to the requested Device Object data, or NULL if the idx * @return Pointer to the requested Device Object data, or NULL if the idx
* is for an invalid row entry (eg, after the last good Device). * is for an invalid row entry (eg, after the last good Device).
*/ */
DEVICE_OBJECT_DATA *Get_Routed_Device_Object( DEVICE_OBJECT_DATA *Get_Routed_Device_Object(
@@ -168,7 +174,7 @@ DEVICE_OBJECT_DATA *Get_Routed_Device_Object(
* -1 is a special case meaning "whichever iCurrent_Device_Idx * -1 is a special case meaning "whichever iCurrent_Device_Idx
* is currently set to" * is currently set to"
* If valid idx, will set iCurrent_Device_Idx with the idx * If valid idx, will set iCurrent_Device_Idx with the idx
* @return Pointer to the requested Device Object BACnet address, or NULL if the idx * @return Pointer to the requested Device Object BACnet address, or NULL if the idx
* is for an invalid row entry (eg, after the last good Device). * is for an invalid row entry (eg, after the last good Device).
*/ */
BACNET_ADDRESS *Get_Routed_Device_Address( BACNET_ADDRESS *Get_Routed_Device_Address(
@@ -186,9 +192,9 @@ BACNET_ADDRESS *Get_Routed_Device_Address(
/** Get the currently active BACnet address. /** Get the currently active BACnet address.
* This is an implementation of the datalink_get_my_address() template for * This is an implementation of the datalink_get_my_address() template for
* devices with routing. * devices with routing.
* *
* @param my_address [out] Points to the currently active Device Object's * @param my_address [out] Points to the currently active Device Object's
* BACnet address. * BACnet address.
*/ */
@@ -205,18 +211,18 @@ void routed_get_my_address(
/** See if the Gateway or Routed Device at the given idx matches /** See if the Gateway or Routed Device at the given idx matches
* the given MAC address. * the given MAC address.
* Has the desirable side-effect of setting iCurrent_Device_Idx to the * Has the desirable side-effect of setting iCurrent_Device_Idx to the
* given idx if a match is found, for use in the subsequent routing handling * given idx if a match is found, for use in the subsequent routing handling
* functions here. * functions here.
* *
* @param idx [in] Index into Devices[] array being requested. * @param idx [in] Index into Devices[] array being requested.
* 0 is for the main, gateway Device entry. * 0 is for the main, gateway Device entry.
* @param address_len [in] Length of the mac_adress[] field. * @param address_len [in] Length of the mac_adress[] field.
* If 0, then this is a MAC broadcast. Otherwise, size is determined * If 0, then this is a MAC broadcast. Otherwise, size is determined
* by the DLL type (eg, 6 for BIP and 2 for MSTP). * by the DLL type (eg, 6 for BIP and 2 for MSTP).
* @param mac_adress [in] The desired MAC address of a Device; * @param mac_adress [in] The desired MAC address of a Device;
* *
* @return True if the MAC addresses match (or the address_len is 0, * @return True if the MAC addresses match (or the address_len is 0,
* meaning MAC broadcast, so it's an automatic match). * meaning MAC broadcast, so it's an automatic match).
* Else False if no match or invalid idx is given. * Else False if no match or invalid idx is given.
*/ */
bool Routed_Device_Address_Lookup( bool Routed_Device_Address_Lookup(
@@ -248,29 +254,29 @@ bool Routed_Device_Address_Lookup(
} }
/** Find the next Gateway or Routed Device at the given MAC address, /** Find the next Gateway or Routed Device at the given MAC address,
* starting the search at the "cursor". * starting the search at the "cursor".
* Has the desirable side-effect of setting internal iCurrent_Device_Idx * Has the desirable side-effect of setting internal iCurrent_Device_Idx
* if a match is found, for use in the subsequent routing handling * if a match is found, for use in the subsequent routing handling
* functions. * functions.
* *
* @param dest [in] The BACNET_ADDRESS of the message's destination. * @param dest [in] The BACNET_ADDRESS of the message's destination.
* If the Length of the mac_adress[] field is 0, then this is a MAC * If the Length of the mac_adress[] field is 0, then this is a MAC
* broadcast. Otherwise, size is determined * broadcast. Otherwise, size is determined
* by the DLL type (eg, 6 for BIP and 2 for MSTP). * by the DLL type (eg, 6 for BIP and 2 for MSTP).
* @param DNET_list [in] List of our reachable downstream BACnet Network numbers. * @param DNET_list [in] List of our reachable downstream BACnet Network numbers.
* Normally just one valid entry; terminated with a -1 value. * Normally just one valid entry; terminated with a -1 value.
* @param cursor [in,out] The concept of the cursor is that it is a starting * @param cursor [in,out] The concept of the cursor is that it is a starting
* "hint" for the search; on return, it is updated to provide the * "hint" for the search; on return, it is updated to provide the
* cursor value to use with a subsequent GetNext call, or it * cursor value to use with a subsequent GetNext call, or it
* equals -1 if there are no further matches. * equals -1 if there are no further matches.
* Set it to 0 on entry to access the main, gateway Device entry, or * Set it to 0 on entry to access the main, gateway Device entry, or
* to start looping through the routed devices. * to start looping through the routed devices.
* Otherwise, its returned value is implementation-dependent and the * Otherwise, its returned value is implementation-dependent and the
* calling function should not alter or interpret it. * calling function should not alter or interpret it.
* *
* @return True if the MAC addresses match (or if BACNET_BROADCAST_NETWORK and * @return True if the MAC addresses match (or if BACNET_BROADCAST_NETWORK and
* the dest->len is 0, meaning MAC bcast, so it's an automatic match). * the dest->len is 0, meaning MAC bcast, so it's an automatic match).
* Else False if no match or invalid idx is given; the cursor will * Else False if no match or invalid idx is given; the cursor will
* be returned as -1 in these cases. * be returned as -1 in these cases.
*/ */
@@ -289,14 +295,14 @@ bool Routed_Device_GetNext(
if ((idx < 0) || (idx >= MAX_NUM_DEVICES)) if ((idx < 0) || (idx >= MAX_NUM_DEVICES))
idx = -1; idx = -1;
/* Next, see if it's a BACnet broadcast. /* Next, see if it's a BACnet broadcast.
* For broadcasts, all Devices get a chance at it. * For broadcasts, all Devices get a chance at it.
*/ */
else if (dest->net == BACNET_BROADCAST_NETWORK) { else if (dest->net == BACNET_BROADCAST_NETWORK) {
/* Just take the entry indexed by the cursor */ /* Just take the entry indexed by the cursor */
bSuccess = Routed_Device_Address_Lookup(idx++, dest->len, dest->adr); bSuccess = Routed_Device_Address_Lookup(idx++, dest->len, dest->adr);
} }
/* Or see if it's for the main Gateway Device, because /* Or see if it's for the main Gateway Device, because
* there's no routing info. * there's no routing info.
*/ */
else if (dest->net == 0) { else if (dest->net == 0) {
@@ -335,15 +341,15 @@ bool Routed_Device_GetNext(
/** Check if the destination network is reachable - is it our virtual network, /** Check if the destination network is reachable - is it our virtual network,
* or local or else broadcast. * or local or else broadcast.
* *
* @param dest_net [in] The BACnet network number of a message's destination. * @param dest_net [in] The BACnet network number of a message's destination.
* Success if it is our virtual network number, or 0 (local for the * Success if it is our virtual network number, or 0 (local for the
* gateway, or 0xFFFF for a broadcast network number. * gateway, or 0xFFFF for a broadcast network number.
* @param DNET_list [in] List of our reachable downstream BACnet Network numbers. * @param DNET_list [in] List of our reachable downstream BACnet Network numbers.
* Normally just one valid entry; terminated with a -1 value. * Normally just one valid entry; terminated with a -1 value.
* @return True if matches our virtual network, or is for the local network * @return True if matches our virtual network, or is for the local network
* Device (the gateway), or is BACNET_BROADCAST_NETWORK, which is * Device (the gateway), or is BACNET_BROADCAST_NETWORK, which is
* an automatic match. * an automatic match.
* Else False if not a reachable network. * Else False if not a reachable network.
*/ */
bool Routed_Device_Is_Valid_Network( bool Routed_Device_Is_Valid_Network(
@@ -356,7 +362,7 @@ bool Routed_Device_Is_Valid_Network(
/* First, see if it's a BACnet broadcast (automatic pass). */ /* First, see if it's a BACnet broadcast (automatic pass). */
if (dest_net == BACNET_BROADCAST_NETWORK) if (dest_net == BACNET_BROADCAST_NETWORK)
bSuccess = true; bSuccess = true;
/* Or see if it's for the main Gateway Device, because /* Or see if it's for the main Gateway Device, because
* there's no routing info. * there's no routing info.
*/ */
else if (dest_net == 0) else if (dest_net == 0)
@@ -378,12 +384,12 @@ uint32_t Routed_Device_Index_To_Instance(
return Devices[iCurrent_Device_Idx].bacObj.Object_Instance_Number; return Devices[iCurrent_Device_Idx].bacObj.Object_Instance_Number;
} }
/** See if the requested Object instance matches that for the currently /** See if the requested Object instance matches that for the currently
* indexed Device Object. * indexed Device Object.
* iCurrent_Device_Idx must have been set to point to this Device Object * iCurrent_Device_Idx must have been set to point to this Device Object
* before this function is called. * before this function is called.
* @param object_id [in] Object ID of the desired Device object. * @param object_id [in] Object ID of the desired Device object.
* If the wildcard value (BACNET_MAX_INSTANCE), always matches. * If the wildcard value (BACNET_MAX_INSTANCE), always matches.
* @return True if Object ID matches the present Device, else False. * @return True if Object ID matches the present Device, else False.
*/ */
bool Routed_Device_Valid_Object_Instance_Number( bool Routed_Device_Valid_Object_Instance_Number(
@@ -497,8 +503,9 @@ bool Routed_Device_Write_Property_Local(
WPValidateString(&value, MAX_DEV_NAME_LEN, false, WPValidateString(&value, MAX_DEV_NAME_LEN, false,
&wp_data->error_class, &wp_data->error_code); &wp_data->error_class, &wp_data->error_code);
if (status) { if (status) {
Routed_Device_Set_Object_Name(characterstring_value Routed_Device_Set_Object_Name(
(&value.type.Character_String), characterstring_encoding(&value.type.Character_String),
characterstring_value(&value.type.Character_String),
characterstring_length(&value.type.Character_String)); characterstring_length(&value.type.Character_String));
} }
break; break;
@@ -512,9 +519,9 @@ bool Routed_Device_Write_Property_Local(
/* methods to manipulate the data */ /* methods to manipulate the data */
/** Return the Object Instance number for the currently active Device Object. /** Return the Object Instance number for the currently active Device Object.
* This is an overload of the important, widely used * This is an overload of the important, widely used
* Device_Object_Instance_Number() function. * Device_Object_Instance_Number() function.
* *
* @return The Instance number of the currently active Device. * @return The Instance number of the currently active Device.
*/ */
uint32_t Routed_Device_Object_Instance_Number( uint32_t Routed_Device_Object_Instance_Number(
@@ -538,24 +545,24 @@ bool Routed_Device_Set_Object_Instance_Number(
return status; return status;
} }
/** Sets the Object Name for a routed Device (or the gateway). /** Sets the Object Name for a routed Device (or the gateway).
* Uses local variable iCurrent_Device_Idx to know which Device * Uses local variable iCurrent_Device_Idx to know which Device
* is to be updated. * is to be updated.
* @param name [in] Text for the new Object Name. * @param object_name [in] Character String for the new Object Name.
* @param length [in] Length of name[] text.
* @return True if succeed in updating Object Name, else False. * @return True if succeed in updating Object Name, else False.
*/ */
bool Routed_Device_Set_Object_Name( bool Routed_Device_Set_Object_Name(
const char *name, uint8_t encoding,
size_t length) const char *value,
size_t length);
{ {
bool status = false; /*return value */ bool status = false; /*return value */
DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx]; DEVICE_OBJECT_DATA *pDev = &Devices[iCurrent_Device_Idx];
if (length < MAX_DEV_NAME_LEN) { if ((encoding == CHARACTER_UTF8) &&
(length < MAX_DEV_NAME_LEN)) {
/* Make the change and update the database revision */ /* Make the change and update the database revision */
memmove(pDev->bacObj.Object_Name, name, length); memmove(pDev->bacObj.Object_Name, value, length);
pDev->bacObj.Object_Name[length] = 0; pDev->bacObj.Object_Name[length] = 0;
Routed_Device_Inc_Database_Revision(); Routed_Device_Inc_Database_Revision();
status = true; status = true;
@@ -581,7 +588,7 @@ bool Routed_Device_Set_Description(
} }
/* /*
* Shortcut for incrementing database revision as this is potentially * Shortcut for incrementing database revision as this is potentially
* the most common operation if changing object names and ids is * the most common operation if changing object names and ids is
* implemented. * implemented.
+7 -6
View File
@@ -272,17 +272,19 @@ static BACNET_SHED_STATE Load_Control_Present_Value(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Load_Control_Name( bool Load_Control_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_LOAD_CONTROLS) { if (object_instance < MAX_LOAD_CONTROLS) {
sprintf(text_string, "LOAD CONTROL %u", object_instance); sprintf(text_string, "LOAD CONTROL %u", object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
static void Update_Current_Time( static void Update_Current_Time(
@@ -706,8 +708,7 @@ int Load_Control_Read_Property(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Load_Control_Object_Name(rpdata->object_instance, &char_string);
Load_Control_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+5 -3
View File
@@ -51,8 +51,10 @@ extern "C" {
unsigned index); unsigned index);
unsigned Load_Control_Instance_To_Index( unsigned Load_Control_Instance_To_Index(
uint32_t object_instance); uint32_t object_instance);
char *Load_Control_Name(
uint32_t object_instance); bool Load_Control_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
void Load_Control_Init( void Load_Control_Init(
void); void);
@@ -77,7 +79,7 @@ extern "C" {
#define LOAD_CONTROL_OBJ_FUNCTIONS \ #define LOAD_CONTROL_OBJ_FUNCTIONS \
OBJECT_LOAD_CONTROL, Load_Control_Init, Load_Control_Count, \ OBJECT_LOAD_CONTROL, Load_Control_Init, Load_Control_Count, \
Load_Control_Index_To_Instance, Load_Control_Valid_Instance, \ Load_Control_Index_To_Instance, Load_Control_Valid_Instance, \
Load_Control_Name, Load_Control_Read_Property, \ Load_Control_Object_Name, Load_Control_Read_Property, \
Load_Control_Write_Property, Load_Control_Property_Lists, NULL, \ Load_Control_Write_Property, Load_Control_Property_Lists, NULL, \
NULL NULL
#endif #endif
+7 -6
View File
@@ -173,17 +173,19 @@ static BACNET_LIFE_SAFETY_STATE Life_Safety_Point_Present_Value(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Life_Safety_Point_Name( bool Life_Safety_Point_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_LIFE_SAFETY_POINTS) { if (object_instance < MAX_LIFE_SAFETY_POINTS) {
sprintf(text_string, "LS POINT %u", object_instance); sprintf(text_string, "LS POINT %u", object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
/* return apdu len, or BACNET_STATUS_ERROR on error */ /* return apdu len, or BACNET_STATUS_ERROR on error */
@@ -216,8 +218,7 @@ int Life_Safety_Point_Read_Property(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Life_Safety_Point_Object_Name(rpdata->object_instance, &char_string);
Life_Safety_Point_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+4 -3
View File
@@ -48,8 +48,9 @@ extern "C" {
unsigned index); unsigned index);
unsigned Life_Safety_Point_Instance_To_Index( unsigned Life_Safety_Point_Instance_To_Index(
uint32_t object_instance); uint32_t object_instance);
char *Life_Safety_Point_Name( bool Life_Safety_Point_Object_Name(
uint32_t object_instance); uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
void Life_Safety_Point_Init( void Life_Safety_Point_Init(
void); void);
@@ -71,7 +72,7 @@ extern "C" {
#define LIFE_SAFETY_POINT_OBJ_FUNCTIONS \ #define LIFE_SAFETY_POINT_OBJ_FUNCTIONS \
OBJECT_LIFE_SAFETY_POINT, Life_Safety_Point_Init, \ OBJECT_LIFE_SAFETY_POINT, Life_Safety_Point_Init, \
Life_Safety_Point_Count, Life_Safety_Point_Index_To_Instance, \ Life_Safety_Point_Count, Life_Safety_Point_Index_To_Instance, \
Life_Safety_Point_Valid_Instance, Life_Safety_Point_Name, \ Life_Safety_Point_Valid_Instance, Life_Safety_Point_Object_Name, \
Life_Safety_Point_Read_Property, \ Life_Safety_Point_Read_Property, \
Life_Safety_Point_Write_Property, \ Life_Safety_Point_Write_Property, \
Life_Safety_Point_Property_Lists, NULL, NULL Life_Safety_Point_Property_Lists, NULL, NULL
+7 -7
View File
@@ -225,18 +225,19 @@ bool Multistate_Input_Description_Set(
return status; return status;
} }
char *Multistate_Input_Name( bool Multistate_Input_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
unsigned index = 0; /* offset from instance lookup */ unsigned index = 0; /* offset from instance lookup */
char *pName = NULL; /* return value */ bool status = false;
index = Multistate_Input_Instance_To_Index(object_instance); index = Multistate_Input_Instance_To_Index(object_instance);
if (index < MAX_MULTISTATE_INPUTS) { if (index < MAX_MULTISTATE_INPUTS) {
pName = Object_Name[index]; status = characterstring_init_ansi(object_name, Object_Name[index]);
} }
return pName; return status;
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
@@ -347,8 +348,7 @@ int Multistate_Input_Read_Property(
/* note: Name and Description don't have to be the same. /* note: Name and Description don't have to be the same.
You could make Description writable and different */ You could make Description writable and different */
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
characterstring_init_ansi(&char_string, Multistate_Input_Object_Name(rpdata->object_instance, &char_string);
Multistate_Input_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+6 -3
View File
@@ -59,11 +59,14 @@ extern "C" {
/* optional API */ /* optional API */
bool Multistate_Input_Object_Instance_Add( bool Multistate_Input_Object_Instance_Add(
uint32_t instance); uint32_t instance);
char *Multistate_Input_Name(
uint32_t object_instance); bool Multistate_Input_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
bool Multistate_Input_Name_Set( bool Multistate_Input_Name_Set(
uint32_t object_instance, uint32_t object_instance,
char *new_name); char *new_name);
uint32_t Multistate_Input_Present_Value( uint32_t Multistate_Input_Present_Value(
uint32_t object_instance); uint32_t object_instance);
bool Multistate_Input_Present_Value_Set( bool Multistate_Input_Present_Value_Set(
@@ -96,7 +99,7 @@ extern "C" {
#define MULTI_STATE_INPUT_OBJ_FUNCTIONS \ #define MULTI_STATE_INPUT_OBJ_FUNCTIONS \
OBJECT_MULTI_STATE_INPUT, Multistate_Input_Init, \ OBJECT_MULTI_STATE_INPUT, Multistate_Input_Init, \
Multistate_Input_Count, Multistate_Input_Index_To_Instance, \ Multistate_Input_Count, Multistate_Input_Index_To_Instance, \
Multistate_Input_Valid_Instance, Multistate_Input_Name, \ Multistate_Input_Valid_Instance, Multistate_Input_Object_Name, \
Multistate_Input_Read_Property, \ Multistate_Input_Read_Property, \
Multistate_Input_Write_Property, \ Multistate_Input_Write_Property, \
Multistate_Input_Property_Lists, NULL, NULL Multistate_Input_Property_Lists, NULL, NULL
+7 -6
View File
@@ -180,17 +180,19 @@ static uint32_t Multistate_Output_Present_Value(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Multistate_Output_Name( bool Multistate_Output_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_MULTISTATE_OUTPUTS) { if (object_instance < MAX_MULTISTATE_OUTPUTS) {
sprintf(text_string, "MULTISTATE OUTPUT %u", object_instance); sprintf(text_string, "MULTISTATE OUTPUT %u", object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
/* return apdu len, or BACNET_STATUS_ERROR on error */ /* return apdu len, or BACNET_STATUS_ERROR on error */
@@ -222,8 +224,7 @@ int Multistate_Output_Read_Property(
You could make Description writable and different */ You could make Description writable and different */
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Multistate_Output_Object_Name(rpdata->object_instance, &char_string);
Multistate_Output_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+5 -3
View File
@@ -48,8 +48,10 @@ extern "C" {
unsigned index); unsigned index);
unsigned Multistate_Output_Instance_To_Index( unsigned Multistate_Output_Instance_To_Index(
uint32_t object_instance); uint32_t object_instance);
char *Multistate_Output_Name(
uint32_t object_instance); bool Multistate_Output_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
void Multistate_Output_Init( void Multistate_Output_Init(
void); void);
@@ -72,7 +74,7 @@ extern "C" {
#define MULTI_STATE_OUTPUT_OBJ_FUNCTIONS \ #define MULTI_STATE_OUTPUT_OBJ_FUNCTIONS \
OBJECT_MULTI_STATE_OUTPUT, Multistate_Output_Init, \ OBJECT_MULTI_STATE_OUTPUT, Multistate_Output_Init, \
Multistate_Output_Count, Multistate_Output_Index_To_Instance, \ Multistate_Output_Count, Multistate_Output_Index_To_Instance, \
Multistate_Output_Valid_Instance, Multistate_Output_Name, \ Multistate_Output_Valid_Instance, Multistate_Output_Object_Name, \
Multistate_Output_Read_Property, \ Multistate_Output_Read_Property, \
Multistate_Output_Write_Property, \ Multistate_Output_Write_Property, \
Multistate_Output_Property_Lists, NULL, NULL Multistate_Output_Property_Lists, NULL, NULL
+19 -18
View File
@@ -80,7 +80,7 @@ static const int Trend_Log_Properties_Optional[] = {
PROP_COV_RESUBSCRIPTION_INTERVAL, PROP_COV_RESUBSCRIPTION_INTERVAL,
PROP_CLIENT_COV_INCREMENT, */ PROP_CLIENT_COV_INCREMENT, */
/* Required if intrinsic reporting supported /* Required if intrinsic reporting supported
PROP_NOTIFICATION_THRESHOLD, PROP_NOTIFICATION_THRESHOLD,
PROP_RECORDS_SINCE_NOTIFICATION, PROP_RECORDS_SINCE_NOTIFICATION,
PROP_LAST_NOTIFY_RECORD, PROP_LAST_NOTIFY_RECORD,
@@ -179,7 +179,7 @@ void Trend_Log_Init(
/* initialize all the values */ /* initialize all the values */
for (iLog = 0; iLog < MAX_TREND_LOGS; iLog++) { for (iLog = 0; iLog < MAX_TREND_LOGS; iLog++) {
/* /*
* Do we need to do anything here? * Do we need to do anything here?
* Trend logs are usually assumed to survive over resets * Trend logs are usually assumed to survive over resets
* and are frequently implemented using Battery Backed RAM * and are frequently implemented using Battery Backed RAM
@@ -257,17 +257,19 @@ void Trend_Log_Init(
* on the assumption that there is a 1 to 1 correspondance. If there * on the assumption that there is a 1 to 1 correspondance. If there
* is not we need to convert to index before proceeding. * is not we need to convert to index before proceeding.
*/ */
char *Trend_Log_Name( bool Trend_Log_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
bool status = false;
if (object_instance < MAX_TREND_LOGS) { if (object_instance < MAX_TREND_LOGS) {
sprintf(text_string, "Trend Log %u", object_instance); sprintf(text_string, "Trend Log %u", object_instance);
return text_string; status = characterstring_init_ansi(object_name, text_string);
} }
return NULL; return status;
} }
@@ -298,8 +300,7 @@ int Trend_Log_Read_Property(
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
characterstring_init_ansi(&char_string, Trend_Log_Object_Name(rpdata->object_instance, &char_string);
Trend_Log_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
@@ -496,14 +497,14 @@ bool Trend_Log_Write_Property(
/* To do: what actions do we need to take on writing ? */ /* To do: what actions do we need to take on writing ? */
if (value.type.Boolean == false) { if (value.type.Boolean == false) {
if (bEffectiveEnable == true) { if (bEffectiveEnable == true) {
/* Only insert record if we really were /* Only insert record if we really were
enabled i.e. times and enable flags */ enabled i.e. times and enable flags */
TL_Insert_Status_Rec(log_index, TL_Insert_Status_Rec(log_index,
LOG_STATUS_LOG_DISABLED, true); LOG_STATUS_LOG_DISABLED, true);
} }
} else { } else {
if (TL_Is_Enabled(log_index)) { if (TL_Is_Enabled(log_index)) {
/* Have really gone from disabled to enabled as /* Have really gone from disabled to enabled as
* enable flag and times were correct * enable flag and times were correct
*/ */
TL_Insert_Status_Rec(log_index, TL_Insert_Status_Rec(log_index,
@@ -563,7 +564,7 @@ bool Trend_Log_Write_Property(
break; break;
case PROP_LOGGING_TYPE: case PROP_LOGGING_TYPE:
/* logic /* logic
* triggered and polled options. * triggered and polled options.
*/ */
status = status =
@@ -1016,7 +1017,7 @@ time_t TL_BAC_Time_To_Local(
LocalTime.tm_year = SourceTime->date.year - 1900; /* We store BACnet year in full format */ LocalTime.tm_year = SourceTime->date.year - 1900; /* We store BACnet year in full format */
/* Some clients send a date of all 0s to indicate start of epoch /* Some clients send a date of all 0s to indicate start of epoch
* even though this is not a valid date. Pick this up here and * even though this is not a valid date. Pick this up here and
* correct the day and month for the local time functions. * correct the day and month for the local time functions.
*/ */
iTemp = iTemp =
@@ -1151,7 +1152,7 @@ int TL_encode_by_position(
* start index/positive count and then process as * start index/positive count and then process as
* normal. This assumes that the order to return items * normal. This assumes that the order to return items
* is always first to last, if this is not true we will * is always first to last, if this is not true we will
* have to handle this differently. * have to handle this differently.
* *
* Note: We need to be careful about how we convert these * Note: We need to be careful about how we convert these
* values due to the mix of signed and unsigned types - don't * values due to the mix of signed and unsigned types - don't
@@ -1184,7 +1185,7 @@ int TL_encode_by_position(
while (uiIndex <= uiTarget) { while (uiIndex <= uiTarget) {
if (uiRemaining < TL_MAX_ENC) { if (uiRemaining < TL_MAX_ENC) {
/* /*
* Can't fit any more in! We just set the result flag to say there * Can't fit any more in! We just set the result flag to say there
* was more and drop out of the loop early * was more and drop out of the loop early
*/ */
bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS, bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS,
@@ -1318,7 +1319,7 @@ int TL_encode_by_sequence(
while (uiSequence != uiEnd + 1) { while (uiSequence != uiEnd + 1) {
if (uiRemaining < TL_MAX_ENC) { if (uiRemaining < TL_MAX_ENC) {
/* /*
* Can't fit any more in! We just set the result flag to say there * Can't fit any more in! We just set the result flag to say there
* was more and drop out of the loop early * was more and drop out of the loop early
*/ */
bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS, bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS,
@@ -1410,7 +1411,7 @@ int TL_encode_by_time(
pRequest->Count = -pRequest->Count; /* Conveert to +ve count */ pRequest->Count = -pRequest->Count; /* Conveert to +ve count */
/* If count would bring us back beyond the limits /* If count would bring us back beyond the limits
* Of the buffer then pin it to the start of the buffer * Of the buffer then pin it to the start of the buffer
* otherwise adjust starting point and sequence number * otherwise adjust starting point and sequence number
* appropriately. * appropriately.
*/ */
iTemp = pRequest->Count - 1; iTemp = pRequest->Count - 1;
@@ -1450,7 +1451,7 @@ int TL_encode_by_time(
while (iCount != 0) { while (iCount != 0) {
if (uiRemaining < TL_MAX_ENC) { if (uiRemaining < TL_MAX_ENC) {
/* /*
* Can't fit any more in! We just set the result flag to say there * Can't fit any more in! We just set the result flag to say there
* was more and drop out of the loop early * was more and drop out of the loop early
*/ */
bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS, bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS,
@@ -1819,7 +1820,7 @@ void trend_log_timer(
/* Also record value if we have waited more than a period /* Also record value if we have waited more than a period
* since the last reading. This ensures we take a reading as * since the last reading. This ensures we take a reading as
* soon as possible after a power down if we have been off for * soon as possible after a power down if we have been off for
* more than a single period. * more than a single period.
*/ */
TL_fetch_property(iCount); TL_fetch_property(iCount);
} }
+5 -4
View File
@@ -104,7 +104,7 @@ extern "C" {
time_t tLastDataTime; time_t tLastDataTime;
} TL_LOG_INFO; } TL_LOG_INFO;
/* /*
* Data types associated with a BACnet Log Record. We use these for managing the * Data types associated with a BACnet Log Record. We use these for managing the
* log buffer but they are also the tag numbers to use when encoding/decoding * log buffer but they are also the tag numbers to use when encoding/decoding
* the log datum field. * the log datum field.
@@ -139,8 +139,9 @@ extern "C" {
bool Trend_Log_Object_Instance_Add( bool Trend_Log_Object_Instance_Add(
uint32_t instance); uint32_t instance);
char *Trend_Log_Name( bool Trend_Log_Object_Name(
uint32_t object_instance); uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name);
int Trend_Log_Read_Property( int Trend_Log_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata); BACNET_READ_PROPERTY_DATA * rpdata);
@@ -199,7 +200,7 @@ extern "C" {
#define TRENDLOG_OBJ_FUNCTIONS \ #define TRENDLOG_OBJ_FUNCTIONS \
OBJECT_TRENDLOG, Trend_Log_Init, Trend_Log_Count, \ OBJECT_TRENDLOG, Trend_Log_Init, Trend_Log_Count, \
Trend_Log_Index_To_Instance, Trend_Log_Valid_Instance, \ Trend_Log_Index_To_Instance, Trend_Log_Valid_Instance, \
Trend_Log_Name, Trend_Log_Read_Property, \ Trend_Log_Object_Name, Trend_Log_Read_Property, \
Trend_Log_Write_Property, Trend_Log_Property_Lists, \ Trend_Log_Write_Property, Trend_Log_Property_Lists, \
TrendLogGetRRInfo, NULL TrendLogGetRRInfo, NULL
#endif #endif
+6 -1
View File
@@ -66,6 +66,11 @@ uint8_t Send_Private_Transfer_Request(
char block_number, char block_number,
DATABLOCK * block); DATABLOCK * block);
/* All included BACnet objects */
static object_functions_t Object_Table[] = {
{DEVICE_OBJ_FUNCTIONS},
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
};
/* buffer used for receive */ /* buffer used for receive */
static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
@@ -124,7 +129,7 @@ void MyRejectHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Init(); Device_Init(&Object_Table[0]);
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -185,8 +185,7 @@ static void LocalIAmHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -149,8 +149,7 @@ void My_Read_Property_Ack_Handler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -194,8 +194,7 @@ void My_Read_Property_Multiple_Ack_Handler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+6 -8
View File
@@ -80,13 +80,11 @@
#define _stricmp stricmp #define _stricmp stricmp
#endif #endif
uint8_t Send_Private_Transfer_Request( /* All included BACnet objects */
uint32_t device_id, static object_functions_t Object_Table[] = {
uint16_t vendor_id, {DEVICE_OBJ_FUNCTIONS},
uint32_t service_number, {MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
char block_number, };
DATABLOCK * block);
/* buffer used for receive */ /* buffer used for receive */
static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
@@ -145,7 +143,7 @@ void MyRejectHandler(
static void Init_Objects( static void Init_Objects(
void) void)
{ {
Device_Init(); Device_Init(&Object_Table[0]);
} }
static void Init_Service_Handlers( static void Init_Service_Handlers(
+1 -2
View File
@@ -120,8 +120,7 @@ void MyReinitializeDeviceSimpleAckHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -101,8 +101,7 @@ static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is to support dynamic device binding */ /* we need to handle who-is to support dynamic device binding */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_HAS, handler_who_has); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_HAS, handler_who_has);
+1 -2
View File
@@ -92,8 +92,7 @@ void MyRejectHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -59,8 +59,7 @@ static object_functions_t Object_Table[] = {
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -95,8 +95,7 @@ void MyRejectHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -95,8 +95,7 @@ void MyRejectHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* Note: this applications doesn't need to handle who-is /* Note: this applications doesn't need to handle who-is
it is confusing for the user! */ it is confusing for the user! */
/* set the handler for all the services we don't implement /* set the handler for all the services we don't implement
+1 -2
View File
@@ -175,8 +175,7 @@ void My_NPDU_Handler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -139,8 +139,7 @@ static void LocalIAmHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -2
View File
@@ -140,8 +140,7 @@ void MyWritePropertySimpleAckHandler(
static void Init_Service_Handlers( static void Init_Service_Handlers(
void) void)
{ {
Device_Initialize_Object_Functions(&Object_Table[0]); Device_Init(&Object_Table[0]);
Device_Init();
/* we need to handle who-is /* we need to handle who-is
to support dynamic device binding to us */ to support dynamic device binding to us */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
+1 -1
View File
@@ -952,7 +952,7 @@ typedef enum {
} BACNET_VT_CLASS; } BACNET_VT_CLASS;
typedef enum { typedef enum {
CHARACTER_ANSI_X34 = 0, CHARACTER_ANSI_X34 = 0, /* deprecated */
CHARACTER_UTF8 = 0, CHARACTER_UTF8 = 0,
CHARACTER_MS_DBCS = 1, CHARACTER_MS_DBCS = 1,
CHARACTER_JISC_6226 = 2, CHARACTER_JISC_6226 = 2,
+2
View File
@@ -153,6 +153,8 @@ extern "C" {
BACNET_CHARACTER_STRING * char_string); BACNET_CHARACTER_STRING * char_string);
bool characterstring_printable( bool characterstring_printable(
BACNET_CHARACTER_STRING * char_string); BACNET_CHARACTER_STRING * char_string);
bool characterstring_valid(
BACNET_CHARACTER_STRING * char_string);
/* returns false if the string exceeds capacity /* returns false if the string exceeds capacity
initialize by using length=0 */ initialize by using length=0 */
+1 -1
View File
@@ -97,7 +97,7 @@ extern "C" {
uint32_t device_id, uint32_t device_id,
BACNET_OBJECT_TYPE object_type, BACNET_OBJECT_TYPE object_type,
uint32_t object_instance, uint32_t object_instance,
const char *object_name); BACNET_CHARACTER_STRING *object_name);
int Send_UCOV_Notify( int Send_UCOV_Notify(
uint8_t * buffer, uint8_t * buffer,
+9 -9
View File
@@ -41,7 +41,7 @@
typedef struct BACnet_Who_Has_Data { typedef struct BACnet_Who_Has_Data {
int32_t low_limit; /* deviceInstanceRange */ int32_t low_limit; /* deviceInstanceRange */
int32_t high_limit; int32_t high_limit;
bool object_name; /* true if a string */ bool is_object_name; /* true if a string */
union { union {
BACNET_OBJECT_ID identifier; BACNET_OBJECT_ID identifier;
BACNET_CHARACTER_STRING name; BACNET_CHARACTER_STRING name;
@@ -79,14 +79,14 @@ extern "C" {
/** @defgroup DMDOB Device Management-Dynamic Object Binding (DM-DOB) /** @defgroup DMDOB Device Management-Dynamic Object Binding (DM-DOB)
* @ingroup RDMS * @ingroup RDMS
* 16.9 Who-Has and I-Have Services <br> * 16.9 Who-Has and I-Have Services <br>
* The Who-Has service is used by a sending BACnet-user to identify the device * The Who-Has service is used by a sending BACnet-user to identify the device
* object identifiers and network addresses of other BACnet devices whose local * object identifiers and network addresses of other BACnet devices whose local
* databases contain an object with a given Object_Name or a given Object_Identifier. * databases contain an object with a given Object_Name or a given Object_Identifier.
* The I-Have service is used to respond to Who-Has service requests or to * The I-Have service is used to respond to Who-Has service requests or to
* advertise the existence of an object with a given Object_Name or * advertise the existence of an object with a given Object_Name or
* Object_Identifier. The I-Have service request may be issued at any time and * Object_Identifier. The I-Have service request may be issued at any time and
* does not need to be preceded by the receipt of a Who-Has service request. * does not need to be preceded by the receipt of a Who-Has service request.
* The Who-Has and I-Have services are unconfirmed services. * The Who-Has and I-Have services are unconfirmed services.
* *
*/ */
#endif #endif
+4
View File
@@ -22,8 +22,12 @@ BACNET_FLAGS += -DCRC_USE_TABLE
BACNET_CORE = ../../src BACNET_CORE = ../../src
BACNET_DEMO = ../../demo BACNET_DEMO = ../../demo
BACNET_INCLUDE = ../../include BACNET_INCLUDE = ../../include
BACNET_OBJECT = ../../demo/object
BACNET_HANDLER = ../../demo/handler
INCLUDES = -I. INCLUDES = -I.
INCLUDES += -I$(BACNET_INCLUDE) INCLUDES += -I$(BACNET_INCLUDE)
INCLUDES += -I$(BACNET_OBJECT)
INCLUDES += -I$(BACNET_HANDLER)
#OPTIMIZATION = -O0 #OPTIMIZATION = -O0
OPTIMIZATION = -Os OPTIMIZATION = -Os
CFLAGS = -fno-common $(INCLUDES) $(BACNET_FLAGS) -Wall -g CFLAGS = -fno-common $(INCLUDES) $(BACNET_FLAGS) -Wall -g
+7 -6
View File
@@ -107,17 +107,19 @@ uint32_t Analog_Input_Index_To_Instance(
return index; return index;
} }
char *Analog_Input_Name( bool Analog_Input_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[16] = "AI-0"; /* okay for single thread */ static char text_string[16] = "AI-0"; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ANALOG_INPUTS) { if (object_instance < MAX_ANALOG_INPUTS) {
text_string[3] = '0' + (uint8_t) object_instance; 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( float Analog_Input_Present_Value(
@@ -165,8 +167,7 @@ int Analog_Input_Read_Property(
You could make Description writable and different */ You could make Description writable and different */
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Analog_Input_Object_Name(rpdata->object_instance, &char_string);
Analog_Input_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+7 -7
View File
@@ -165,18 +165,19 @@ float Analog_Value_Present_Value(
return value; return value;
} }
/* note: the object name must be unique within this device */ bool Analog_Value_Object_Name(
char *Analog_Value_Name( uint32_t object_instance,
uint32_t object_instance) BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[16] = "AV-0"; /* okay for single thread */ static char text_string[16] = "AV-0"; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ANALOG_VALUES) { if (object_instance < MAX_ANALOG_VALUES) {
text_string[3] = '0' + (uint8_t) object_instance; 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 */ /* return apdu len, or -1 on error */
@@ -208,8 +209,7 @@ int Analog_Value_Read_Property(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Analog_Value_Object_Name(rpdata->object_instance, &char_string);
Analog_Value_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+7 -7
View File
@@ -144,17 +144,19 @@ BACNET_BINARY_PV Binary_Input_Present_Value(
return value; return value;
} }
char *Binary_Input_Name( bool Binary_Input_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[16] = "BI-0"; /* okay for single thread */ static char text_string[16] = "BI-0"; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_INPUTS) { if (object_instance < MAX_BINARY_INPUTS) {
text_string[3] = '0' + (uint8_t) object_instance; 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 */ /* return apdu length, or -1 on error */
@@ -182,9 +184,7 @@ int Binary_Input_Read_Property(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
/* note: object name must be unique in our device */ Binary_Input_Object_Name(rpdata->object_instance, &char_string);
characterstring_init_ansi(&char_string,
Binary_Input_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+7 -6
View File
@@ -139,17 +139,19 @@ static BACNET_BINARY_PV Binary_Value_Present_Value(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Binary_Value_Name( bool Binary_Value_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[16] = "BV-0"; /* okay for single thread */ static char text_string[16] = "BV-0"; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_VALUES) { if (object_instance < MAX_BINARY_VALUES) {
text_string[3] = '0' + (uint8_t) object_instance; 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 */ /* return apdu len, or -1 on error */
@@ -179,8 +181,7 @@ int Binary_Value_Read_Property(
You could make Description writable and different */ You could make Description writable and different */
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, Binary_Value_Object_Name(rpdata->object_instance, &char_string);
Binary_Value_Name(rpdata->object_instance));
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
+362 -337
View File
@@ -25,13 +25,15 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "bacdef.h" #include "bacdef.h"
#include "bacdcode.h" #include "bacdcode.h"
#include "bacstr.h" #include "bacstr.h"
#include "bacenum.h" #include "bacenum.h"
#include "apdu.h" #include "apdu.h"
#include "dlmstp.h" #include "dcc.h"
#include "datalink.h"
#include "rs485.h" #include "rs485.h"
#include "version.h" #include "version.h"
#include "handlers.h" #include "handlers.h"
@@ -44,16 +46,7 @@
#include "wp.h" #include "wp.h"
#include "dcc.h" #include "dcc.h"
/* note: you really only need to define variables for /* forward prototype */
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 */
int Device_Read_Property_Local( int Device_Read_Property_Local(
BACNET_READ_PROPERTY_DATA * rpdata); BACNET_READ_PROPERTY_DATA * rpdata);
bool Device_Write_Property_Local( bool Device_Write_Property_Local(
@@ -73,28 +66,38 @@ static struct my_object_functions {
{ {
OBJECT_DEVICE, NULL, /* don't init - recursive! */ OBJECT_DEVICE, NULL, /* don't init - recursive! */
Device_Count, Device_Index_To_Instance, 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_Read_Property_Local, Device_Write_Property_Local,
Device_Property_Lists}, { Device_Property_Lists}, {
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, 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}, { Analog_Input_Property_Lists}, {
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, 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}, { Analog_Value_Write_Property, Analog_Value_Property_Lists}, {
OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count,
Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance, 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}, { Binary_Input_Property_Lists}, {
OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count, OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count,
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance, 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}, { Binary_Value_Write_Property, Binary_Value_Property_Lists}, {
MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL} 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 */ /* These three arrays are used by the ReadPropertyMultiple handler */
static const int Device_Properties_Required[] = { static const int Device_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_IDENTIFIER,
@@ -132,54 +135,92 @@ static const int Device_Properties_Proprietary[] = {
-1 -1
}; };
void Device_Property_Lists( static struct my_object_functions *Device_Objects_Find_Functions(
const int **pRequired, BACNET_OBJECT_TYPE Object_Type)
const int **pOptional,
const int **pProprietary)
{ {
if (pRequired) struct my_object_functions *pObject = NULL;
*pRequired = Device_Properties_Required;
if (pOptional)
*pOptional = Device_Properties_Optional;
if (pProprietary)
*pProprietary = Device_Properties_Proprietary;
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, /* 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( int Device_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata) BACNET_READ_PROPERTY_DATA * rpdata)
{ {
int apdu_len = BACNET_STATUS_ERROR; int apdu_len = BACNET_STATUS_ERROR;
unsigned index = 0;
struct my_object_functions *pObject = NULL; struct my_object_functions *pObject = NULL;
bool found = false;
/* initialize the default return values */ /* initialize the default return values */
rpdata->error_class = ERROR_CLASS_OBJECT; pObject = Device_Objects_Find_Functions(rpdata->object_type);
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT; if (pObject) {
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;
if (pObject->Object_Valid_Instance && if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(rpdata->object_instance)) { pObject->Object_Valid_Instance(rpdata->object_instance)) {
if (pObject->Object_Read_Property) { apdu_len = Read_Property_Common(pObject, rpdata);
apdu_len = pObject->Object_Read_Property(rpdata);
}
} else { } else {
rpdata->error_class = ERROR_CLASS_OBJECT; rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT; rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
} }
break; } else {
}
index++;
pObject = &Object_Table[index];
}
if (!found) {
rpdata->error_class = ERROR_CLASS_OBJECT; rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE; rpdata->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
} }
@@ -191,18 +232,11 @@ bool Device_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data) BACNET_WRITE_PROPERTY_DATA * wp_data)
{ {
bool status = false; bool status = false;
unsigned index = 0;
struct my_object_functions *pObject = NULL; struct my_object_functions *pObject = NULL;
bool found = false;
/* initialize the default return values */ /* initialize the default return values */
wp_data->error_class = ERROR_CLASS_OBJECT; pObject = Device_Objects_Find_Functions(wp_data->object_type);
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; if (pObject) {
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;
if (pObject->Object_Valid_Instance && if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(wp_data->object_instance)) { pObject->Object_Valid_Instance(wp_data->object_instance)) {
if (pObject->Object_Write_Property) { if (pObject->Object_Write_Property) {
@@ -215,12 +249,7 @@ bool Device_Write_Property(
wp_data->error_class = ERROR_CLASS_OBJECT; wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
} }
break; } else {
}
index++;
pObject = &Object_Table[index];
}
if (!found) {
wp_data->error_class = ERROR_CLASS_OBJECT; wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE; wp_data->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
} }
@@ -248,59 +277,222 @@ void Device_Objects_Property_List(
BACNET_OBJECT_TYPE object_type, BACNET_OBJECT_TYPE object_type,
struct special_property_list_t *pPropertyList) struct special_property_list_t *pPropertyList)
{ {
rpm_property_lists_function object_property_list = NULL;
unsigned index = 0;
struct my_object_functions *pObject = NULL; struct my_object_functions *pObject = NULL;
bool found = false;
pPropertyList->Required.pList = NULL; pPropertyList->Required.pList = NULL;
pPropertyList->Optional.pList = NULL; pPropertyList->Optional.pList = NULL;
pPropertyList->Proprietary.pList = NULL; pPropertyList->Proprietary.pList = NULL;
pObject = &Object_Table[0];
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { /* If we can find an entry for the required object type
/* handle each object type */ * and there is an Object_List_RPM fn ptr then call it
if (pObject->Object_Type == object_type) { * to populate the pointers to the individual list counters.
found = true; */
object_property_list = pObject->Object_RPM_List;
break; pObject = Device_Objects_Find_Functions(object_type);
} if ((pObject != NULL) && (pObject->Object_RPM_List != NULL)) {
index++; pObject->Object_RPM_List(&pPropertyList->Required.pList,
pObject = &Object_Table[index];
}
if (found && object_property_list) {
object_property_list(&pPropertyList->Required.pList,
&pPropertyList->Optional.pList, &pPropertyList->Proprietary.pList); &pPropertyList->Optional.pList, &pPropertyList->Proprietary.pList);
} }
/* fill the count */
if (pPropertyList->Required.pList) { /* Fetch the counts if available otherwise zero them */
pPropertyList->Required.count = pPropertyList->Required.count =
property_list_count(pPropertyList->Required.pList); pPropertyList->Required.pList ==
} else { NULL ? 0 : property_list_count(pPropertyList->Required.pList);
pPropertyList->Required.count = 0;
} pPropertyList->Optional.count =
if (pPropertyList->Optional.pList) { pPropertyList->Optional.pList ==
pPropertyList->Optional.count = NULL ? 0 : property_list_count(pPropertyList->Optional.pList);
property_list_count(pPropertyList->Optional.pList);
} else { pPropertyList->Proprietary.count =
pPropertyList->Optional.count = 0; pPropertyList->Proprietary.pList ==
} NULL ? 0 : property_list_count(pPropertyList->Proprietary.pList);
if (pPropertyList->Proprietary.pList) {
pPropertyList->Proprietary.count =
property_list_count(pPropertyList->Proprietary.pList);
} else {
pPropertyList->Proprietary.count = 0;
}
return; 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 */ /* Since many network clients depend on the object list */
/* for discovery, it must be consistent! */ /* for discovery, it must be consistent! */
unsigned Device_Object_List_Count( unsigned Device_Object_List_Count(
void) void)
{ {
unsigned count = 0; /* number of objects */ unsigned count = 0; /* number of objects */
unsigned index = 0; /* loop counter */
struct my_object_functions *pObject = NULL; struct my_object_functions *pObject = NULL;
/* initialize the default return values */ /* initialize the default return values */
@@ -309,8 +501,7 @@ unsigned Device_Object_List_Count(
if (pObject->Object_Count) { if (pObject->Object_Count) {
count += pObject->Object_Count(); count += pObject->Object_Count();
} }
index++; pObject++;
pObject = &Object_Table[index];
} }
return count; return count;
@@ -324,7 +515,6 @@ bool Device_Object_List_Identifier(
bool status = false; bool status = false;
unsigned count = 0; unsigned count = 0;
unsigned object_index = 0; unsigned object_index = 0;
unsigned index = 0; /* loop counter */
struct my_object_functions *pObject = NULL; struct my_object_functions *pObject = NULL;
/* array index zero is length - so invalid */ /* array index zero is length - so invalid */
@@ -345,15 +535,14 @@ bool Device_Object_List_Identifier(
break; break;
} }
} }
index++; pObject++;
pObject = &Object_Table[index];
} }
return status; return status;
} }
bool Device_Valid_Object_Name( bool Device_Valid_Object_Name(
const char *object_name, BACNET_CHARACTER_STRING *object_name1,
int *object_type, int *object_type,
uint32_t * object_instance) uint32_t * object_instance)
{ {
@@ -362,14 +551,17 @@ bool Device_Valid_Object_Name(
uint32_t instance; uint32_t instance;
unsigned max_objects = 0, i = 0; unsigned max_objects = 0, i = 0;
bool check_id = false; bool check_id = false;
char *name = NULL; BACNET_CHARACTER_STRING object_name2;
struct my_object_functions *pObject = NULL;
max_objects = Device_Object_List_Count(); max_objects = Device_Object_List_Count();
for (i = 0; i < max_objects; i++) { for (i = 0; i < max_objects; i++) {
check_id = Device_Object_List_Identifier(i, &type, &instance); check_id = Device_Object_List_Identifier(i, &type, &instance);
if (check_id) { if (check_id) {
name = Device_Valid_Object_Id(type, instance); pObject = Device_Objects_Find_Functions(type);
if (strcmp(name, object_name) == 0) { if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
(pObject->Object_Name(instance, &object_name2) &&
characterstring_same(object_name1, &object_name2))) {
found = true; found = true;
if (object_type) { if (object_type) {
*object_type = type; *object_type = type;
@@ -385,179 +577,49 @@ bool Device_Valid_Object_Name(
return found; return found;
} }
/* returns the name or NULL if not found */ bool Device_Valid_Object_Id(
char *Device_Valid_Object_Id(
int object_type, int object_type,
uint32_t object_instance) uint32_t object_instance)
{ {
char *name = NULL; /* return value */ bool status = false; /* return value */
unsigned index = 0; /* loop counter */
struct my_object_functions *pObject = NULL; struct my_object_functions *pObject = NULL;
pObject = &Object_Table[0]; pObject = Device_Objects_Find_Functions(object_type);
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
if ((pObject->Object_Type == object_type) && (pObject->Object_Name)) { status = pObject->Object_Valid_Instance(object_instance);
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;
} }
return status; return status;
} }
void Device_Init( bool Device_Object_Name_Copy(
void) int object_type,
uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
unsigned index = 0; /* loop counter */
struct my_object_functions *pObject = NULL; 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; max_objects = Device_Object_List_Count();
dcc_set_status_duration(COMMUNICATION_ENABLE, 0); for (i = 0; i < max_objects; i++) {
/* FIXME: Get the data from the eeprom */ check_id = Device_Object_List_Identifier(i, &type, &instance);
/* I2C_Read_Block(EEPROM_DEVICE_ADDRESS, if (check_id) {
(char *)&Object_Instance_Number, pObject = Device_Objects_Find_Functions(type);
sizeof(Object_Instance_Number), if ((pObject != NULL) && (pObject->Object_Name != NULL)) {
EEPROM_BACNET_ID_ADDR); */ found = pObject->Object_Name(instance, object_name);
pObject = &Object_Table[0]; break;
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { }
if (pObject->Object_Init) {
pObject->Object_Init();
} }
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( /* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */
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 */
int Device_Read_Property_Local( int Device_Read_Property_Local(
BACNET_READ_PROPERTY_DATA * rpdata) BACNET_READ_PROPERTY_DATA * rpdata)
{ {
@@ -569,18 +631,13 @@ int Device_Read_Property_Local(
int object_type = 0; int object_type = 0;
uint32_t instance = 0; uint32_t instance = 0;
unsigned count = 0; unsigned count = 0;
BACNET_TIME local_time;
BACNET_DATE local_date;
uint8_t *apdu = NULL; uint8_t *apdu = NULL;
struct my_object_functions *pObject = 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)) { (rpdata->application_data_len == 0)) {
return 0; return 0;
} }
/* requested instance may have been the wildcard instance */
rpdata->object_instance = Object_Instance_Number;
apdu = rpdata->application_data; apdu = rpdata->application_data;
switch (rpdata->object_property) { switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER: case PROP_OBJECT_IDENTIFIER:
@@ -588,19 +645,23 @@ int Device_Read_Property_Local(
encode_application_object_id(&apdu[0], OBJECT_DEVICE, encode_application_object_id(&apdu[0], OBJECT_DEVICE,
rpdata->object_instance); rpdata->object_instance);
break; 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: case PROP_OBJECT_TYPE:
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE); apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
break; break;
case PROP_OBJECT_NAME:
apdu_len =
encode_application_character_string(&apdu[0], &My_Object_Name);
break;
case PROP_DESCRIPTION: case PROP_DESCRIPTION:
characterstring_init_ansi(&char_string, "BACnet Demo"); characterstring_init_ansi(&char_string, "BACnet Demo");
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; 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: case PROP_SYSTEM_STATUS:
apdu_len = apdu_len =
encode_application_enumerated(&apdu[0], encode_application_enumerated(&apdu[0],
@@ -612,9 +673,7 @@ int Device_Read_Property_Local(
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
case PROP_VENDOR_IDENTIFIER: case PROP_VENDOR_IDENTIFIER:
apdu_len = apdu_len = encode_application_unsigned(&apdu[0], BACNET_VENDOR_ID);
encode_application_unsigned(&apdu[0],
Device_Vendor_Identifier());
break; break;
case PROP_MODEL_NAME: case PROP_MODEL_NAME:
characterstring_init_ansi(&char_string, "GNU Demo"); characterstring_init_ansi(&char_string, "GNU Demo");
@@ -631,20 +690,14 @@ int Device_Read_Property_Local(
apdu_len = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; 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: case PROP_PROTOCOL_VERSION:
apdu_len = apdu_len =
encode_application_unsigned(&apdu[0], encode_application_unsigned(&apdu[0], BACNET_PROTOCOL_VERSION);
Device_Protocol_Version());
break; break;
case PROP_PROTOCOL_REVISION: case PROP_PROTOCOL_REVISION:
apdu_len = apdu_len =
encode_application_unsigned(&apdu[0], encode_application_unsigned(&apdu[0],
Device_Protocol_Revision()); BACNET_PROTOCOL_REVISION);
break; break;
case PROP_PROTOCOL_SERVICES_SUPPORTED: case PROP_PROTOCOL_SERVICES_SUPPORTED:
/* Note: list of services that are executed, not initiated. */ /* 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++) { for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
/* automatic lookup based on handlers set */ /* automatic lookup based on handlers set */
bitstring_set_bit(&bit_string, (uint8_t) i, 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); apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break; break;
@@ -671,8 +724,7 @@ int Device_Read_Property_Local(
if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) { if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) {
bitstring_set_bit(&bit_string, pObject->Object_Type, true); bitstring_set_bit(&bit_string, pObject->Object_Type, true);
} }
i++; pObject++;
pObject = &Object_Table[i];
} }
apdu_len = encode_application_bitstring(&apdu[0], &bit_string); apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break; break;
@@ -687,10 +739,8 @@ int Device_Read_Property_Local(
/* your maximum APDU size. */ /* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) { else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) { for (i = 1; i <= count; i++) {
found = if (Device_Object_List_Identifier(i, &object_type,
Device_Object_List_Identifier(i, &object_type, &instance)) {
&instance);
if (found) {
len = len =
encode_application_object_id(&apdu[apdu_len], encode_application_object_id(&apdu[apdu_len],
object_type, instance); object_type, instance);
@@ -756,31 +806,6 @@ int Device_Read_Property_Local(
apdu_len = apdu_len =
encode_application_unsigned(&apdu[0], dlmstp_max_master()); encode_application_unsigned(&apdu[0], dlmstp_max_master());
break; 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: case 9600:
apdu_len = apdu_len =
encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate()); encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
@@ -805,15 +830,12 @@ int Device_Read_Property_Local(
bool Device_Write_Property_Local( bool Device_Write_Property_Local(
BACNET_WRITE_PROPERTY_DATA * wp_data) BACNET_WRITE_PROPERTY_DATA * wp_data)
{ {
bool status = false; /* return value */ bool status = false; /* return value - false=error */
int len = 0; int len = 0;
uint8_t encoding = 0;
size_t length = 0;
BACNET_APPLICATION_DATA_VALUE value; 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 */ /* decode the some of the request */
len = len =
bacapp_decode_application_data(wp_data->application_data, bacapp_decode_application_data(wp_data->application_data,
@@ -873,29 +895,32 @@ bool Device_Write_Property_Local(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
uint8_t encoding; length = characterstring_length(
size_t len; &value.type.Character_String);
if (length < characterstring_capacity(&My_Object_Name)) {
encoding = encoding = characterstring_encoding(
characterstring_encoding(&value.type.Character_String); &value.type.Character_String);
len = characterstring_length(&value.type.Character_String); if (encoding < MAX_CHARACTER_STRING_ENCODING) {
if (encoding == CHARACTER_ANSI_X34) { /* All the object names in a device must be unique. */
if (len <= 20) { if (Device_Valid_Object_Name(
/* FIXME: set the name */ &value.type.Character_String,
/* Display_Set_Name( NULL, NULL)) {
characterstring_value(&value.type.Character_String)); */ status = false;
/* FIXME: All the object names in a device must be unique. wp_data->error_class = ERROR_CLASS_PROPERTY;
Disallow setting the Device Object Name to any objects in wp_data->error_code = ERROR_CODE_DUPLICATE_NAME;
the device. */ } else {
Device_Set_Object_Name(
&value.type.Character_String);
}
} else { } else {
wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = wp_data->error_code =
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
} }
} else { } else {
wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = wp_data->error_code =
ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
} }
} else { } else {
wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_class = ERROR_CLASS_PROPERTY;
+1 -1
View File
@@ -143,7 +143,7 @@ static inline void bacnet_init(
#endif #endif
Device_Set_Object_Instance_Number(22222); Device_Set_Object_Instance_Number(22222);
/* initialize objects */ /* initialize objects */
Device_Init(); Device_Init(NULL);
/* set up our confirmed service unrecognized service handler - required! */ /* set up our confirmed service unrecognized service handler - required! */
apdu_set_unrecognized_service_handler_handler apdu_set_unrecognized_service_handler_handler
(handler_unrecognized_service); (handler_unrecognized_service);
+4
View File
@@ -31,6 +31,8 @@ AVRDUDE_PORT = /dev/ttyUSB0
# Source locations # Source locations
BACNET_CORE = ../../src BACNET_CORE = ../../src
BACNET_INCLUDE = ../../include BACNET_INCLUDE = ../../include
BACNET_HANDLER = ../../demo/handler
BACNET_OBJECT = ../../demo/object
BACNET_DEMO = ../../demo BACNET_DEMO = ../../demo
# local files for this project # local files for this project
@@ -93,6 +95,8 @@ CORESRC = \
## Include Directories ## Include Directories
INCLUDES = -I. -I$(BACNET_INCLUDE) INCLUDES = -I. -I$(BACNET_INCLUDE)
INCLUDES += -I$(BACNET_OBJECT)
INCLUDES += -I$(BACNET_HANDLER)
# Source to Object conversion # Source to Object conversion
COBJ = $(CSRC:.c=.o) COBJ = $(CSRC:.c=.o)
+99
View File
@@ -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
+4 -1
View File
@@ -45,6 +45,8 @@ AVRDUDE_PORT = usb
# Source locations # Source locations
BACNET_CORE = ../../src BACNET_CORE = ../../src
BACNET_INCLUDE = ../../include BACNET_INCLUDE = ../../include
BACNET_HANDLER = ../../demo/handler
BACNET_OBJECT = ../../demo/object
BACNET_DEMO = ../../demo BACNET_DEMO = ../../demo
# local files for this project # local files for this project
@@ -65,6 +67,7 @@ CSRC = main.c \
dlmstp.c \ dlmstp.c \
test.c \ test.c \
bacnet.c \ bacnet.c \
bname.c \
device.c \ device.c \
ai.c \ ai.c \
av.c \ av.c \
@@ -130,7 +133,7 @@ CORESRC = \
# $(BACNET_CORE)/address.c \ # $(BACNET_CORE)/address.c \
## Include Directories ## Include Directories
INCLUDES = -I. -I$(BACNET_INCLUDE) INCLUDES = -I. -I$(BACNET_INCLUDE) -I$(BACNET_HANDLER) -I$(BACNET_OBJECT)
# Source to Object conversion # Source to Object conversion
COBJ = $(CSRC:%.c=%.o) COBJ = $(CSRC:%.c=%.o)
+6 -4
View File
@@ -109,17 +109,19 @@ uint32_t Analog_Input_Index_To_Instance(
return index; return index;
} }
char *Analog_Input_Name( bool Analog_Input_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32]; /* okay for single thread */ static char text_string[32]; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ANALOG_INPUTS) { if (object_instance < MAX_ANALOG_INPUTS) {
sprintf(text_string, "AI-%lu", object_instance); 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( float Analog_Input_Present_Value(
+6 -4
View File
@@ -175,19 +175,21 @@ bool Analog_Value_Present_Value_Set(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Analog_Value_Name( bool Analog_Value_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32] = ""; /* okay for single thread */ static char text_string[32] = ""; /* okay for single thread */
unsigned index = 0; unsigned index = 0;
bool status = false;
index = Analog_Value_Instance_To_Index(object_instance); index = Analog_Value_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_VALUES) { if (index < MAX_ANALOG_VALUES) {
sprintf(text_string, "AV-%lu", object_instance); 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 */ /* return apdu len, or -1 on error */
+2 -2
View File
@@ -85,10 +85,10 @@ void bacnet_init(
dlmstp_init(NULL); dlmstp_init(NULL);
if (!seeprom_version_test()) { if (!seeprom_version_test()) {
/* invalid version data */ /* do something when SEEPROM is invalid - i.e. init to defaults */
} }
/* initialize objects */ /* initialize objects */
Device_Init(); Device_Init(NULL);
/* set up our confirmed service unrecognized service handler - required! */ /* set up our confirmed service unrecognized service handler - required! */
apdu_set_unrecognized_service_handler_handler apdu_set_unrecognized_service_handler_handler
+6 -4
View File
@@ -157,17 +157,19 @@ bool Binary_Input_Present_Value_Set(
return false; return false;
} }
char *Binary_Input_Name( bool Binary_Input_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32]; /* okay for single thread */ static char text_string[32]; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_INPUTS) { if (object_instance < MAX_BINARY_INPUTS) {
sprintf(text_string, "BI-%lu", object_instance); 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 */ /* return apdu length, or -1 on error */
+275
View File
@@ -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);
}
}
+60
View File
@@ -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
+6 -4
View File
@@ -229,17 +229,19 @@ bool Binary_Output_Out_Of_Service(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Binary_Output_Name( bool Binary_Output_Object_Name(
uint32_t object_instance) uint32_t object_instance,
BACNET_CHARACTER_STRING *object_name)
{ {
static char text_string[32]; /* okay for single thread */ static char text_string[32]; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_OUTPUTS) { if (object_instance < MAX_BINARY_OUTPUTS) {
sprintf(text_string, "BO-%lu", object_instance); 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 */ /* return apdu len, or -1 on error */
+127 -84
View File
@@ -39,6 +39,7 @@
#include "nvdata.h" #include "nvdata.h"
#include "stack.h" #include "stack.h"
#include "handlers.h" #include "handlers.h"
#include "bname.h"
/* objects */ /* objects */
#include "device.h" #include "device.h"
#include "ai.h" #include "ai.h"
@@ -66,24 +67,24 @@ static struct my_object_functions {
{ {
OBJECT_DEVICE, NULL, /* don't init - recursive! */ OBJECT_DEVICE, NULL, /* don't init - recursive! */
Device_Count, Device_Index_To_Instance, 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_Read_Property_Local, Device_Write_Property_Local,
Device_Property_Lists}, { Device_Property_Lists}, {
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, 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}, { Analog_Input_Property_Lists}, {
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, 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}, { Analog_Value_Write_Property, Analog_Value_Property_Lists}, {
OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count,
Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance, 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}, { Binary_Input_Property_Lists}, {
OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count,
Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, 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}, { Binary_Output_Write_Property, Binary_Output_Property_Lists}, {
MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL} 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. */ into the read-property encoding. */
static uint32_t Object_Instance_Number; static uint32_t Object_Instance_Number;
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
static uint32_t Database_Revision;
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE; static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
/* These three arrays are used by the ReadPropertyMultiple handler */ /* 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[] = { static const int Device_Properties_Proprietary[] = {
512,
513,
9600,
-1 -1
}; };
@@ -157,7 +161,6 @@ static int Read_Property_Common(
{ {
int apdu_len = BACNET_STATUS_ERROR; int apdu_len = BACNET_STATUS_ERROR;
BACNET_CHARACTER_STRING char_string; BACNET_CHARACTER_STRING char_string;
char *pString = "";
uint8_t *apdu = NULL; uint8_t *apdu = NULL;
if ((rpdata->application_data == NULL) || if ((rpdata->application_data == NULL) ||
@@ -178,9 +181,12 @@ static int Read_Property_Common(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
if (pObject->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 = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
@@ -334,38 +340,30 @@ uint32_t Device_Index_To_Instance(
return Object_Instance_Number; return Object_Instance_Number;
} }
char *Device_Name( static char *Device_Name_Default(void)
uint32_t object_instance)
{ {
uint8_t encoding = 0; static char text_string[32]; /* okay for single thread */
uint8_t length = 0;
static char name[NV_EEPROM_DEVICE_NAME_SIZE + 1] = ""; sprintf(text_string, "DEVICE-%lu", Object_Instance_Number);
char *pName = NULL;
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) { if (object_instance == Object_Instance_Number) {
eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_ENCODING, &encoding, 1); bacnet_name(
eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_LENGTH, &length, 1); NV_EEPROM_DEVICE_NAME,
eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_0, (uint8_t *) & name, object_name,
NV_EEPROM_DEVICE_NAME_SIZE); Device_Name_Default());
if ((encoding >= MAX_CHARACTER_STRING_ENCODING) || status = true;
(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];
} }
return pName; return status;
} }
bool Device_Reinitialize( bool Device_Reinitialize(
@@ -397,10 +395,14 @@ BACNET_REINITIALIZED_STATE Device_Reinitialized_State(
} }
void Device_Init( void Device_Init(
void) object_functions_t * object_table)
{ {
struct my_object_functions *pObject = NULL; 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]; pObject = &Object_Table[0];
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
if (pObject->Object_Init) { if (pObject->Object_Init) {
@@ -418,7 +420,6 @@ void Device_Init(
(uint8_t *) & Object_Instance_Number, (uint8_t *) & Object_Instance_Number,
sizeof(Object_Instance_Number)); sizeof(Object_Instance_Number));
} }
(void) Device_Name(Object_Instance_Number);
} }
/* methods to manipulate the data */ /* methods to manipulate the data */
@@ -488,7 +489,13 @@ BACNET_SEGMENTATION Device_Segmentation_Supported(
uint32_t Device_Database_Revision( uint32_t Device_Database_Revision(
void) void)
{ {
return 0; return Database_Revision;
}
void Device_Inc_Database_Revision(
void)
{
Database_Revision++;
} }
/* Since many network clients depend on the object list */ /* Since many network clients depend on the object list */
@@ -546,7 +553,7 @@ bool Device_Object_List_Identifier(
} }
bool Device_Valid_Object_Name( bool Device_Valid_Object_Name(
const char *object_name, BACNET_CHARACTER_STRING *object_name1,
int *object_type, int *object_type,
uint32_t * object_instance) uint32_t * object_instance)
{ {
@@ -555,14 +562,17 @@ bool Device_Valid_Object_Name(
uint32_t instance; uint32_t instance;
unsigned max_objects = 0, i = 0; unsigned max_objects = 0, i = 0;
bool check_id = false; bool check_id = false;
char *name = NULL; BACNET_CHARACTER_STRING object_name2;
struct my_object_functions *pObject = NULL;
max_objects = Device_Object_List_Count(); max_objects = Device_Object_List_Count();
for (i = 0; i < max_objects; i++) { for (i = 0; i < max_objects; i++) {
check_id = Device_Object_List_Identifier(i, &type, &instance); check_id = Device_Object_List_Identifier(i, &type, &instance);
if (check_id) { if (check_id) {
name = Device_Valid_Object_Id(type, instance); pObject = Device_Objects_Find_Functions(type);
if (strcmp(name, object_name) == 0) { if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
(pObject->Object_Name(instance, &object_name2) &&
characterstring_same(object_name1, &object_name2))) {
found = true; found = true;
if (object_type) { if (object_type) {
*object_type = type; *object_type = type;
@@ -578,20 +588,46 @@ bool Device_Valid_Object_Name(
return found; return found;
} }
/* returns the name or NULL if not found */ bool Device_Valid_Object_Id(
char *Device_Valid_Object_Id(
int object_type, int object_type,
uint32_t object_instance) uint32_t object_instance)
{ {
char *name = NULL; /* return value */ bool status = false; /* return value */
struct my_object_functions *pObject = NULL; struct my_object_functions *pObject = NULL;
pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE) object_type); pObject = Device_Objects_Find_Functions(object_type);
if ((pObject) && (pObject->Object_Name)) { if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
name = pObject->Object_Name(object_instance); 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 */ /* 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; apdu = rpdata->application_data;
switch (rpdata->object_property) { switch (rpdata->object_property) {
case PROP_DESCRIPTION: 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 = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
@@ -672,7 +719,6 @@ int Device_Read_Property_Local(
not a list of objects that this device can access */ not a list of objects that this device can access */
bitstring_init(&bit_string); bitstring_init(&bit_string);
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { 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 */ /* initialize all the object types to not-supported */
bitstring_set_bit(&bit_string, (uint8_t) i, false); bitstring_set_bit(&bit_string, (uint8_t) i, false);
} }
@@ -858,38 +904,35 @@ bool Device_Write_Property_Local(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
size_t length = status = bacnet_name_write(
characterstring_length(&value.type.Character_String); NV_EEPROM_DEVICE_NAME,
if (length < 1) { &value.type.Character_String,
wp_data->error_class = ERROR_CLASS_PROPERTY; &wp_data->error_class,
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; &wp_data->error_code);
} else if (length < NV_EEPROM_DEVICE_NAME_SIZE) { } else {
uint8_t encoding = wp_data->error_class = ERROR_CLASS_PROPERTY;
characterstring_encoding(&value.type.Character_String); wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
if (encoding < MAX_CHARACTER_STRING_ENCODING) { }
char *pCharString; break;
uint8_t small_length; case PROP_DESCRIPTION:
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_ENCODING, if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
&encoding, 1); status = bacnet_name_write_other(
small_length = length; NV_EEPROM_DEVICE_DESCRIPTION,
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_LENGTH, &value.type.Character_String,
&small_length, 1); &wp_data->error_class,
pCharString = &wp_data->error_code);
characterstring_value(&value.type. } else {
Character_String); wp_data->error_class = ERROR_CLASS_PROPERTY;
eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_0, wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
(uint8_t *) pCharString, length); }
status = true; break;
} else { case PROP_LOCATION:
wp_data->error_class = ERROR_CLASS_PROPERTY; if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
wp_data->error_code = status = bacnet_name_write_other(
ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; NV_EEPROM_DEVICE_LOCATION,
} &value.type.Character_String,
} else { &wp_data->error_class,
wp_data->error_class = ERROR_CLASS_PROPERTY; &wp_data->error_code);
wp_data->error_code =
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
}
} else { } else {
wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
+44 -57
View File
@@ -28,21 +28,8 @@
#include "seeprom.h" #include "seeprom.h"
#include "eeprom.h" #include "eeprom.h"
/* data version - use to check valid version */ /*=============== EEPROM ================*/
#define SEEPROM_ID 0xBAC0 /* define the MAC, BAUD, MAX Master, Device Instance internal
#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
so that bootloader *could* use them. */ so that bootloader *could* use them. */
/* note: MAC could come from DIP switch, or be in non-volatile memory */ /* note: MAC could come from DIP switch, or be in non-volatile memory */
#define NV_EEPROM_MAC 0 #define NV_EEPROM_MAC 0
@@ -54,49 +41,44 @@
#define NV_EEPROM_DEVICE_1 4 #define NV_EEPROM_DEVICE_1 4
#define NV_EEPROM_DEVICE_2 5 #define NV_EEPROM_DEVICE_2 5
#define NV_EEPROM_DEVICE_3 6 #define NV_EEPROM_DEVICE_3 6
/* Device Name */
#define NV_EEPROM_DEVICE_NAME_LENGTH 8 /* EEPROM free space - 7..31 */
#define NV_EEPROM_DEVICE_NAME_ENCODING 9
#define NV_EEPROM_DEVICE_NAME_0 10 /* BACnet Names - 32 bytes of data each */
#define NV_EEPROM_DEVICE_NAME_1 11 #define NV_EEPROM_NAME_LENGTH(n) ((n)+0)
#define NV_EEPROM_DEVICE_NAME_2 12 #define NV_EEPROM_NAME_ENCODING(n) ((n)+1)
#define NV_EEPROM_DEVICE_NAME_3 13 #define NV_EEPROM_NAME_STRING(n) ((n)+2)
#define NV_EEPROM_DEVICE_NAME_4 14 #define NV_EEPROM_NAME_SIZE 30
#define NV_EEPROM_DEVICE_NAME_5 15 #define NV_EEPROM_NAME_OFFSET (1+1+NV_EEPROM_NAME_SIZE)
#define NV_EEPROM_DEVICE_NAME_6 16 /* Device Name - starting offset */
#define NV_EEPROM_DEVICE_NAME_7 17 #define NV_EEPROM_DEVICE_NAME 32
#define NV_EEPROM_DEVICE_NAME_8 18 /* Device Description - starting offset */
#define NV_EEPROM_DEVICE_NAME_9 19 #define NV_EEPROM_DEVICE_DESCRIPTION \
#define NV_EEPROM_DEVICE_NAME_10 20 (NV_EEPROM_DEVICE_NAME+NV_EEPROM_NAME_OFFSET)
#define NV_EEPROM_DEVICE_NAME_11 21 /* Device Location - starting offset */
#define NV_EEPROM_DEVICE_NAME_12 22 #define NV_EEPROM_DEVICE_LOCATION \
#define NV_EEPROM_DEVICE_NAME_13 23 (NV_EEPROM_DEVICE_DESCRIPTION+NV_EEPROM_NAME_OFFSET)
#define NV_EEPROM_DEVICE_NAME_14 24
#define NV_EEPROM_DEVICE_NAME_15 25 /* EEPROM free space 128..1024 */
#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
/*=============== SEEPROM ================*/ /*=============== SEEPROM ================*/
#define NV_SEEPROM_BINARY_OUTPUT_OFFSET 32 /* data version - use to check valid version */
#define NV_SEEPROM_BINARY_OUTPUT_0 10 #define SEEPROM_ID 0xBAC0
#define NV_SEEPROM_BINARY_OUTPUT(n,p) \ #define SEEPROM_VERSION 0x0001
(NV_SEEPROM_BINARY_OUTPUT_0 + \
(NV_SEEPROM_BINARY_OUTPUT_OFFSET * (n)) + (p)) #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 */ /* BO properties */
#define NV_SEEPROM_BO_POLARITY 0 #define NV_SEEPROM_BO_POLARITY 0
#define NV_SEEPROM_BO_OUT_OF_SERVICE 1 #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_14 15
#define NV_SEEPROM_BO_PRIORITY_ARRAY_15 16 #define NV_SEEPROM_BO_PRIORITY_ARRAY_15 16
#define NV_SEEPROM_BO_PRIORITY_ARRAY_16 17 #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 #ifdef __cplusplus
extern "C" { extern "C" {
+8 -6
View File
@@ -220,17 +220,19 @@ bool Binary_Output_Out_Of_Service(
} }
/* note: the object name must be unique within this device */ /* note: the object name must be unique within this device */
char *Binary_Output_Name( bool Binary_Output_Object_Name(
uint32_t object_instance) 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) { if (object_instance < MAX_BINARY_OUTPUTS) {
sprintf(text_string, "BO-%lu", object_instance); 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 */ /* return apdu len, or -1 on error */
+57 -18
View File
@@ -61,12 +61,12 @@ static struct my_object_functions {
{ {
OBJECT_DEVICE, NULL, /* don't init - recursive! */ OBJECT_DEVICE, NULL, /* don't init - recursive! */
Device_Count, Device_Index_To_Instance, 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_Read_Property_Local, Device_Write_Property_Local,
Device_Property_Lists}, { Device_Property_Lists}, {
OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count,
Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, 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}, { Binary_Output_Write_Property, Binary_Output_Property_Lists}, {
MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL} MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
}; };
@@ -162,9 +162,12 @@ static int Read_Property_Common(
break; break;
case PROP_OBJECT_NAME: case PROP_OBJECT_NAME:
if (pObject->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 = apdu_len =
encode_application_character_string(&apdu[0], &char_string); encode_application_character_string(&apdu[0], &char_string);
break; break;
@@ -318,10 +321,17 @@ uint32_t Device_Index_To_Instance(
return Object_Instance_Number; return Object_Instance_Number;
} }
char *Device_Name( bool Device_Object_Name(
uint32_t object_instance) 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( bool Device_Reinitialize(
@@ -494,7 +504,7 @@ bool Device_Object_List_Identifier(
} }
bool Device_Valid_Object_Name( bool Device_Valid_Object_Name(
const char *object_name, BACNET_CHARACTER_STRING *object_name1,
int *object_type, int *object_type,
uint32_t * object_instance) uint32_t * object_instance)
{ {
@@ -503,14 +513,17 @@ bool Device_Valid_Object_Name(
uint32_t instance; uint32_t instance;
unsigned max_objects = 0, i = 0; unsigned max_objects = 0, i = 0;
bool check_id = false; bool check_id = false;
char *name = NULL; BACNET_CHARACTER_STRING object_name2;
struct my_object_functions *pObject = NULL;
max_objects = Device_Object_List_Count(); max_objects = Device_Object_List_Count();
for (i = 0; i < max_objects; i++) { for (i = 0; i < max_objects; i++) {
check_id = Device_Object_List_Identifier(i, &type, &instance); check_id = Device_Object_List_Identifier(i, &type, &instance);
if (check_id) { if (check_id) {
name = Device_Valid_Object_Id(type, instance); pObject = Device_Objects_Find_Functions(type);
if (strcmp(name, object_name) == 0) { if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
(pObject->Object_Name(instance, &object_name2) &&
characterstring_same(object_name1, &object_name2))) {
found = true; found = true;
if (object_type) { if (object_type) {
*object_type = type; *object_type = type;
@@ -526,20 +539,46 @@ bool Device_Valid_Object_Name(
return found; return found;
} }
/* returns the name or NULL if not found */ bool Device_Valid_Object_Id(
char *Device_Valid_Object_Id(
int object_type, int object_type,
uint32_t object_instance) uint32_t object_instance)
{ {
char *name = NULL; /* return value */ bool status = false; /* return value */
struct my_object_functions *pObject = NULL; struct my_object_functions *pObject = NULL;
pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE) object_type); pObject = Device_Objects_Find_Functions(object_type);
if ((pObject) && (pObject->Object_Name)) { if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
name = pObject->Object_Name(object_instance); 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 */ /* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */
+106
View File
@@ -484,12 +484,118 @@ bool characterstring_printable(
break; break;
} }
} }
} else {
status = true;
} }
} }
return status; return status;
} }
/* 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;
}
bool characterstring_valid(
BACNET_CHARACTER_STRING * char_string)
{
bool valid = false; /* return value */
if (char_string->encoding < MAX_CHARACTER_STRING_ENCODING) {
if (char_string->encoding == CHARACTER_UTF8) {
if (utf8_isvalid(char_string->value, char_string->length)) {
valid = true;
}
} else {
valid = true;
}
}
return valid;
}
/* returns false if the string exceeds capacity /* returns false if the string exceeds capacity
initialize by using value=NULL */ initialize by using value=NULL */
bool octetstring_init( bool octetstring_init(
+8 -8
View File
@@ -63,7 +63,7 @@ int whohas_encode_apdu(
encode_context_unsigned(&apdu[apdu_len], 1, data->high_limit); encode_context_unsigned(&apdu[apdu_len], 1, data->high_limit);
apdu_len += len; apdu_len += len;
} }
if (data->object_name) { if (data->is_object_name) {
len = len =
encode_context_character_string(&apdu[apdu_len], 3, encode_context_character_string(&apdu[apdu_len], 3,
&data->object.name); &data->object.name);
@@ -115,7 +115,7 @@ int whohas_decode_service_request(
} }
/* object id */ /* object id */
if (decode_is_context_tag(&apdu[len], 2)) { if (decode_is_context_tag(&apdu[len], 2)) {
data->object_name = false; data->is_object_name = false;
len += len +=
decode_tag_number_and_value(&apdu[len], &tag_number, decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value); &len_value);
@@ -126,7 +126,7 @@ int whohas_decode_service_request(
} }
/* object name */ /* object name */
else if (decode_is_context_tag(&apdu[len], 3)) { else if (decode_is_context_tag(&apdu[len], 3)) {
data->object_name = true; data->is_object_name = true;
len += len +=
decode_tag_number_and_value(&apdu[len], &tag_number, decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value); &len_value);
@@ -186,9 +186,9 @@ void testWhoHasData(
ct_test(pTest, len != -1); ct_test(pTest, len != -1);
ct_test(pTest, test_data.low_limit == data->low_limit); ct_test(pTest, test_data.low_limit == data->low_limit);
ct_test(pTest, test_data.high_limit == data->high_limit); ct_test(pTest, test_data.high_limit == data->high_limit);
ct_test(pTest, test_data.object_name == data->object_name); ct_test(pTest, test_data.is_object_name == data->is_object_name);
/* Object ID */ /* Object ID */
if (data->object_name == false) { if (data->is_object_name == false) {
ct_test(pTest, ct_test(pTest,
test_data.object.identifier.type == data->object.identifier.type); test_data.object.identifier.type == data->object.identifier.type);
ct_test(pTest, ct_test(pTest,
@@ -209,7 +209,7 @@ void testWhoHas(
data.low_limit = -1; data.low_limit = -1;
data.high_limit = -1; data.high_limit = -1;
data.object_name = false; data.is_object_name = false;
data.object.identifier.type = OBJECT_ANALOG_INPUT; data.object.identifier.type = OBJECT_ANALOG_INPUT;
data.object.identifier.instance = 1; data.object.identifier.instance = 1;
testWhoHasData(pTest, &data); testWhoHasData(pTest, &data);
@@ -218,7 +218,7 @@ void testWhoHas(
data.low_limit += (BACNET_MAX_INSTANCE / 4)) { data.low_limit += (BACNET_MAX_INSTANCE / 4)) {
for (data.high_limit = 0; data.high_limit <= BACNET_MAX_INSTANCE; for (data.high_limit = 0; data.high_limit <= BACNET_MAX_INSTANCE;
data.high_limit += (BACNET_MAX_INSTANCE / 4)) { data.high_limit += (BACNET_MAX_INSTANCE / 4)) {
data.object_name = false; data.is_object_name = false;
for (data.object.identifier.type = OBJECT_ANALOG_INPUT; for (data.object.identifier.type = OBJECT_ANALOG_INPUT;
data.object.identifier.type < MAX_BACNET_OBJECT_TYPE; data.object.identifier.type < MAX_BACNET_OBJECT_TYPE;
data.object.identifier.type++) { data.object.identifier.type++) {
@@ -228,7 +228,7 @@ void testWhoHas(
testWhoHasData(pTest, &data); testWhoHasData(pTest, &data);
} }
} }
data.object_name = true; data.is_object_name = true;
characterstring_init_ansi(&data.object.name, "patricia"); characterstring_init_ansi(&data.object.name, "patricia");
testWhoHasData(pTest, &data); testWhoHasData(pTest, &data);
} }