diff --git a/bacnet-stack/demo/dcc/main.c b/bacnet-stack/demo/dcc/main.c index 360a6d53..11395854 100644 --- a/bacnet-stack/demo/dcc/main.c +++ b/bacnet-stack/demo/dcc/main.c @@ -122,8 +122,7 @@ void MyDeviceCommunicationControlSimpleAckHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/epics/main.c b/bacnet-stack/demo/epics/main.c index f79e9cca..52040732 100644 --- a/bacnet-stack/demo/epics/main.c +++ b/bacnet-stack/demo/epics/main.c @@ -276,8 +276,7 @@ void MyReadPropertyMultipleAckHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); #if BAC_ROUTING uint32_t Object_Instance; diff --git a/bacnet-stack/demo/gateway/main.c b/bacnet-stack/demo/gateway/main.c index 8903906c..4af3679e 100644 --- a/bacnet-stack/demo/gateway/main.c +++ b/bacnet-stack/demo/gateway/main.c @@ -153,7 +153,7 @@ void Devices_Init( static void Init_Service_Handlers( uint32_t first_object_instance) { - Device_Initialize_Object_Functions(&Object_Table[0]); + Device_Init(&Object_Table[0]); Routing_Device_Init(first_object_instance); /* we need to handle who-is to support dynamic device binding diff --git a/bacnet-stack/demo/handler/h_whohas.c b/bacnet-stack/demo/handler/h_whohas.c index a96f795d..83d4727d 100644 --- a/bacnet-stack/demo/handler/h_whohas.c +++ b/bacnet-stack/demo/handler/h_whohas.c @@ -40,36 +40,39 @@ /** Local function which responds with either the requested object name * 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( BACNET_WHO_HAS_DATA * data) { - char *object_name = NULL; int object_type = 0; uint32_t object_instance = 0; bool found = false; + BACNET_CHARACTER_STRING object_name; + /* do we have such an object? If so, send an I-Have. note: we should have only 1 of such an object */ - if (data->object_name) { + if (data->is_object_name) { /* valid name in my device? */ - object_name = characterstring_value(&data->object.name); found = - Device_Valid_Object_Name(object_name, &object_type, + Device_Valid_Object_Name(&data->object.name, &object_type, &object_instance); - if (found) + if (found) { Send_I_Have(Device_Object_Instance_Number(), (BACNET_OBJECT_TYPE) object_type, object_instance, - object_name); + &data->object.name); + } } else { - /* valid object in my device? */ - object_name = - Device_Valid_Object_Id(data->object.identifier.type, - data->object.identifier.instance); - if (object_name) + /* valid object_name copy in my device? */ + found = Device_Object_Name_Copy( + data->object.identifier.type, + data->object.identifier.instance, + &object_name); + if (found) { Send_I_Have(Device_Object_Instance_Number(), (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 -/** 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. * Will respond if the device Object ID matches, and we have * the Object or Object Name requested. diff --git a/bacnet-stack/demo/handler/s_ihave.c b/bacnet-stack/demo/handler/s_ihave.c index 7927b1d1..4361d5e7 100644 --- a/bacnet-stack/demo/handler/s_ihave.c +++ b/bacnet-stack/demo/handler/s_ihave.c @@ -57,7 +57,7 @@ void Send_I_Have( uint32_t device_id, BACNET_OBJECT_TYPE object_type, uint32_t object_instance, - const char *object_name) + BACNET_CHARACTER_STRING *object_name) { int len = 0; int pdu_len = 0; @@ -84,7 +84,7 @@ void Send_I_Have( data.device_id.instance = device_id; data.object_id.type = object_type; 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); pdu_len += len; /* send the data */ diff --git a/bacnet-stack/demo/handler/s_whohas.c b/bacnet-stack/demo/handler/s_whohas.c index d8e3fd35..c423365d 100644 --- a/bacnet-stack/demo/handler/s_whohas.c +++ b/bacnet-stack/demo/handler/s_whohas.c @@ -83,7 +83,7 @@ void Send_WhoHas_Name( /* encode the APDU portion of the packet */ data.low_limit = low_limit; data.high_limit = high_limit; - data.object_name = true; + data.is_object_name = true; characterstring_init_ansi(&data.object.name, object_name); len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data); pdu_len += len; @@ -138,7 +138,7 @@ void Send_WhoHas_Object( /* encode the APDU portion of the packet */ data.low_limit = low_limit; data.high_limit = high_limit; - data.object_name = false; + data.is_object_name = false; data.object.identifier.type = object_type; data.object.identifier.instance = object_instance; len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data); diff --git a/bacnet-stack/demo/iamrouter/main.c b/bacnet-stack/demo/iamrouter/main.c index ba6118d8..7d8d3853 100644 --- a/bacnet-stack/demo/iamrouter/main.c +++ b/bacnet-stack/demo/iamrouter/main.c @@ -90,8 +90,7 @@ void MyRejectHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/initrouter/main.c b/bacnet-stack/demo/initrouter/main.c index 48e459f5..6205788d 100644 --- a/bacnet-stack/demo/initrouter/main.c +++ b/bacnet-stack/demo/initrouter/main.c @@ -220,8 +220,7 @@ static void My_NPDU_Handler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/object/ai.c b/bacnet-stack/demo/object/ai.c index eda4ccd3..8291456c 100644 --- a/bacnet-stack/demo/object/ai.c +++ b/bacnet-stack/demo/object/ai.c @@ -152,19 +152,21 @@ void Analog_Input_Present_Value_Set( } } -char *Analog_Input_Name( - uint32_t object_instance) +bool Analog_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ unsigned int index; + bool status = false; index = Analog_Input_Instance_To_Index(object_instance); if (index < MAX_ANALOG_INPUTS) { 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 */ @@ -190,8 +192,7 @@ int Analog_Input_Read_Property( break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Analog_Input_Name(rpdata->object_instance)); + Analog_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/ai.h b/bacnet-stack/demo/object/ai.h index fec425f2..b7a51bd8 100644 --- a/bacnet-stack/demo/object/ai.h +++ b/bacnet-stack/demo/object/ai.h @@ -50,8 +50,9 @@ extern "C" { bool Analog_Input_Object_Instance_Add( uint32_t instance); - char *Analog_Input_Name( - uint32_t object_instance); + bool Analog_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name); bool Analog_Input_Name_Set( uint32_t object_instance, char *new_name); @@ -94,6 +95,6 @@ extern "C" { #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_Object_Name, Analog_Input_Read_Property, NULL, \ Analog_Input_Property_Lists, NULL, NULL #endif diff --git a/bacnet-stack/demo/object/ao.c b/bacnet-stack/demo/object/ao.c index de003cbb..4b2b7e93 100644 --- a/bacnet-stack/demo/object/ao.c +++ b/bacnet-stack/demo/object/ao.c @@ -253,18 +253,20 @@ bool Analog_Output_Present_Value_Relinquish( } /* note: the object name must be unique within this device */ -char *Analog_Output_Name( - uint32_t object_instance) +bool Analog_Output_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_ANALOG_OUTPUTS) { sprintf(text_string, "ANALOG OUTPUT %lu", (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 */ @@ -294,8 +296,7 @@ int Analog_Output_Read_Property( break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Analog_Output_Name(rpdata->object_instance)); + Analog_Output_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/ao.h b/bacnet-stack/demo/object/ao.h index 7c46ff2d..d4b87808 100644 --- a/bacnet-stack/demo/object/ao.h +++ b/bacnet-stack/demo/object/ao.h @@ -63,8 +63,9 @@ extern "C" { uint32_t object_instance, unsigned priority); - char *Analog_Output_Name( - uint32_t object_instance); + bool Analog_Output_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name); bool Analog_Output_Name_Set( uint32_t object_instance, char *new_name); @@ -102,7 +103,7 @@ extern "C" { #define ANALOG_OUTPUT_OBJ_FUNCTIONS \ OBJECT_ANALOG_OUTPUT, Analog_Output_Init, Analog_Output_Count, \ 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, \ NULL, NULL #endif diff --git a/bacnet-stack/demo/object/av.c b/bacnet-stack/demo/object/av.c index ef5bbebd..cff42a65 100644 --- a/bacnet-stack/demo/object/av.c +++ b/bacnet-stack/demo/object/av.c @@ -201,18 +201,20 @@ float Analog_Value_Present_Value( } /* note: the object name must be unique within this device */ -char *Analog_Value_Name( - uint32_t object_instance) +bool Analog_Value_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_ANALOG_VALUES) { sprintf(text_string, "ANALOG VALUE %lu", (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 */ @@ -242,8 +244,7 @@ int Analog_Value_Read_Property( break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Analog_Value_Name(rpdata->object_instance)); + Analog_Value_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/av.h b/bacnet-stack/demo/object/av.h index 4b24a68f..34f4c139 100644 --- a/bacnet-stack/demo/object/av.h +++ b/bacnet-stack/demo/object/av.h @@ -47,8 +47,10 @@ extern "C" { unsigned index); unsigned Analog_Value_Instance_To_Index( 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( BACNET_READ_PROPERTY_DATA * rpdata); @@ -78,7 +80,7 @@ extern "C" { #define ANALOG_VALUE_OBJ_FUNCTIONS \ OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, \ Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, \ - Analog_Value_Name, Analog_Value_Read_Property, \ + Analog_Value_Object_Name, Analog_Value_Read_Property, \ Analog_Value_Write_Property, Analog_Value_Property_Lists, NULL, \ NULL #endif diff --git a/bacnet-stack/demo/object/bi.c b/bacnet-stack/demo/object/bi.c index d2076225..8fa0be1b 100644 --- a/bacnet-stack/demo/object/bi.c +++ b/bacnet-stack/demo/object/bi.c @@ -283,18 +283,20 @@ static void Binary_Input_Out_Of_Service_Set( return; } -char *Binary_Input_Name( - uint32_t object_instance) +bool Binary_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_BINARY_INPUTS) { sprintf(text_string, "BINARY INPUT %lu", (unsigned long) object_instance); - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } BACNET_POLARITY Binary_Input_Polarity( @@ -346,8 +348,7 @@ int Binary_Input_Read_Property( case PROP_OBJECT_NAME: case PROP_DESCRIPTION: /* note: object name must be unique in our device */ - characterstring_init_ansi(&char_string, - Binary_Input_Name(rpdata->object_instance)); + Binary_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/bi.h b/bacnet-stack/demo/object/bi.h index 217f1f35..4eb0c17d 100644 --- a/bacnet-stack/demo/object/bi.h +++ b/bacnet-stack/demo/object/bi.h @@ -52,8 +52,9 @@ extern "C" { bool Binary_Input_Object_Instance_Add( uint32_t instance); - char *Binary_Input_Name( - uint32_t object_instance); + bool Binary_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name); bool Binary_Input_Name_Set( uint32_t object_instance, char *new_name); @@ -116,6 +117,6 @@ extern "C" { #define BINARY_INPUT_OBJ_FUNCTIONS \ OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, \ Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance, \ - Binary_Input_Name, Binary_Input_Read_Property, NULL, \ + Binary_Input_Object_Name, Binary_Input_Read_Property, NULL, \ Binary_Input_Property_Lists, NULL, NULL #endif diff --git a/bacnet-stack/demo/object/bo.c b/bacnet-stack/demo/object/bo.c index 5fc42f03..81fd7b0e 100644 --- a/bacnet-stack/demo/object/bo.c +++ b/bacnet-stack/demo/object/bo.c @@ -177,18 +177,20 @@ BACNET_BINARY_PV Binary_Output_Present_Value( } /* note: the object name must be unique within this device */ -char *Binary_Output_Name( - uint32_t object_instance) +bool Binary_Output_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_BINARY_OUTPUTS) { sprintf(text_string, "BINARY OUTPUT %lu", (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 */ @@ -221,8 +223,7 @@ int Binary_Output_Read_Property( You could make Description writable and different */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Binary_Output_Name(rpdata->object_instance)); + Binary_Output_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/bo.h b/bacnet-stack/demo/object/bo.h index 666b3a08..741cf170 100644 --- a/bacnet-stack/demo/object/bo.h +++ b/bacnet-stack/demo/object/bo.h @@ -55,8 +55,9 @@ extern "C" { bool Binary_Output_Object_Instance_Add( uint32_t instance); - char *Binary_Output_Name( - uint32_t object_instance); + bool Binary_Output_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name); bool Binary_Output_Name_Set( uint32_t object_instance, char *new_name); @@ -111,7 +112,7 @@ extern "C" { #define BINARY_OUTPUT_OBJ_FUNCTIONS \ OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, \ Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, \ - Binary_Output_Name, Binary_Output_Read_Property, \ + Binary_Output_Object_Name, Binary_Output_Read_Property, \ Binary_Output_Write_Property, Binary_Output_Property_Lists, \ NULL, NULL #endif diff --git a/bacnet-stack/demo/object/bv.c b/bacnet-stack/demo/object/bv.c index 4fb02e2e..30b6e727 100644 --- a/bacnet-stack/demo/object/bv.c +++ b/bacnet-stack/demo/object/bv.c @@ -174,18 +174,20 @@ static BACNET_BINARY_PV Binary_Value_Present_Value( } /* note: the object name must be unique within this device */ -char *Binary_Value_Name( - uint32_t object_instance) +bool Binary_Value_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_BINARY_VALUES) { sprintf(text_string, "BINARY VALUE %lu", (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 */ @@ -217,8 +219,7 @@ int Binary_Value_Read_Property( You could make Description writable and different */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Binary_Value_Name(rpdata->object_instance)); + Binary_Value_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/bv.h b/bacnet-stack/demo/object/bv.h index 0eeeed11..ace89ca2 100644 --- a/bacnet-stack/demo/object/bv.h +++ b/bacnet-stack/demo/object/bv.h @@ -48,8 +48,10 @@ extern "C" { unsigned index); unsigned Binary_Value_Instance_To_Index( 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); @@ -72,7 +74,7 @@ extern "C" { #define BINARY_VALUE_OBJ_FUNCTIONS \ OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count, \ Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance, \ - Binary_Value_Name, Binary_Value_Read_Property, \ + Binary_Value_Object_Name, Binary_Value_Read_Property, \ Binary_Value_Write_Property, Binary_Value_Property_Lists, NULL, \ NULL #endif diff --git a/bacnet-stack/demo/object/device.c b/bacnet-stack/demo/object/device.c index 1f41d3d0..37d03a95 100644 --- a/bacnet-stack/demo/object/device.c +++ b/bacnet-stack/demo/object/device.c @@ -289,7 +289,7 @@ void Device_Property_Lists( into the read-property encoding. */ 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 char *Vendor_Name = BACNET_VENDOR_NAME; static uint16_t Vendor_Identifier = BACNET_VENDOR_ID; @@ -384,37 +384,28 @@ bool Device_Valid_Object_Instance_Number( (object_id == BACNET_MAX_INSTANCE)); } -char *Device_Name( - uint32_t object_instance) +bool Device_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { + bool status = false; + if (object_instance == Object_Instance_Number) { - return My_Object_Name; + status = characterstring_copy(object_name, &My_Object_Name); } - return NULL; -} - -const char *Device_Object_Name( - void) -{ - return My_Object_Name; + return status; } bool Device_Set_Object_Name( - const char *name, - size_t length) + BACNET_CHARACTER_STRING *object_name) { bool status = false; /*return value */ - /* FIXME: All the object names in a device must be unique. - Disallow setting the Device Object Name to any objects in - the device. */ - if (length < sizeof(My_Object_Name)) { + if (!characterstring_same(&My_Object_Name, object_name)) { /* Make the change and update the database revision */ - memmove(My_Object_Name, name, length); - My_Object_Name[length] = 0; + status = characterstring_copy(&My_Object_Name, object_name); Device_Inc_Database_Revision(); - status = true; } return status; @@ -737,7 +728,7 @@ bool Device_Object_List_Identifier( * @return True on success or else False if not found. */ bool Device_Valid_Object_Name( - const char *object_name, + BACNET_CHARACTER_STRING *object_name1, int *object_type, uint32_t * object_instance) { @@ -746,14 +737,17 @@ bool Device_Valid_Object_Name( uint32_t instance; unsigned max_objects = 0, i = 0; bool check_id = false; - char *name = NULL; + BACNET_CHARACTER_STRING object_name2; + struct object_functions *pObject = NULL; max_objects = Device_Object_List_Count(); for (i = 0; i < max_objects; i++) { check_id = Device_Object_List_Identifier(i, &type, &instance); if (check_id) { - name = Device_Valid_Object_Id(type, instance); - if (strcmp(name, object_name) == 0) { + pObject = Device_Objects_Find_Functions(type); + if ((pObject != NULL) && (pObject->Object_Name != NULL) && + (pObject->Object_Name(instance, &object_name2) && + characterstring_same(object_name1, &object_name2))) { found = true; if (object_type) { *object_type = type; @@ -774,18 +768,52 @@ bool Device_Valid_Object_Name( * @param object_instance [in] The object instance number to be looked up. * @return The Object Name or else NULL if not found */ -char *Device_Valid_Object_Id( +bool Device_Valid_Object_Id( int object_type, uint32_t object_instance) { - char *name = NULL; /* return value */ + bool status = false; /* return value */ struct object_functions *pObject = NULL; pObject = Device_Objects_Find_Functions(object_type); - if ((pObject != NULL) && (pObject->Object_Name != NULL)) - name = pObject->Object_Name(object_instance); + if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) { + 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( @@ -873,9 +901,8 @@ int Device_Read_Property_Local( Object_Instance_Number); break; case PROP_OBJECT_NAME: - characterstring_init_ansi(&char_string, My_Object_Name); apdu_len = - encode_application_character_string(&apdu[0], &char_string); + encode_application_character_string(&apdu[0], &My_Object_Name); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE); @@ -1201,12 +1228,22 @@ bool Device_Write_Property_Local( break; case PROP_OBJECT_NAME: status = - WPValidateString(&value, MAX_DEV_NAME_LEN, false, - &wp_data->error_class, &wp_data->error_code); + WPValidateString(&value, + characterstring_capacity(&My_Object_Name), + false, + &wp_data->error_class, &wp_data->error_code); if (status) { - Device_Set_Object_Name(characterstring_value(&value.type. - Character_String), - characterstring_length(&value.type.Character_String)); + /* All the object names in a device must be unique. + Disallow setting the Device Object Name to any objects in + 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; case PROP_LOCATION: @@ -1322,26 +1359,22 @@ bool Device_Write_Property( 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 * @param object_table [in,out] array of structure with object functions. * Each Child Object must provide some implementation of each of these * 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) + object_functions_t * object_table) { 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]; while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { if (pObject->Object_Init) { @@ -1412,8 +1445,6 @@ void Routing_Device_Init( { struct object_functions *pDevObject = NULL; - /* First, do the usual Device_Init() functions: */ - Device_Init(); /* Initialize with our preset strings */ Add_Routed_Device(first_object_instance, My_Object_Name, Description); diff --git a/bacnet-stack/demo/object/device.h b/bacnet-stack/demo/object/device.h index ea968903..ab17738a 100644 --- a/bacnet-stack/demo/object/device.h +++ b/bacnet-stack/demo/object/device.h @@ -71,10 +71,11 @@ typedef uint32_t( * is temporary and should be copied upon the return. It is * allocated by the system and does not need to be freed. */ -typedef char *( +typedef bool( *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 * instance number. @@ -179,8 +180,6 @@ extern "C" { #endif /* __cplusplus */ void Device_Init( - void); - void Device_Initialize_Object_Functions( object_functions_t * object_table); bool Device_Reinitialize( @@ -217,8 +216,17 @@ extern "C" { void); uint32_t Device_Index_To_Instance( 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( void); @@ -249,12 +257,6 @@ extern "C" { const char *name, size_t length); - bool Device_Set_Object_Name( - const char *name, - size_t length); - const char *Device_Object_Name( - void); - const char *Device_Description( void); bool Device_Set_Description( @@ -283,10 +285,10 @@ extern "C" { void); bool Device_Valid_Object_Name( - const char *object_name, + BACNET_CHARACTER_STRING *object_name, int *object_type, uint32_t * object_instance); - char *Device_Valid_Object_Id( + bool Device_Valid_Object_Id( int object_type, uint32_t object_instance); @@ -362,7 +364,7 @@ extern "C" { #endif /* __cplusplus */ #define DEVICE_OBJ_FUNCTIONS \ 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_Property_Lists, DeviceGetRRInfo, NULL /** @defgroup ObjFrmwk Object Framework diff --git a/bacnet-stack/demo/object/gw_device.c b/bacnet-stack/demo/object/gw_device.c index 24fd1545..418918d6 100644 --- a/bacnet-stack/demo/object/gw_device.c +++ b/bacnet-stack/demo/object/gw_device.c @@ -85,7 +85,7 @@ bool Routed_Device_Write_Property_Local( /**************************************************************************** ************* 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. ****************************************************************************/ @@ -96,8 +96,8 @@ DEVICE_OBJECT_DATA Devices[MAX_NUM_DEVICES]; /** Keep track of the number of managed devices, including the gateway */ uint16_t Num_Managed_Devices = 0; /** Which Device entry are we currently managing. - * 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 + * 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 * request is addressing. Should default to 0, the main gateway Device. */ uint16_t iCurrent_Device_Idx = 0; @@ -127,9 +127,15 @@ uint16_t Add_Routed_Device( pDev->bacObj.mObject_Type = OBJECT_DEVICE; pDev->bacObj.Object_Instance_Number = Object_Instance; 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 - 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) Routed_Device_Set_Description(sDescription, strlen(sDescription)); else @@ -147,7 +153,7 @@ uint16_t Add_Routed_Device( * -1 is a special case meaning "whichever iCurrent_Device_Idx * is currently set to" * If valid idx, will set iCurrent_Device_Idx with the idx - * @return Pointer to the requested Device Object 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). */ 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 * is currently set to" * If valid idx, will set iCurrent_Device_Idx with the idx - * @return Pointer to the requested Device Object BACnet address, or NULL if the idx + * @return Pointer to the requested Device Object BACnet address, or NULL if the idx * is for an invalid row entry (eg, after the last good Device). */ BACNET_ADDRESS *Get_Routed_Device_Address( @@ -186,9 +192,9 @@ BACNET_ADDRESS *Get_Routed_Device_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. - * + * * @param my_address [out] Points to the currently active Device Object's * BACnet address. */ @@ -205,18 +211,18 @@ void routed_get_my_address( /** See if the Gateway or Routed Device at the given idx matches * the given MAC address. * Has the desirable side-effect of setting iCurrent_Device_Idx to the - * 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. - * + * * @param idx [in] Index into Devices[] array being requested. * 0 is for the main, gateway Device entry. * @param address_len [in] Length of the mac_adress[] field. * If 0, then this is a MAC broadcast. Otherwise, size is determined * by the DLL type (eg, 6 for BIP and 2 for MSTP). * @param mac_adress [in] The desired MAC address of a Device; - * - * @return True if the MAC addresses match (or the address_len is 0, - * meaning MAC broadcast, so it's an automatic match). + * + * @return True if the MAC addresses match (or the address_len is 0, + * meaning MAC broadcast, so it's an automatic match). * Else False if no match or invalid idx is given. */ 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". - * Has the desirable side-effect of setting internal iCurrent_Device_Idx - * if a match is found, for use in the subsequent routing handling + * Has the desirable side-effect of setting internal iCurrent_Device_Idx + * if a match is found, for use in the subsequent routing handling * functions. - * + * * @param dest [in] The BACNET_ADDRESS of the message's destination. - * If the Length of the mac_adress[] field is 0, then this is a MAC + * If the Length of the mac_adress[] field is 0, then this is a MAC * broadcast. Otherwise, size is determined * by the DLL type (eg, 6 for BIP and 2 for MSTP). * @param DNET_list [in] List of our reachable downstream BACnet Network numbers. * Normally just one valid entry; terminated with a -1 value. * @param cursor [in,out] The concept of the cursor is that it is a starting * "hint" for the search; on return, it is updated to provide the - * cursor value to use with a subsequent GetNext call, or it + * cursor value to use with a subsequent GetNext call, or it * equals -1 if there are no further matches. * Set it to 0 on entry to access the main, gateway Device entry, or * to start looping through the routed devices. - * Otherwise, its returned value is implementation-dependent and the + * Otherwise, its returned value is implementation-dependent and the * calling function should not alter or interpret it. - * + * * @return True if the MAC addresses match (or if BACNET_BROADCAST_NETWORK and - * the dest->len is 0, meaning MAC bcast, so it's an automatic match). + * the dest->len is 0, meaning MAC bcast, so it's an automatic match). * Else False if no match or invalid idx is given; the cursor will * be returned as -1 in these cases. */ @@ -289,14 +295,14 @@ bool Routed_Device_GetNext( if ((idx < 0) || (idx >= MAX_NUM_DEVICES)) 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. */ else if (dest->net == BACNET_BROADCAST_NETWORK) { /* Just take the entry indexed by the cursor */ 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. */ 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, * or local or else broadcast. - * + * * @param dest_net [in] The BACnet network number of a message's destination. - * Success if it is our virtual network number, or 0 (local for the + * Success if it is our virtual network number, or 0 (local for the * gateway, or 0xFFFF for a broadcast network number. * @param DNET_list [in] List of our reachable downstream BACnet Network numbers. * Normally just one valid entry; terminated with a -1 value. - * @return True if matches our virtual network, or is for the local network + * @return True if matches our virtual network, or is for the local network * Device (the gateway), or is BACNET_BROADCAST_NETWORK, which is - * an automatic match. + * an automatic match. * Else False if not a reachable 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). */ if (dest_net == BACNET_BROADCAST_NETWORK) 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. */ 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; } -/** See if the requested Object instance matches that for the currently - * indexed Device Object. - * iCurrent_Device_Idx must have been set to point to this Device Object +/** See if the requested Object instance matches that for the currently + * indexed Device Object. + * iCurrent_Device_Idx must have been set to point to this Device Object * before this function is called. * @param object_id [in] Object ID of the desired Device object. - * If the wildcard value (BACNET_MAX_INSTANCE), always matches. + * If the wildcard value (BACNET_MAX_INSTANCE), always matches. * @return True if Object ID matches the present Device, else False. */ bool Routed_Device_Valid_Object_Instance_Number( @@ -497,8 +503,9 @@ bool Routed_Device_Write_Property_Local( WPValidateString(&value, MAX_DEV_NAME_LEN, false, &wp_data->error_class, &wp_data->error_code); if (status) { - Routed_Device_Set_Object_Name(characterstring_value - (&value.type.Character_String), + Routed_Device_Set_Object_Name( + characterstring_encoding(&value.type.Character_String), + characterstring_value(&value.type.Character_String), characterstring_length(&value.type.Character_String)); } break; @@ -512,9 +519,9 @@ bool Routed_Device_Write_Property_Local( /* methods to manipulate the data */ /** 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. - * + * * @return The Instance number of the currently active Device. */ uint32_t Routed_Device_Object_Instance_Number( @@ -538,24 +545,24 @@ bool Routed_Device_Set_Object_Instance_Number( return status; } - /** Sets the Object Name for a routed Device (or the gateway). * Uses local variable iCurrent_Device_Idx to know which Device * is to be updated. - * @param name [in] Text for the new Object Name. - * @param length [in] Length of name[] text. + * @param object_name [in] Character String for the new Object Name. * @return True if succeed in updating Object Name, else False. */ bool Routed_Device_Set_Object_Name( - const char *name, - size_t length) + uint8_t encoding, + const char *value, + size_t length); { bool status = false; /*return value */ 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 */ - memmove(pDev->bacObj.Object_Name, name, length); + memmove(pDev->bacObj.Object_Name, value, length); pDev->bacObj.Object_Name[length] = 0; Routed_Device_Inc_Database_Revision(); status = true; @@ -581,7 +588,7 @@ bool Routed_Device_Set_Description( } -/* +/* * Shortcut for incrementing database revision as this is potentially * the most common operation if changing object names and ids is * implemented. diff --git a/bacnet-stack/demo/object/lc.c b/bacnet-stack/demo/object/lc.c index eacb2c5c..1ed8617e 100644 --- a/bacnet-stack/demo/object/lc.c +++ b/bacnet-stack/demo/object/lc.c @@ -272,17 +272,19 @@ static BACNET_SHED_STATE Load_Control_Present_Value( } /* note: the object name must be unique within this device */ -char *Load_Control_Name( - uint32_t object_instance) +bool Load_Control_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_LOAD_CONTROLS) { 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( @@ -706,8 +708,7 @@ int Load_Control_Read_Property( break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Load_Control_Name(rpdata->object_instance)); + Load_Control_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/lc.h b/bacnet-stack/demo/object/lc.h index 40b764c2..2a8943ba 100644 --- a/bacnet-stack/demo/object/lc.h +++ b/bacnet-stack/demo/object/lc.h @@ -51,8 +51,10 @@ extern "C" { unsigned index); unsigned Load_Control_Instance_To_Index( 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); @@ -77,7 +79,7 @@ extern "C" { #define LOAD_CONTROL_OBJ_FUNCTIONS \ OBJECT_LOAD_CONTROL, Load_Control_Init, Load_Control_Count, \ 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, \ NULL #endif diff --git a/bacnet-stack/demo/object/lsp.c b/bacnet-stack/demo/object/lsp.c index f1edf765..33d76a69 100644 --- a/bacnet-stack/demo/object/lsp.c +++ b/bacnet-stack/demo/object/lsp.c @@ -173,17 +173,19 @@ static BACNET_LIFE_SAFETY_STATE Life_Safety_Point_Present_Value( } /* note: the object name must be unique within this device */ -char *Life_Safety_Point_Name( - uint32_t object_instance) +bool Life_Safety_Point_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_LIFE_SAFETY_POINTS) { 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 */ @@ -216,8 +218,7 @@ int Life_Safety_Point_Read_Property( break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Life_Safety_Point_Name(rpdata->object_instance)); + Life_Safety_Point_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/lsp.h b/bacnet-stack/demo/object/lsp.h index 37d51018..56e41691 100644 --- a/bacnet-stack/demo/object/lsp.h +++ b/bacnet-stack/demo/object/lsp.h @@ -48,8 +48,9 @@ extern "C" { unsigned index); unsigned Life_Safety_Point_Instance_To_Index( uint32_t object_instance); - char *Life_Safety_Point_Name( - uint32_t object_instance); + bool Life_Safety_Point_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name); void Life_Safety_Point_Init( void); @@ -71,7 +72,7 @@ extern "C" { #define LIFE_SAFETY_POINT_OBJ_FUNCTIONS \ OBJECT_LIFE_SAFETY_POINT, Life_Safety_Point_Init, \ 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_Write_Property, \ Life_Safety_Point_Property_Lists, NULL, NULL diff --git a/bacnet-stack/demo/object/ms-input.c b/bacnet-stack/demo/object/ms-input.c index 7a143ba5..38278961 100644 --- a/bacnet-stack/demo/object/ms-input.c +++ b/bacnet-stack/demo/object/ms-input.c @@ -225,18 +225,19 @@ bool Multistate_Input_Description_Set( return status; } -char *Multistate_Input_Name( - uint32_t object_instance) +bool Multistate_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { unsigned index = 0; /* offset from instance lookup */ - char *pName = NULL; /* return value */ + bool status = false; index = Multistate_Input_Instance_To_Index(object_instance); 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 */ @@ -347,8 +348,7 @@ int Multistate_Input_Read_Property( /* note: Name and Description don't have to be the same. You could make Description writable and different */ case PROP_OBJECT_NAME: - characterstring_init_ansi(&char_string, - Multistate_Input_Name(rpdata->object_instance)); + Multistate_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/ms-input.h b/bacnet-stack/demo/object/ms-input.h index 6ed1f609..e7e97884 100644 --- a/bacnet-stack/demo/object/ms-input.h +++ b/bacnet-stack/demo/object/ms-input.h @@ -59,11 +59,14 @@ extern "C" { /* optional API */ bool Multistate_Input_Object_Instance_Add( 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( uint32_t object_instance, char *new_name); + uint32_t Multistate_Input_Present_Value( uint32_t object_instance); bool Multistate_Input_Present_Value_Set( @@ -96,7 +99,7 @@ extern "C" { #define MULTI_STATE_INPUT_OBJ_FUNCTIONS \ OBJECT_MULTI_STATE_INPUT, Multistate_Input_Init, \ 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_Write_Property, \ Multistate_Input_Property_Lists, NULL, NULL diff --git a/bacnet-stack/demo/object/mso.c b/bacnet-stack/demo/object/mso.c index d17846fb..efd8fecf 100644 --- a/bacnet-stack/demo/object/mso.c +++ b/bacnet-stack/demo/object/mso.c @@ -180,17 +180,19 @@ static uint32_t Multistate_Output_Present_Value( } /* note: the object name must be unique within this device */ -char *Multistate_Output_Name( - uint32_t object_instance) +bool Multistate_Output_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_MULTISTATE_OUTPUTS) { 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 */ @@ -222,8 +224,7 @@ int Multistate_Output_Read_Property( You could make Description writable and different */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Multistate_Output_Name(rpdata->object_instance)); + Multistate_Output_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/demo/object/mso.h b/bacnet-stack/demo/object/mso.h index c602ddd2..0e971854 100644 --- a/bacnet-stack/demo/object/mso.h +++ b/bacnet-stack/demo/object/mso.h @@ -48,8 +48,10 @@ extern "C" { unsigned index); unsigned Multistate_Output_Instance_To_Index( 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); @@ -72,7 +74,7 @@ extern "C" { #define MULTI_STATE_OUTPUT_OBJ_FUNCTIONS \ OBJECT_MULTI_STATE_OUTPUT, Multistate_Output_Init, \ 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_Write_Property, \ Multistate_Output_Property_Lists, NULL, NULL diff --git a/bacnet-stack/demo/object/trendlog.c b/bacnet-stack/demo/object/trendlog.c index b10ff0b3..3a0fd065 100644 --- a/bacnet-stack/demo/object/trendlog.c +++ b/bacnet-stack/demo/object/trendlog.c @@ -80,7 +80,7 @@ static const int Trend_Log_Properties_Optional[] = { PROP_COV_RESUBSCRIPTION_INTERVAL, PROP_CLIENT_COV_INCREMENT, */ -/* Required if intrinsic reporting supported +/* Required if intrinsic reporting supported PROP_NOTIFICATION_THRESHOLD, PROP_RECORDS_SINCE_NOTIFICATION, PROP_LAST_NOTIFY_RECORD, @@ -179,7 +179,7 @@ void Trend_Log_Init( /* initialize all the values */ for (iLog = 0; iLog < MAX_TREND_LOGS; iLog++) { - /* + /* * Do we need to do anything here? * Trend logs are usually assumed to survive over resets * 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 * is not we need to convert to index before proceeding. */ -char *Trend_Log_Name( - uint32_t object_instance) +bool Trend_Log_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ + bool status = false; if (object_instance < MAX_TREND_LOGS) { 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_OBJECT_NAME: - characterstring_init_ansi(&char_string, - Trend_Log_Name(rpdata->object_instance)); + Trend_Log_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; @@ -496,14 +497,14 @@ bool Trend_Log_Write_Property( /* To do: what actions do we need to take on writing ? */ if (value.type.Boolean == false) { if (bEffectiveEnable == true) { - /* Only insert record if we really were + /* Only insert record if we really were enabled i.e. times and enable flags */ TL_Insert_Status_Rec(log_index, LOG_STATUS_LOG_DISABLED, true); } } else { 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 */ TL_Insert_Status_Rec(log_index, @@ -563,7 +564,7 @@ bool Trend_Log_Write_Property( break; case PROP_LOGGING_TYPE: - /* logic + /* logic * triggered and polled options. */ 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 */ /* 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. */ iTemp = @@ -1151,7 +1152,7 @@ int TL_encode_by_position( * start index/positive count and then process as * normal. This assumes that the order to return items * 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 * values due to the mix of signed and unsigned types - don't @@ -1184,7 +1185,7 @@ int TL_encode_by_position( while (uiIndex <= uiTarget) { 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 */ bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS, @@ -1318,7 +1319,7 @@ int TL_encode_by_sequence( while (uiSequence != uiEnd + 1) { 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 */ 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 */ /* If count would bring us back beyond the limits * 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. */ iTemp = pRequest->Count - 1; @@ -1450,7 +1451,7 @@ int TL_encode_by_time( while (iCount != 0) { 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 */ 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 * since the last reading. This ensures we take a reading as * 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); } diff --git a/bacnet-stack/demo/object/trendlog.h b/bacnet-stack/demo/object/trendlog.h index 55512b57..cd0cee67 100644 --- a/bacnet-stack/demo/object/trendlog.h +++ b/bacnet-stack/demo/object/trendlog.h @@ -104,7 +104,7 @@ extern "C" { time_t tLastDataTime; } TL_LOG_INFO; -/* +/* * 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 * the log datum field. @@ -139,8 +139,9 @@ extern "C" { bool Trend_Log_Object_Instance_Add( uint32_t instance); - char *Trend_Log_Name( - uint32_t object_instance); + bool Trend_Log_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name); int Trend_Log_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata); @@ -199,7 +200,7 @@ extern "C" { #define TRENDLOG_OBJ_FUNCTIONS \ OBJECT_TRENDLOG, Trend_Log_Init, Trend_Log_Count, \ 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, \ TrendLogGetRRInfo, NULL #endif diff --git a/bacnet-stack/demo/ptransfer/main.c b/bacnet-stack/demo/ptransfer/main.c index ae6c231e..6c5597e5 100644 --- a/bacnet-stack/demo/ptransfer/main.c +++ b/bacnet-stack/demo/ptransfer/main.c @@ -66,6 +66,11 @@ uint8_t Send_Private_Transfer_Request( char block_number, 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 */ static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; @@ -124,7 +129,7 @@ void MyRejectHandler( static void Init_Service_Handlers( void) { - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/readfile/main.c b/bacnet-stack/demo/readfile/main.c index 0a468f9f..05463819 100644 --- a/bacnet-stack/demo/readfile/main.c +++ b/bacnet-stack/demo/readfile/main.c @@ -185,8 +185,7 @@ static void LocalIAmHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/readprop/main.c b/bacnet-stack/demo/readprop/main.c index 16ce33c6..b5ba03ea 100644 --- a/bacnet-stack/demo/readprop/main.c +++ b/bacnet-stack/demo/readprop/main.c @@ -149,8 +149,7 @@ void My_Read_Property_Ack_Handler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/readpropm/main.c b/bacnet-stack/demo/readpropm/main.c index 3988ca12..a038a250 100644 --- a/bacnet-stack/demo/readpropm/main.c +++ b/bacnet-stack/demo/readpropm/main.c @@ -194,8 +194,7 @@ void My_Read_Property_Multiple_Ack_Handler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/readrange/main.c b/bacnet-stack/demo/readrange/main.c index 4f7752d2..7088f004 100644 --- a/bacnet-stack/demo/readrange/main.c +++ b/bacnet-stack/demo/readrange/main.c @@ -80,13 +80,11 @@ #define _stricmp stricmp #endif -uint8_t Send_Private_Transfer_Request( - uint32_t device_id, - uint16_t vendor_id, - uint32_t service_number, - char block_number, - 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 */ static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; @@ -145,7 +143,7 @@ void MyRejectHandler( static void Init_Objects( void) { - Device_Init(); + Device_Init(&Object_Table[0]); } static void Init_Service_Handlers( diff --git a/bacnet-stack/demo/reinit/main.c b/bacnet-stack/demo/reinit/main.c index e1467422..a1cf6cd2 100644 --- a/bacnet-stack/demo/reinit/main.c +++ b/bacnet-stack/demo/reinit/main.c @@ -120,8 +120,7 @@ void MyReinitializeDeviceSimpleAckHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/server/main.c b/bacnet-stack/demo/server/main.c index b71ab30a..be706089 100644 --- a/bacnet-stack/demo/server/main.c +++ b/bacnet-stack/demo/server/main.c @@ -101,8 +101,7 @@ static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* 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_HAS, handler_who_has); diff --git a/bacnet-stack/demo/timesync/main.c b/bacnet-stack/demo/timesync/main.c index 25305147..14787bd5 100644 --- a/bacnet-stack/demo/timesync/main.c +++ b/bacnet-stack/demo/timesync/main.c @@ -92,8 +92,7 @@ void MyRejectHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/ucov/main.c b/bacnet-stack/demo/ucov/main.c index 09cdb33d..cd79299c 100644 --- a/bacnet-stack/demo/ucov/main.c +++ b/bacnet-stack/demo/ucov/main.c @@ -59,8 +59,7 @@ static object_functions_t Object_Table[] = { static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/whohas/main.c b/bacnet-stack/demo/whohas/main.c index 7018bee1..5e079b44 100644 --- a/bacnet-stack/demo/whohas/main.c +++ b/bacnet-stack/demo/whohas/main.c @@ -95,8 +95,7 @@ void MyRejectHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/whois/main.c b/bacnet-stack/demo/whois/main.c index 8f15022d..c3a3c812 100644 --- a/bacnet-stack/demo/whois/main.c +++ b/bacnet-stack/demo/whois/main.c @@ -95,8 +95,7 @@ void MyRejectHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* Note: this applications doesn't need to handle who-is it is confusing for the user! */ /* set the handler for all the services we don't implement diff --git a/bacnet-stack/demo/whoisrouter/main.c b/bacnet-stack/demo/whoisrouter/main.c index 65df6865..a5b8249a 100644 --- a/bacnet-stack/demo/whoisrouter/main.c +++ b/bacnet-stack/demo/whoisrouter/main.c @@ -175,8 +175,7 @@ void My_NPDU_Handler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/writefile/main.c b/bacnet-stack/demo/writefile/main.c index b10b9b05..efb08479 100644 --- a/bacnet-stack/demo/writefile/main.c +++ b/bacnet-stack/demo/writefile/main.c @@ -139,8 +139,7 @@ static void LocalIAmHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/demo/writeprop/main.c b/bacnet-stack/demo/writeprop/main.c index a3364991..f3fe73db 100644 --- a/bacnet-stack/demo/writeprop/main.c +++ b/bacnet-stack/demo/writeprop/main.c @@ -140,8 +140,7 @@ void MyWritePropertySimpleAckHandler( static void Init_Service_Handlers( void) { - Device_Initialize_Object_Functions(&Object_Table[0]); - Device_Init(); + Device_Init(&Object_Table[0]); /* we need to handle who-is to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); diff --git a/bacnet-stack/include/bacenum.h b/bacnet-stack/include/bacenum.h index 0d342948..329e3a80 100644 --- a/bacnet-stack/include/bacenum.h +++ b/bacnet-stack/include/bacenum.h @@ -952,7 +952,7 @@ typedef enum { } BACNET_VT_CLASS; typedef enum { - CHARACTER_ANSI_X34 = 0, + CHARACTER_ANSI_X34 = 0, /* deprecated */ CHARACTER_UTF8 = 0, CHARACTER_MS_DBCS = 1, CHARACTER_JISC_6226 = 2, diff --git a/bacnet-stack/include/bacstr.h b/bacnet-stack/include/bacstr.h index 12f7c199..45996956 100644 --- a/bacnet-stack/include/bacstr.h +++ b/bacnet-stack/include/bacstr.h @@ -153,6 +153,8 @@ extern "C" { BACNET_CHARACTER_STRING * char_string); bool characterstring_printable( BACNET_CHARACTER_STRING * char_string); + bool characterstring_valid( + BACNET_CHARACTER_STRING * char_string); /* returns false if the string exceeds capacity initialize by using length=0 */ diff --git a/bacnet-stack/include/client.h b/bacnet-stack/include/client.h index 1c50fcce..89d84fd6 100644 --- a/bacnet-stack/include/client.h +++ b/bacnet-stack/include/client.h @@ -97,7 +97,7 @@ extern "C" { uint32_t device_id, BACNET_OBJECT_TYPE object_type, uint32_t object_instance, - const char *object_name); + BACNET_CHARACTER_STRING *object_name); int Send_UCOV_Notify( uint8_t * buffer, diff --git a/bacnet-stack/include/whohas.h b/bacnet-stack/include/whohas.h index b86da356..f6ddeda5 100644 --- a/bacnet-stack/include/whohas.h +++ b/bacnet-stack/include/whohas.h @@ -41,7 +41,7 @@ typedef struct BACnet_Who_Has_Data { int32_t low_limit; /* deviceInstanceRange */ int32_t high_limit; - bool object_name; /* true if a string */ + bool is_object_name; /* true if a string */ union { BACNET_OBJECT_ID identifier; BACNET_CHARACTER_STRING name; @@ -79,14 +79,14 @@ extern "C" { /** @defgroup DMDOB Device Management-Dynamic Object Binding (DM-DOB) * @ingroup RDMS * 16.9 Who-Has and I-Have Services
- * 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 - * 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 - * 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 - * does not need to be preceded by the receipt of a Who-Has service request. + * 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 + * 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 + * 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 + * 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. - * + * */ #endif diff --git a/bacnet-stack/ports/at91sam7s/Makefile b/bacnet-stack/ports/at91sam7s/Makefile index 86f903f6..15be50b4 100644 --- a/bacnet-stack/ports/at91sam7s/Makefile +++ b/bacnet-stack/ports/at91sam7s/Makefile @@ -22,8 +22,12 @@ BACNET_FLAGS += -DCRC_USE_TABLE BACNET_CORE = ../../src BACNET_DEMO = ../../demo BACNET_INCLUDE = ../../include +BACNET_OBJECT = ../../demo/object +BACNET_HANDLER = ../../demo/handler INCLUDES = -I. INCLUDES += -I$(BACNET_INCLUDE) +INCLUDES += -I$(BACNET_OBJECT) +INCLUDES += -I$(BACNET_HANDLER) #OPTIMIZATION = -O0 OPTIMIZATION = -Os CFLAGS = -fno-common $(INCLUDES) $(BACNET_FLAGS) -Wall -g diff --git a/bacnet-stack/ports/at91sam7s/ai.c b/bacnet-stack/ports/at91sam7s/ai.c index 8b305c51..c0721e14 100644 --- a/bacnet-stack/ports/at91sam7s/ai.c +++ b/bacnet-stack/ports/at91sam7s/ai.c @@ -107,17 +107,19 @@ uint32_t Analog_Input_Index_To_Instance( return index; } -char *Analog_Input_Name( - uint32_t object_instance) +bool Analog_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[16] = "AI-0"; /* okay for single thread */ + bool status = false; if (object_instance < MAX_ANALOG_INPUTS) { text_string[3] = '0' + (uint8_t) object_instance; - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } float Analog_Input_Present_Value( @@ -165,8 +167,7 @@ int Analog_Input_Read_Property( You could make Description writable and different */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Analog_Input_Name(rpdata->object_instance)); + Analog_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/ports/at91sam7s/av.c b/bacnet-stack/ports/at91sam7s/av.c index 68f78efe..26770208 100644 --- a/bacnet-stack/ports/at91sam7s/av.c +++ b/bacnet-stack/ports/at91sam7s/av.c @@ -165,18 +165,19 @@ float Analog_Value_Present_Value( return value; } -/* note: the object name must be unique within this device */ -char *Analog_Value_Name( - uint32_t object_instance) +bool Analog_Value_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[16] = "AV-0"; /* okay for single thread */ + bool status = false; if (object_instance < MAX_ANALOG_VALUES) { text_string[3] = '0' + (uint8_t) object_instance; - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } /* return apdu len, or -1 on error */ @@ -208,8 +209,7 @@ int Analog_Value_Read_Property( break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Analog_Value_Name(rpdata->object_instance)); + Analog_Value_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/ports/at91sam7s/bi.c b/bacnet-stack/ports/at91sam7s/bi.c index 56452bd1..fbb2a232 100644 --- a/bacnet-stack/ports/at91sam7s/bi.c +++ b/bacnet-stack/ports/at91sam7s/bi.c @@ -144,17 +144,19 @@ BACNET_BINARY_PV Binary_Input_Present_Value( return value; } -char *Binary_Input_Name( - uint32_t object_instance) +bool Binary_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[16] = "BI-0"; /* okay for single thread */ + bool status = false; if (object_instance < MAX_BINARY_INPUTS) { text_string[3] = '0' + (uint8_t) object_instance; - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } /* return apdu length, or -1 on error */ @@ -182,9 +184,7 @@ int Binary_Input_Read_Property( break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - /* note: object name must be unique in our device */ - characterstring_init_ansi(&char_string, - Binary_Input_Name(rpdata->object_instance)); + Binary_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/ports/at91sam7s/bv.c b/bacnet-stack/ports/at91sam7s/bv.c index fcdccd70..10b7312a 100644 --- a/bacnet-stack/ports/at91sam7s/bv.c +++ b/bacnet-stack/ports/at91sam7s/bv.c @@ -139,17 +139,19 @@ static BACNET_BINARY_PV Binary_Value_Present_Value( } /* note: the object name must be unique within this device */ -char *Binary_Value_Name( - uint32_t object_instance) +bool Binary_Value_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[16] = "BV-0"; /* okay for single thread */ + bool status = false; if (object_instance < MAX_BINARY_VALUES) { text_string[3] = '0' + (uint8_t) object_instance; - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } /* return apdu len, or -1 on error */ @@ -179,8 +181,7 @@ int Binary_Value_Read_Property( You could make Description writable and different */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Binary_Value_Name(rpdata->object_instance)); + Binary_Value_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; diff --git a/bacnet-stack/ports/at91sam7s/device.c b/bacnet-stack/ports/at91sam7s/device.c index d3ee2140..4c213f69 100644 --- a/bacnet-stack/ports/at91sam7s/device.c +++ b/bacnet-stack/ports/at91sam7s/device.c @@ -25,13 +25,15 @@ #include #include +#include #include #include "bacdef.h" #include "bacdcode.h" #include "bacstr.h" #include "bacenum.h" #include "apdu.h" -#include "dlmstp.h" +#include "dcc.h" +#include "datalink.h" #include "rs485.h" #include "version.h" #include "handlers.h" @@ -44,16 +46,7 @@ #include "wp.h" #include "dcc.h" -/* note: you really only need to define variables for - properties that are writable or that may change. - The properties that are constant can be hard coded - into the read-property encoding. */ -static uint32_t Object_Instance_Number = 12345; -static char My_Object_Name[32] = "ARM7 Device"; -static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; -static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE; - -/* forward prototypes */ +/* forward prototype */ int Device_Read_Property_Local( BACNET_READ_PROPERTY_DATA * rpdata); bool Device_Write_Property_Local( @@ -73,28 +66,38 @@ static struct my_object_functions { { OBJECT_DEVICE, NULL, /* don't init - recursive! */ Device_Count, Device_Index_To_Instance, - Device_Valid_Object_Instance_Number, Device_Name, + Device_Valid_Object_Instance_Number, Device_Object_Name, Device_Read_Property_Local, Device_Write_Property_Local, Device_Property_Lists}, { OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, - Analog_Input_Name, Analog_Input_Read_Property, NULL, + Analog_Input_Object_Name, Analog_Input_Read_Property, NULL, Analog_Input_Property_Lists}, { OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, - Analog_Value_Name, Analog_Value_Read_Property, + Analog_Value_Object_Name, Analog_Value_Read_Property, Analog_Value_Write_Property, Analog_Value_Property_Lists}, { OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance, - Binary_Input_Name, Binary_Input_Read_Property, NULL, + Binary_Input_Object_Name, Binary_Input_Read_Property, NULL, Binary_Input_Property_Lists}, { OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count, Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance, - Binary_Value_Name, Binary_Value_Read_Property, + Binary_Value_Object_Name, Binary_Value_Read_Property, Binary_Value_Write_Property, Binary_Value_Property_Lists}, { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL} }; +/* note: you really only need to define variables for + properties that are writable or that may change. + The properties that are constant can be hard coded + into the read-property encoding. */ +static uint32_t Object_Instance_Number; +static BACNET_CHARACTER_STRING My_Object_Name; +static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; +static uint32_t Database_Revision; +static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE; + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, @@ -132,54 +135,92 @@ static const int Device_Properties_Proprietary[] = { -1 }; -void Device_Property_Lists( - const int **pRequired, - const int **pOptional, - const int **pProprietary) +static struct my_object_functions *Device_Objects_Find_Functions( + BACNET_OBJECT_TYPE Object_Type) { - if (pRequired) - *pRequired = Device_Properties_Required; - if (pOptional) - *pOptional = Device_Properties_Optional; - if (pProprietary) - *pProprietary = Device_Properties_Proprietary; + struct my_object_functions *pObject = NULL; - return; + pObject = &Object_Table[0]; + while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { + /* handle each object type */ + if (pObject->Object_Type == Object_Type) { + return (pObject); + } + + pObject++; + } + + return (NULL); +} + +static int Read_Property_Common( + struct my_object_functions *pObject, + BACNET_READ_PROPERTY_DATA * rpdata) +{ + int apdu_len = BACNET_STATUS_ERROR; + BACNET_CHARACTER_STRING char_string; + uint8_t *apdu = NULL; + + if ((rpdata->application_data == NULL) || + (rpdata->application_data_len == 0)) { + return 0; + } + apdu = rpdata->application_data; + switch (rpdata->object_property) { + case PROP_OBJECT_IDENTIFIER: + /* Device Object exception: requested instance + may not match our instance if a wildcard */ + if (rpdata->object_type == OBJECT_DEVICE) { + rpdata->object_instance = Object_Instance_Number; + } + apdu_len = + encode_application_object_id(&apdu[0], rpdata->object_type, + rpdata->object_instance); + break; + case PROP_OBJECT_NAME: + if (pObject->Object_Name) { + (void)pObject->Object_Name( + rpdata->object_instance, + &char_string); + } else { + characterstring_init_ansi(&char_string, ""); + } + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = + encode_application_enumerated(&apdu[0], rpdata->object_type); + break; + default: + if (pObject->Object_Read_Property) { + apdu_len = pObject->Object_Read_Property(rpdata); + } + break; + } + + return apdu_len; } /* Encodes the property APDU and returns the length, - or sets the error, and returns -1 */ + or sets the error, and returns BACNET_STATUS_ERROR */ int Device_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int apdu_len = BACNET_STATUS_ERROR; - unsigned index = 0; struct my_object_functions *pObject = NULL; - bool found = false; /* initialize the default return values */ - rpdata->error_class = ERROR_CLASS_OBJECT; - rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT; - pObject = &Object_Table[0]; - while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { - /* handle each object type */ - if (pObject->Object_Type == rpdata->object_type) { - found = true; + pObject = Device_Objects_Find_Functions(rpdata->object_type); + if (pObject) { if (pObject->Object_Valid_Instance && pObject->Object_Valid_Instance(rpdata->object_instance)) { - if (pObject->Object_Read_Property) { - apdu_len = pObject->Object_Read_Property(rpdata); - } + apdu_len = Read_Property_Common(pObject, rpdata); } else { rpdata->error_class = ERROR_CLASS_OBJECT; rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT; } - break; - } - index++; - pObject = &Object_Table[index]; - } - if (!found) { + } else { rpdata->error_class = ERROR_CLASS_OBJECT; rpdata->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE; } @@ -191,18 +232,11 @@ bool Device_Write_Property( BACNET_WRITE_PROPERTY_DATA * wp_data) { bool status = false; - unsigned index = 0; struct my_object_functions *pObject = NULL; - bool found = false; /* initialize the default return values */ - wp_data->error_class = ERROR_CLASS_OBJECT; - wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; - pObject = &Object_Table[0]; - while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { - /* handle each object type */ - if (pObject->Object_Type == wp_data->object_type) { - found = true; + pObject = Device_Objects_Find_Functions(wp_data->object_type); + if (pObject) { if (pObject->Object_Valid_Instance && pObject->Object_Valid_Instance(wp_data->object_instance)) { if (pObject->Object_Write_Property) { @@ -215,12 +249,7 @@ bool Device_Write_Property( wp_data->error_class = ERROR_CLASS_OBJECT; wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; } - break; - } - index++; - pObject = &Object_Table[index]; - } - if (!found) { + } else { wp_data->error_class = ERROR_CLASS_OBJECT; wp_data->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE; } @@ -248,59 +277,222 @@ void Device_Objects_Property_List( BACNET_OBJECT_TYPE object_type, struct special_property_list_t *pPropertyList) { - rpm_property_lists_function object_property_list = NULL; - unsigned index = 0; struct my_object_functions *pObject = NULL; - bool found = false; pPropertyList->Required.pList = NULL; pPropertyList->Optional.pList = NULL; pPropertyList->Proprietary.pList = NULL; - pObject = &Object_Table[0]; - while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { - /* handle each object type */ - if (pObject->Object_Type == object_type) { - found = true; - object_property_list = pObject->Object_RPM_List; - break; - } - index++; - pObject = &Object_Table[index]; - } - if (found && object_property_list) { - object_property_list(&pPropertyList->Required.pList, + + /* If we can find an entry for the required object type + * and there is an Object_List_RPM fn ptr then call it + * to populate the pointers to the individual list counters. + */ + + pObject = Device_Objects_Find_Functions(object_type); + if ((pObject != NULL) && (pObject->Object_RPM_List != NULL)) { + pObject->Object_RPM_List(&pPropertyList->Required.pList, &pPropertyList->Optional.pList, &pPropertyList->Proprietary.pList); } - /* fill the count */ - if (pPropertyList->Required.pList) { - pPropertyList->Required.count = - property_list_count(pPropertyList->Required.pList); - } else { - pPropertyList->Required.count = 0; - } - if (pPropertyList->Optional.pList) { - pPropertyList->Optional.count = - property_list_count(pPropertyList->Optional.pList); - } else { - pPropertyList->Optional.count = 0; - } - if (pPropertyList->Proprietary.pList) { - pPropertyList->Proprietary.count = - property_list_count(pPropertyList->Proprietary.pList); - } else { - pPropertyList->Proprietary.count = 0; - } + + /* Fetch the counts if available otherwise zero them */ + pPropertyList->Required.count = + pPropertyList->Required.pList == + NULL ? 0 : property_list_count(pPropertyList->Required.pList); + + pPropertyList->Optional.count = + pPropertyList->Optional.pList == + NULL ? 0 : property_list_count(pPropertyList->Optional.pList); + + pPropertyList->Proprietary.count = + pPropertyList->Proprietary.pList == + NULL ? 0 : property_list_count(pPropertyList->Proprietary.pList); return; } +void Device_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (pRequired) + *pRequired = Device_Properties_Required; + if (pOptional) + *pOptional = Device_Properties_Optional; + if (pProprietary) + *pProprietary = Device_Properties_Proprietary; + + return; +} + +unsigned Device_Count( + void) +{ + return 1; +} + +uint32_t Device_Index_To_Instance( + unsigned index) +{ + index = index; + return Object_Instance_Number; +} + +bool Device_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) +{ + bool status = false; + + if (object_instance == Object_Instance_Number) { + status = characterstring_copy(object_name, &My_Object_Name); + } + + return status; +} + +bool Device_Set_Object_Name( + BACNET_CHARACTER_STRING *object_name) +{ + bool status = false; /*return value */ + + if (!characterstring_same(&My_Object_Name, object_name)) { + /* Make the change and update the database revision */ + status = characterstring_copy(&My_Object_Name, object_name); + Device_Inc_Database_Revision(); + } + + return status; +} + +bool Device_Reinitialize( + BACNET_REINITIALIZE_DEVICE_DATA * rd_data) +{ + bool status = false; + + if (characterstring_ansi_same(&rd_data->password, "rehmite")) { + Reinitialize_State = rd_data->state; + dcc_set_status_duration(COMMUNICATION_ENABLE, 0); + /* Note: you could use a mix of state + and password to multiple things */ + /* note: you probably want to restart *after* the + simple ack has been sent from the return handler + so just set a flag from here */ + status = true; + } else { + rd_data->error_class = ERROR_CLASS_SECURITY; + rd_data->error_code = ERROR_CODE_PASSWORD_FAILURE; + } + + return status; +} + +BACNET_REINITIALIZED_STATE Device_Reinitialized_State( + void) +{ + return Reinitialize_State; +} + +void Device_Init( + object_functions_t * object_table) +{ + struct my_object_functions *pObject = NULL; + + /* we don't use the object table passed in + since there is extra stuff we don't need in there. */ + (void)object_table; + /* our local object table */ + pObject = &Object_Table[0]; + while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { + if (pObject->Object_Init) { + pObject->Object_Init(); + } + pObject++; + } + dcc_set_status_duration(COMMUNICATION_ENABLE, 0); + Object_Instance_Number = 12345; + characterstring_init_ansi(&My_Object_Name, "ARM7 Demo Device"); +} + +/* methods to manipulate the data */ +uint32_t Device_Object_Instance_Number( + void) +{ + return Object_Instance_Number; +} + +bool Device_Set_Object_Instance_Number( + uint32_t object_id) +{ + bool status = true; /* return value */ + + if (object_id <= BACNET_MAX_INSTANCE) { + Object_Instance_Number = object_id; + } else + status = false; + + return status; +} + +bool Device_Valid_Object_Instance_Number( + uint32_t object_id) +{ + /* BACnet allows for a wildcard instance number */ + return ((Object_Instance_Number == object_id) || + (object_id == BACNET_MAX_INSTANCE)); + } + +BACNET_DEVICE_STATUS Device_System_Status( + void) +{ + return System_Status; +} + +int Device_Set_System_Status( + BACNET_DEVICE_STATUS status, + bool local) +{ + /*return value - 0 = ok, -1 = bad value, -2 = not allowed */ + int result = -1; + + if (status < MAX_DEVICE_STATUS) { + System_Status = status; + result = 0; + } + + return result; + } + +uint16_t Device_Vendor_Identifier( + void) +{ + return BACNET_VENDOR_ID; + } + +BACNET_SEGMENTATION Device_Segmentation_Supported( + void) +{ + return SEGMENTATION_NONE; + } + +uint32_t Device_Database_Revision( + void) +{ + return Database_Revision; + } + +void Device_Inc_Database_Revision( + void) +{ + Database_Revision++; +} + /* Since many network clients depend on the object list */ /* for discovery, it must be consistent! */ unsigned Device_Object_List_Count( void) { unsigned count = 0; /* number of objects */ - unsigned index = 0; /* loop counter */ struct my_object_functions *pObject = NULL; /* initialize the default return values */ @@ -309,8 +501,7 @@ unsigned Device_Object_List_Count( if (pObject->Object_Count) { count += pObject->Object_Count(); } - index++; - pObject = &Object_Table[index]; + pObject++; } return count; @@ -324,7 +515,6 @@ bool Device_Object_List_Identifier( bool status = false; unsigned count = 0; unsigned object_index = 0; - unsigned index = 0; /* loop counter */ struct my_object_functions *pObject = NULL; /* array index zero is length - so invalid */ @@ -345,15 +535,14 @@ bool Device_Object_List_Identifier( break; } } - index++; - pObject = &Object_Table[index]; + pObject++; } return status; } bool Device_Valid_Object_Name( - const char *object_name, + BACNET_CHARACTER_STRING *object_name1, int *object_type, uint32_t * object_instance) { @@ -362,14 +551,17 @@ bool Device_Valid_Object_Name( uint32_t instance; unsigned max_objects = 0, i = 0; bool check_id = false; - char *name = NULL; + BACNET_CHARACTER_STRING object_name2; + struct my_object_functions *pObject = NULL; max_objects = Device_Object_List_Count(); for (i = 0; i < max_objects; i++) { check_id = Device_Object_List_Identifier(i, &type, &instance); if (check_id) { - name = Device_Valid_Object_Id(type, instance); - if (strcmp(name, object_name) == 0) { + pObject = Device_Objects_Find_Functions(type); + if ((pObject != NULL) && (pObject->Object_Name != NULL) && + (pObject->Object_Name(instance, &object_name2) && + characterstring_same(object_name1, &object_name2))) { found = true; if (object_type) { *object_type = type; @@ -385,179 +577,49 @@ bool Device_Valid_Object_Name( return found; } -/* returns the name or NULL if not found */ -char *Device_Valid_Object_Id( +bool Device_Valid_Object_Id( int object_type, uint32_t object_instance) { - char *name = NULL; /* return value */ - unsigned index = 0; /* loop counter */ + bool status = false; /* return value */ struct my_object_functions *pObject = NULL; - pObject = &Object_Table[0]; - while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { - if ((pObject->Object_Type == object_type) && (pObject->Object_Name)) { - name = pObject->Object_Name(object_instance); - break; - } - index++; - pObject = &Object_Table[index]; - } - - return name; -} - -unsigned Device_Count( - void) -{ - return 1; -} - -uint32_t Device_Index_To_Instance( - unsigned index) -{ - return Object_Instance_Number; -} - -char *Device_Name( - uint32_t object_instance) -{ - if (object_instance == Object_Instance_Number) { - return My_Object_Name; - } - - return NULL; -} - -bool Device_Reinitialize( - BACNET_REINITIALIZE_DEVICE_DATA * rd_data) -{ - bool status = false; - - if (characterstring_ansi_same(&rd_data->password, "filister")) { - Reinitialize_State = rd_data->state; - dcc_set_status_duration(COMMUNICATION_ENABLE, 0); - /* Note: you could use a mix of state - and password to multiple things */ - /* note: you probably want to restart *after* the - simple ack has been sent from the return handler - so just set a flag from here */ - status = true; - } else { - rd_data->error_class = ERROR_CLASS_SECURITY; - rd_data->error_code = ERROR_CODE_PASSWORD_FAILURE; + pObject = Device_Objects_Find_Functions(object_type); + if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) { + status = pObject->Object_Valid_Instance(object_instance); } return status; } -void Device_Init( - void) +bool Device_Object_Name_Copy( + int object_type, + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { - unsigned index = 0; /* loop counter */ struct my_object_functions *pObject = NULL; + bool found = false; + int type = 0; + uint32_t instance; + unsigned max_objects = 0, i = 0; + bool check_id = false; - Reinitialize_State = BACNET_REINIT_IDLE; - dcc_set_status_duration(COMMUNICATION_ENABLE, 0); - /* FIXME: Get the data from the eeprom */ - /* I2C_Read_Block(EEPROM_DEVICE_ADDRESS, - (char *)&Object_Instance_Number, - sizeof(Object_Instance_Number), - EEPROM_BACNET_ID_ADDR); */ - pObject = &Object_Table[0]; - while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { - if (pObject->Object_Init) { - pObject->Object_Init(); + max_objects = Device_Object_List_Count(); + for (i = 0; i < max_objects; i++) { + check_id = Device_Object_List_Identifier(i, &type, &instance); + if (check_id) { + pObject = Device_Objects_Find_Functions(type); + if ((pObject != NULL) && (pObject->Object_Name != NULL)) { + found = pObject->Object_Name(instance, object_name); + break; + } } - index++; - pObject = &Object_Table[index]; - } -} - -/* methods to manipulate the data */ -uint32_t Device_Object_Instance_Number( - void) -{ - return Object_Instance_Number; -} - -bool Device_Set_Object_Instance_Number( - uint32_t object_id) -{ - bool status = true; /* return value */ - - if (object_id <= BACNET_MAX_INSTANCE) { - Object_Instance_Number = object_id; - /* FIXME: Write the data to the eeprom */ - /* I2C_Write_Block( - EEPROM_DEVICE_ADDRESS, - (char *)&Object_Instance_Number, - sizeof(Object_Instance_Number), - EEPROM_BACNET_ID_ADDR); */ - } else - status = false; - - return status; -} - -bool Device_Valid_Object_Instance_Number( - uint32_t object_id) -{ - /* BACnet allows for a wildcard instance number */ - return ((Object_Instance_Number == object_id) || - (object_id == BACNET_MAX_INSTANCE)); -} - -BACNET_DEVICE_STATUS Device_System_Status( - void) -{ - return System_Status; -} - -int Device_Set_System_Status( - BACNET_DEVICE_STATUS status, - bool local) -{ - int result = 0; /*return value - 0 = ok, -1 = bad value, -2 = not allowed */ - - if (status < MAX_DEVICE_STATUS) { - System_Status = status; } - return result; + return found; } -uint16_t Device_Vendor_Identifier( - void) -{ - return BACNET_VENDOR_ID; -} - -uint8_t Device_Protocol_Version( - void) -{ - return BACNET_PROTOCOL_VERSION; -} - -uint8_t Device_Protocol_Revision( - void) -{ - return BACNET_PROTOCOL_REVISION; -} - -BACNET_SEGMENTATION Device_Segmentation_Supported( - void) -{ - return SEGMENTATION_NONE; -} - -uint32_t Device_Database_Revision( - void) -{ - return 0; -} - -/* return the length of the apdu encoded or -1 for error */ +/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */ int Device_Read_Property_Local( BACNET_READ_PROPERTY_DATA * rpdata) { @@ -569,18 +631,13 @@ int Device_Read_Property_Local( int object_type = 0; uint32_t instance = 0; unsigned count = 0; - BACNET_TIME local_time; - BACNET_DATE local_date; uint8_t *apdu = NULL; struct my_object_functions *pObject = NULL; - bool found = false; - if ((rpdata == NULL) || (rpdata->application_data == NULL) || + if ((rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } - /* requested instance may have been the wildcard instance */ - rpdata->object_instance = Object_Instance_Number; apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: @@ -588,19 +645,23 @@ int Device_Read_Property_Local( encode_application_object_id(&apdu[0], OBJECT_DEVICE, rpdata->object_instance); break; - case PROP_OBJECT_NAME: - characterstring_init_ansi(&char_string, My_Object_Name); - apdu_len = - encode_application_character_string(&apdu[0], &char_string); - break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE); break; + case PROP_OBJECT_NAME: + apdu_len = + encode_application_character_string(&apdu[0], &My_Object_Name); + break; case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, "BACnet Demo"); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; + case PROP_LOCATION: + characterstring_init_ansi(&char_string, "USA"); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; case PROP_SYSTEM_STATUS: apdu_len = encode_application_enumerated(&apdu[0], @@ -612,9 +673,7 @@ int Device_Read_Property_Local( encode_application_character_string(&apdu[0], &char_string); break; case PROP_VENDOR_IDENTIFIER: - apdu_len = - encode_application_unsigned(&apdu[0], - Device_Vendor_Identifier()); + apdu_len = encode_application_unsigned(&apdu[0], BACNET_VENDOR_ID); break; case PROP_MODEL_NAME: characterstring_init_ansi(&char_string, "GNU Demo"); @@ -631,20 +690,14 @@ int Device_Read_Property_Local( apdu_len = encode_application_character_string(&apdu[0], &char_string); break; - case PROP_LOCATION: - characterstring_init_ansi(&char_string, "USA"); - apdu_len = - encode_application_character_string(&apdu[0], &char_string); - break; case PROP_PROTOCOL_VERSION: apdu_len = - encode_application_unsigned(&apdu[0], - Device_Protocol_Version()); + encode_application_unsigned(&apdu[0], BACNET_PROTOCOL_VERSION); break; case PROP_PROTOCOL_REVISION: apdu_len = encode_application_unsigned(&apdu[0], - Device_Protocol_Revision()); + BACNET_PROTOCOL_REVISION); break; case PROP_PROTOCOL_SERVICES_SUPPORTED: /* Note: list of services that are executed, not initiated. */ @@ -652,7 +705,7 @@ int Device_Read_Property_Local( for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) { /* automatic lookup based on handlers set */ bitstring_set_bit(&bit_string, (uint8_t) i, - apdu_service_supported(i)); + apdu_service_supported((BACNET_SERVICES_SUPPORTED) i)); } apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; @@ -671,8 +724,7 @@ int Device_Read_Property_Local( if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) { bitstring_set_bit(&bit_string, pObject->Object_Type, true); } - i++; - pObject = &Object_Table[i]; + pObject++; } apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; @@ -687,10 +739,8 @@ int Device_Read_Property_Local( /* your maximum APDU size. */ else if (rpdata->array_index == BACNET_ARRAY_ALL) { for (i = 1; i <= count; i++) { - found = - Device_Object_List_Identifier(i, &object_type, - &instance); - if (found) { + if (Device_Object_List_Identifier(i, &object_type, + &instance)) { len = encode_application_object_id(&apdu[apdu_len], object_type, instance); @@ -756,31 +806,6 @@ int Device_Read_Property_Local( apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_master()); break; - case PROP_LOCAL_TIME: - /* FIXME: if you support time */ - local_time.hour = 0; - local_time.min = 0; - local_time.sec = 0; - local_time.hundredths = 0; - apdu_len = encode_application_time(&apdu[0], &local_time); - break; - case PROP_UTC_OFFSET: - /* Note: BACnet Time Zone is offset of local time and UTC, - rather than offset of GMT. It is expressed in minutes */ - apdu_len = encode_application_signed(&apdu[0], 5 * 60 /* EST */ ); - break; - case PROP_LOCAL_DATE: - /* FIXME: if you support date */ - local_date.year = 2006; /* AD */ - local_date.month = 4; /* Jan=1..Dec=12 */ - local_date.day = 11; /* 1..31 */ - local_date.wday = 0; /* 1=Mon..7=Sun */ - apdu_len = encode_application_date(&apdu[0], &local_date); - break; - case PROP_DAYLIGHT_SAVINGS_STATUS: - /* FIXME: if you support time/date */ - apdu_len = encode_application_boolean(&apdu[0], false); - break; case 9600: apdu_len = encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate()); @@ -805,15 +830,12 @@ int Device_Read_Property_Local( bool Device_Write_Property_Local( BACNET_WRITE_PROPERTY_DATA * wp_data) { - bool status = false; /* return value */ + bool status = false; /* return value - false=error */ int len = 0; + uint8_t encoding = 0; + size_t length = 0; BACNET_APPLICATION_DATA_VALUE value; - if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) { - wp_data->error_class = ERROR_CLASS_OBJECT; - wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT; - return false; - } /* decode the some of the request */ len = bacapp_decode_application_data(wp_data->application_data, @@ -873,29 +895,32 @@ bool Device_Write_Property_Local( break; case PROP_OBJECT_NAME: if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { - uint8_t encoding; - size_t len; - - encoding = - characterstring_encoding(&value.type.Character_String); - len = characterstring_length(&value.type.Character_String); - if (encoding == CHARACTER_ANSI_X34) { - if (len <= 20) { - /* FIXME: set the name */ - /* Display_Set_Name( - characterstring_value(&value.type.Character_String)); */ - /* FIXME: All the object names in a device must be unique. - Disallow setting the Device Object Name to any objects in - the device. */ + length = characterstring_length( + &value.type.Character_String); + if (length < characterstring_capacity(&My_Object_Name)) { + encoding = characterstring_encoding( + &value.type.Character_String); + if (encoding < MAX_CHARACTER_STRING_ENCODING) { + /* All the object names in a device must be unique. */ + if (Device_Valid_Object_Name( + &value.type.Character_String, + NULL, NULL)) { + status = false; + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_DUPLICATE_NAME; + } else { + Device_Set_Object_Name( + &value.type.Character_String); + } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = - ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; + ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = - ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; + ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; } } else { wp_data->error_class = ERROR_CLASS_PROPERTY; diff --git a/bacnet-stack/ports/at91sam7s/main.c b/bacnet-stack/ports/at91sam7s/main.c index 40336e5b..df2c5e02 100644 --- a/bacnet-stack/ports/at91sam7s/main.c +++ b/bacnet-stack/ports/at91sam7s/main.c @@ -143,7 +143,7 @@ static inline void bacnet_init( #endif Device_Set_Object_Instance_Number(22222); /* initialize objects */ - Device_Init(); + Device_Init(NULL); /* set up our confirmed service unrecognized service handler - required! */ apdu_set_unrecognized_service_handler_handler (handler_unrecognized_service); diff --git a/bacnet-stack/ports/atmega168/Makefile b/bacnet-stack/ports/atmega168/Makefile index 8a2a4486..fe109cb9 100644 --- a/bacnet-stack/ports/atmega168/Makefile +++ b/bacnet-stack/ports/atmega168/Makefile @@ -31,6 +31,8 @@ AVRDUDE_PORT = /dev/ttyUSB0 # Source locations BACNET_CORE = ../../src BACNET_INCLUDE = ../../include +BACNET_HANDLER = ../../demo/handler +BACNET_OBJECT = ../../demo/object BACNET_DEMO = ../../demo # local files for this project @@ -93,6 +95,8 @@ CORESRC = \ ## Include Directories INCLUDES = -I. -I$(BACNET_INCLUDE) +INCLUDES += -I$(BACNET_OBJECT) +INCLUDES += -I$(BACNET_HANDLER) # Source to Object conversion COBJ = $(CSRC:.c=.o) diff --git a/bacnet-stack/ports/atmega168/ai.h b/bacnet-stack/ports/atmega168/ai.h new file mode 100644 index 00000000..fec425f2 --- /dev/null +++ b/bacnet-stack/ports/atmega168/ai.h @@ -0,0 +1,99 @@ +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* 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 +#include +#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 diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/Makefile b/bacnet-stack/ports/bdk-atxx4-mstp/Makefile index 1df30eb8..066d267b 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/Makefile +++ b/bacnet-stack/ports/bdk-atxx4-mstp/Makefile @@ -45,6 +45,8 @@ AVRDUDE_PORT = usb # Source locations BACNET_CORE = ../../src BACNET_INCLUDE = ../../include +BACNET_HANDLER = ../../demo/handler +BACNET_OBJECT = ../../demo/object BACNET_DEMO = ../../demo # local files for this project @@ -65,6 +67,7 @@ CSRC = main.c \ dlmstp.c \ test.c \ bacnet.c \ + bname.c \ device.c \ ai.c \ av.c \ @@ -130,7 +133,7 @@ CORESRC = \ # $(BACNET_CORE)/address.c \ ## Include Directories -INCLUDES = -I. -I$(BACNET_INCLUDE) +INCLUDES = -I. -I$(BACNET_INCLUDE) -I$(BACNET_HANDLER) -I$(BACNET_OBJECT) # Source to Object conversion COBJ = $(CSRC:%.c=%.o) diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/ai.c b/bacnet-stack/ports/bdk-atxx4-mstp/ai.c index 10ad25e7..d17b34ec 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/ai.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/ai.c @@ -109,17 +109,19 @@ uint32_t Analog_Input_Index_To_Instance( return index; } -char *Analog_Input_Name( - uint32_t object_instance) +bool Analog_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32]; /* okay for single thread */ + bool status = false; if (object_instance < MAX_ANALOG_INPUTS) { sprintf(text_string, "AI-%lu", object_instance); - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } float Analog_Input_Present_Value( diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/av.c b/bacnet-stack/ports/bdk-atxx4-mstp/av.c index 5902abee..25897cc7 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/av.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/av.c @@ -175,19 +175,21 @@ bool Analog_Value_Present_Value_Set( } /* note: the object name must be unique within this device */ -char *Analog_Value_Name( - uint32_t object_instance) +bool Analog_Value_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32] = ""; /* okay for single thread */ unsigned index = 0; + bool status = false; index = Analog_Value_Instance_To_Index(object_instance); if (index < MAX_ANALOG_VALUES) { sprintf(text_string, "AV-%lu", object_instance); - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } /* return apdu len, or -1 on error */ diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bacnet.c b/bacnet-stack/ports/bdk-atxx4-mstp/bacnet.c index 08c0ff1e..b2dcee6a 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bacnet.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bacnet.c @@ -85,10 +85,10 @@ void bacnet_init( dlmstp_init(NULL); if (!seeprom_version_test()) { - /* invalid version data */ + /* do something when SEEPROM is invalid - i.e. init to defaults */ } /* initialize objects */ - Device_Init(); + Device_Init(NULL); /* set up our confirmed service unrecognized service handler - required! */ apdu_set_unrecognized_service_handler_handler diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bi.c b/bacnet-stack/ports/bdk-atxx4-mstp/bi.c index d2e59c4a..7fa4a972 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bi.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bi.c @@ -157,17 +157,19 @@ bool Binary_Input_Present_Value_Set( return false; } -char *Binary_Input_Name( - uint32_t object_instance) +bool Binary_Input_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32]; /* okay for single thread */ + bool status = false; if (object_instance < MAX_BINARY_INPUTS) { sprintf(text_string, "BI-%lu", object_instance); - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } /* return apdu length, or -1 on error */ diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bname.c b/bacnet-stack/ports/bdk-atxx4-mstp/bname.c new file mode 100644 index 00000000..fcadc71b --- /dev/null +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bname.c @@ -0,0 +1,275 @@ +/************************************************************************** +* +* Copyright (C) 2011 Steve Karg +* +* 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 +#include +#include +#include +#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); + } +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bname.h b/bacnet-stack/ports/bdk-atxx4-mstp/bname.h new file mode 100644 index 00000000..af070223 --- /dev/null +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bname.h @@ -0,0 +1,60 @@ +/************************************************************************** +* +* Copyright (C) 2010 Steve Karg +* +* 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 +#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 diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bo.c b/bacnet-stack/ports/bdk-atxx4-mstp/bo.c index a6c32465..2ec608c2 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bo.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bo.c @@ -229,17 +229,19 @@ bool Binary_Output_Out_Of_Service( } /* note: the object name must be unique within this device */ -char *Binary_Output_Name( - uint32_t object_instance) +bool Binary_Output_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { static char text_string[32]; /* okay for single thread */ + bool status = false; if (object_instance < MAX_BINARY_OUTPUTS) { sprintf(text_string, "BO-%lu", object_instance); - return text_string; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } /* return apdu len, or -1 on error */ diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/device.c b/bacnet-stack/ports/bdk-atxx4-mstp/device.c index 86205011..cd9e3bb0 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/device.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/device.c @@ -39,6 +39,7 @@ #include "nvdata.h" #include "stack.h" #include "handlers.h" +#include "bname.h" /* objects */ #include "device.h" #include "ai.h" @@ -66,24 +67,24 @@ static struct my_object_functions { { OBJECT_DEVICE, NULL, /* don't init - recursive! */ Device_Count, Device_Index_To_Instance, - Device_Valid_Object_Instance_Number, Device_Name, + Device_Valid_Object_Instance_Number, Device_Object_Name, Device_Read_Property_Local, Device_Write_Property_Local, Device_Property_Lists}, { OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, - Analog_Input_Name, Analog_Input_Read_Property, NULL, + Analog_Input_Object_Name, Analog_Input_Read_Property, NULL, Analog_Input_Property_Lists}, { OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, - Analog_Value_Name, Analog_Value_Read_Property, + Analog_Value_Object_Name, Analog_Value_Read_Property, Analog_Value_Write_Property, Analog_Value_Property_Lists}, { OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance, - Binary_Input_Name, Binary_Input_Read_Property, NULL, + Binary_Input_Object_Name, Binary_Input_Read_Property, NULL, Binary_Input_Property_Lists}, { OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, - Binary_Output_Name, Binary_Output_Read_Property, + Binary_Output_Object_Name, Binary_Output_Read_Property, Binary_Output_Write_Property, Binary_Output_Property_Lists}, { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL} }; @@ -94,7 +95,7 @@ static struct my_object_functions { into the read-property encoding. */ static uint32_t Object_Instance_Number; static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; - +static uint32_t Database_Revision; static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE; /* These three arrays are used by the ReadPropertyMultiple handler */ @@ -130,6 +131,9 @@ static const int Device_Properties_Optional[] = { }; static const int Device_Properties_Proprietary[] = { + 512, + 513, + 9600, -1 }; @@ -157,7 +161,6 @@ static int Read_Property_Common( { int apdu_len = BACNET_STATUS_ERROR; BACNET_CHARACTER_STRING char_string; - char *pString = ""; uint8_t *apdu = NULL; if ((rpdata->application_data == NULL) || @@ -178,9 +181,12 @@ static int Read_Property_Common( break; case PROP_OBJECT_NAME: if (pObject->Object_Name) { - pString = pObject->Object_Name(rpdata->object_instance); + (void)pObject->Object_Name( + rpdata->object_instance, + &char_string); + } else { + characterstring_init_ansi(&char_string, ""); } - characterstring_init_ansi(&char_string, pString); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; @@ -334,38 +340,30 @@ uint32_t Device_Index_To_Instance( return Object_Instance_Number; } -char *Device_Name( - uint32_t object_instance) +static char *Device_Name_Default(void) { - uint8_t encoding = 0; - uint8_t length = 0; - static char name[NV_EEPROM_DEVICE_NAME_SIZE + 1] = ""; - char *pName = NULL; + static char text_string[32]; /* okay for single thread */ + + sprintf(text_string, "DEVICE-%lu", Object_Instance_Number); + + return text_string; +} + +bool Device_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) +{ + bool status = false; if (object_instance == Object_Instance_Number) { - eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_ENCODING, &encoding, 1); - eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_LENGTH, &length, 1); - eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_0, (uint8_t *) & name, - NV_EEPROM_DEVICE_NAME_SIZE); - if ((encoding >= MAX_CHARACTER_STRING_ENCODING) || - (length > NV_EEPROM_DEVICE_NAME_SIZE) || (length < 1)) { - encoding = CHARACTER_ANSI_X34; - eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_ENCODING, &encoding, 1); - sprintf(name, "DEVICE-%lu", Object_Instance_Number); - eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_0, (uint8_t *) & name[0], - NV_EEPROM_DEVICE_NAME_SIZE); - length = strlen(name); - eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_LENGTH, &length, 1); - } - if (length < NV_EEPROM_DEVICE_NAME_SIZE) { - name[length] = 0; - } else { - name[NV_EEPROM_DEVICE_NAME_SIZE] = 0; - } - pName = &name[0]; + bacnet_name( + NV_EEPROM_DEVICE_NAME, + object_name, + Device_Name_Default()); + status = true; } - return pName; + return status; } bool Device_Reinitialize( @@ -397,10 +395,14 @@ BACNET_REINITIALIZED_STATE Device_Reinitialized_State( } void Device_Init( - void) + object_functions_t * object_table) { struct my_object_functions *pObject = NULL; + /* we don't use the object table passed in + since there is extra stuff we don't need in there. */ + (void)object_table; + /* our local object table */ pObject = &Object_Table[0]; while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { if (pObject->Object_Init) { @@ -418,7 +420,6 @@ void Device_Init( (uint8_t *) & Object_Instance_Number, sizeof(Object_Instance_Number)); } - (void) Device_Name(Object_Instance_Number); } /* methods to manipulate the data */ @@ -488,7 +489,13 @@ BACNET_SEGMENTATION Device_Segmentation_Supported( uint32_t Device_Database_Revision( void) { - return 0; + return Database_Revision; +} + +void Device_Inc_Database_Revision( + void) +{ + Database_Revision++; } /* Since many network clients depend on the object list */ @@ -546,7 +553,7 @@ bool Device_Object_List_Identifier( } bool Device_Valid_Object_Name( - const char *object_name, + BACNET_CHARACTER_STRING *object_name1, int *object_type, uint32_t * object_instance) { @@ -555,14 +562,17 @@ bool Device_Valid_Object_Name( uint32_t instance; unsigned max_objects = 0, i = 0; bool check_id = false; - char *name = NULL; + BACNET_CHARACTER_STRING object_name2; + struct my_object_functions *pObject = NULL; max_objects = Device_Object_List_Count(); for (i = 0; i < max_objects; i++) { check_id = Device_Object_List_Identifier(i, &type, &instance); if (check_id) { - name = Device_Valid_Object_Id(type, instance); - if (strcmp(name, object_name) == 0) { + pObject = Device_Objects_Find_Functions(type); + if ((pObject != NULL) && (pObject->Object_Name != NULL) && + (pObject->Object_Name(instance, &object_name2) && + characterstring_same(object_name1, &object_name2))) { found = true; if (object_type) { *object_type = type; @@ -578,20 +588,46 @@ bool Device_Valid_Object_Name( return found; } -/* returns the name or NULL if not found */ -char *Device_Valid_Object_Id( +bool Device_Valid_Object_Id( int object_type, uint32_t object_instance) { - char *name = NULL; /* return value */ + bool status = false; /* return value */ struct my_object_functions *pObject = NULL; - pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE) object_type); - if ((pObject) && (pObject->Object_Name)) { - name = pObject->Object_Name(object_instance); + pObject = Device_Objects_Find_Functions(object_type); + if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) { + status = pObject->Object_Valid_Instance(object_instance); } - return name; + return status; +} + +bool Device_Object_Name_Copy( + int object_type, + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) +{ + struct my_object_functions *pObject = NULL; + bool found = false; + int type = 0; + uint32_t instance; + unsigned max_objects = 0, i = 0; + bool check_id = false; + + max_objects = Device_Object_List_Count(); + for (i = 0; i < max_objects; i++) { + check_id = Device_Object_List_Identifier(i, &type, &instance); + if (check_id) { + pObject = Device_Objects_Find_Functions(type); + if ((pObject != NULL) && (pObject->Object_Name != NULL)) { + found = pObject->Object_Name(instance, object_name); + break; + } + } + } + + return found; } /* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */ @@ -616,7 +652,18 @@ int Device_Read_Property_Local( apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, "BACnet Development Kit"); + bacnet_name( + NV_EEPROM_DEVICE_DESCRIPTION, + &char_string, + "BACnet Development Kit"); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_LOCATION: + bacnet_name( + NV_EEPROM_DEVICE_LOCATION, + &char_string, + "default location"); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; @@ -672,7 +719,6 @@ int Device_Read_Property_Local( not a list of objects that this device can access */ bitstring_init(&bit_string); for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { - /* FIXME: if ReadProperty used an array of Functions... */ /* initialize all the object types to not-supported */ bitstring_set_bit(&bit_string, (uint8_t) i, false); } @@ -858,38 +904,35 @@ bool Device_Write_Property_Local( break; case PROP_OBJECT_NAME: if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { - size_t length = - characterstring_length(&value.type.Character_String); - if (length < 1) { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } else if (length < NV_EEPROM_DEVICE_NAME_SIZE) { - uint8_t encoding = - characterstring_encoding(&value.type.Character_String); - if (encoding < MAX_CHARACTER_STRING_ENCODING) { - char *pCharString; - uint8_t small_length; - eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_ENCODING, - &encoding, 1); - small_length = length; - eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_LENGTH, - &small_length, 1); - pCharString = - characterstring_value(&value.type. - Character_String); - eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_0, - (uint8_t *) pCharString, length); - status = true; - } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = - ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; - } - } else { - wp_data->error_class = ERROR_CLASS_PROPERTY; - wp_data->error_code = - ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; - } + status = bacnet_name_write( + NV_EEPROM_DEVICE_NAME, + &value.type.Character_String, + &wp_data->error_class, + &wp_data->error_code); + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_DESCRIPTION: + if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { + status = bacnet_name_write_other( + NV_EEPROM_DEVICE_DESCRIPTION, + &value.type.Character_String, + &wp_data->error_class, + &wp_data->error_code); + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_LOCATION: + if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { + status = bacnet_name_write_other( + NV_EEPROM_DEVICE_LOCATION, + &value.type.Character_String, + &wp_data->error_class, + &wp_data->error_code); } else { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h b/bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h index 9ae1fc06..872a7fdb 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h @@ -28,21 +28,8 @@ #include "seeprom.h" #include "eeprom.h" -/* data version - use to check valid version */ -#define SEEPROM_ID 0xBAC0 -#define SEEPROM_VERSION 0x0001 - -#define SEEPROM_BYTES_MAX (2*1024) - -/* list of SEEPROM addresses */ -/* note to developers: define each byte, - even if they are not used explicitly */ -#define NV_SEEPROM_TYPE_0 0 -#define NV_SEEPROM_TYPE_1 1 -#define NV_SEEPROM_VERSION_0 2 -#define NV_SEEPROM_VERSION_1 3 -/* --- */ -/* define the MAC, BAUD, MAX Master, Device Instance internal +/*=============== EEPROM ================*/ +/* define the MAC, BAUD, MAX Master, Device Instance internal so that bootloader *could* use them. */ /* note: MAC could come from DIP switch, or be in non-volatile memory */ #define NV_EEPROM_MAC 0 @@ -54,49 +41,44 @@ #define NV_EEPROM_DEVICE_1 4 #define NV_EEPROM_DEVICE_2 5 #define NV_EEPROM_DEVICE_3 6 -/* Device Name */ -#define NV_EEPROM_DEVICE_NAME_LENGTH 8 -#define NV_EEPROM_DEVICE_NAME_ENCODING 9 -#define NV_EEPROM_DEVICE_NAME_0 10 -#define NV_EEPROM_DEVICE_NAME_1 11 -#define NV_EEPROM_DEVICE_NAME_2 12 -#define NV_EEPROM_DEVICE_NAME_3 13 -#define NV_EEPROM_DEVICE_NAME_4 14 -#define NV_EEPROM_DEVICE_NAME_5 15 -#define NV_EEPROM_DEVICE_NAME_6 16 -#define NV_EEPROM_DEVICE_NAME_7 17 -#define NV_EEPROM_DEVICE_NAME_8 18 -#define NV_EEPROM_DEVICE_NAME_9 19 -#define NV_EEPROM_DEVICE_NAME_10 20 -#define NV_EEPROM_DEVICE_NAME_11 21 -#define NV_EEPROM_DEVICE_NAME_12 22 -#define NV_EEPROM_DEVICE_NAME_13 23 -#define NV_EEPROM_DEVICE_NAME_14 24 -#define NV_EEPROM_DEVICE_NAME_15 25 -#define NV_EEPROM_DEVICE_NAME_16 26 -#define NV_EEPROM_DEVICE_NAME_17 27 -#define NV_EEPROM_DEVICE_NAME_18 28 -#define NV_EEPROM_DEVICE_NAME_19 29 -#define NV_EEPROM_DEVICE_NAME_20 30 -#define NV_EEPROM_DEVICE_NAME_21 31 -#define NV_EEPROM_DEVICE_NAME_22 32 -#define NV_EEPROM_DEVICE_NAME_23 33 -#define NV_EEPROM_DEVICE_NAME_24 34 -#define NV_EEPROM_DEVICE_NAME_25 35 -#define NV_EEPROM_DEVICE_NAME_26 36 -#define NV_EEPROM_DEVICE_NAME_27 37 -#define NV_EEPROM_DEVICE_NAME_28 38 -#define NV_EEPROM_DEVICE_NAME_29 39 -#define NV_EEPROM_DEVICE_NAME_30 40 -#define NV_EEPROM_DEVICE_NAME_31 41 -#define NV_EEPROM_DEVICE_NAME_SIZE 32 + +/* EEPROM free space - 7..31 */ + +/* BACnet Names - 32 bytes of data each */ +#define NV_EEPROM_NAME_LENGTH(n) ((n)+0) +#define NV_EEPROM_NAME_ENCODING(n) ((n)+1) +#define NV_EEPROM_NAME_STRING(n) ((n)+2) +#define NV_EEPROM_NAME_SIZE 30 +#define NV_EEPROM_NAME_OFFSET (1+1+NV_EEPROM_NAME_SIZE) +/* Device Name - starting offset */ +#define NV_EEPROM_DEVICE_NAME 32 +/* Device Description - starting offset */ +#define NV_EEPROM_DEVICE_DESCRIPTION \ + (NV_EEPROM_DEVICE_NAME+NV_EEPROM_NAME_OFFSET) +/* Device Location - starting offset */ +#define NV_EEPROM_DEVICE_LOCATION \ + (NV_EEPROM_DEVICE_DESCRIPTION+NV_EEPROM_NAME_OFFSET) + +/* EEPROM free space 128..1024 */ /*=============== SEEPROM ================*/ -#define NV_SEEPROM_BINARY_OUTPUT_OFFSET 32 -#define NV_SEEPROM_BINARY_OUTPUT_0 10 -#define NV_SEEPROM_BINARY_OUTPUT(n,p) \ - (NV_SEEPROM_BINARY_OUTPUT_0 + \ - (NV_SEEPROM_BINARY_OUTPUT_OFFSET * (n)) + (p)) +/* data version - use to check valid version */ +#define SEEPROM_ID 0xBAC0 +#define SEEPROM_VERSION 0x0001 + +#define SEEPROM_BYTES_MAX (2*1024) + +/* list of SEEPROM addresses */ +/* note to developers: define each byte, + even if they are not used explicitly */ +#define NV_SEEPROM_TYPE_0 0 +#define NV_SEEPROM_TYPE_1 1 +#define NV_SEEPROM_VERSION_0 2 +#define NV_SEEPROM_VERSION_1 3 + +/* SEEPROM free space - 4..31 */ + +#define NV_SEEPROM_BINARY_OUTPUT_0 32 /* BO properties */ #define NV_SEEPROM_BO_POLARITY 0 #define NV_SEEPROM_BO_OUT_OF_SERVICE 1 @@ -116,8 +98,13 @@ #define NV_SEEPROM_BO_PRIORITY_ARRAY_14 15 #define NV_SEEPROM_BO_PRIORITY_ARRAY_15 16 #define NV_SEEPROM_BO_PRIORITY_ARRAY_16 17 +/* formula for paramters */ +#define NV_SEEPROM_BINARY_OUTPUT_SIZE 18 +#define NV_SEEPROM_BINARY_OUTPUT(n,p) \ + (NV_SEEPROM_BINARY_OUTPUT_0 + \ + (NV_SEEPROM_BINARY_OUTPUT_SIZE * (n)) + (p)) - +/* SEEPROM free space - depends on number of BO */ #ifdef __cplusplus extern "C" { diff --git a/bacnet-stack/ports/stm32f10x/bo.c b/bacnet-stack/ports/stm32f10x/bo.c index e4431569..4b2489f2 100644 --- a/bacnet-stack/ports/stm32f10x/bo.c +++ b/bacnet-stack/ports/stm32f10x/bo.c @@ -220,17 +220,19 @@ bool Binary_Output_Out_Of_Service( } /* note: the object name must be unique within this device */ -char *Binary_Output_Name( - uint32_t object_instance) +bool Binary_Output_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { - static char text_string[32]; /* okay for single thread */ + static char text_string[16] = "BO-0"; /* okay for single thread */ + bool status = false; if (object_instance < MAX_BINARY_OUTPUTS) { - sprintf(text_string, "BO-%lu", object_instance); - return text_string; + text_string[3] = '0' + (uint8_t) object_instance; + status = characterstring_init_ansi(object_name, text_string); } - return NULL; + return status; } /* return apdu len, or -1 on error */ diff --git a/bacnet-stack/ports/stm32f10x/device.c b/bacnet-stack/ports/stm32f10x/device.c index 83416674..13903509 100644 --- a/bacnet-stack/ports/stm32f10x/device.c +++ b/bacnet-stack/ports/stm32f10x/device.c @@ -61,12 +61,12 @@ static struct my_object_functions { { OBJECT_DEVICE, NULL, /* don't init - recursive! */ Device_Count, Device_Index_To_Instance, - Device_Valid_Object_Instance_Number, Device_Name, + Device_Valid_Object_Instance_Number, Device_Object_Name, Device_Read_Property_Local, Device_Write_Property_Local, Device_Property_Lists}, { OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, - Binary_Output_Name, Binary_Output_Read_Property, + Binary_Output_Object_Name, Binary_Output_Read_Property, Binary_Output_Write_Property, Binary_Output_Property_Lists}, { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL} }; @@ -162,9 +162,12 @@ static int Read_Property_Common( break; case PROP_OBJECT_NAME: if (pObject->Object_Name) { - pString = pObject->Object_Name(rpdata->object_instance); + (void)pObject->Object_Name( + rpdata->object_instance, + &char_string); + } else { + characterstring_init_ansi(&char_string, ""); } - characterstring_init_ansi(&char_string, pString); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; @@ -318,10 +321,17 @@ uint32_t Device_Index_To_Instance( return Object_Instance_Number; } -char *Device_Name( - uint32_t object_instance) +bool Device_Object_Name( + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) { - return characterstring_value(&My_Object_Name); + bool status = false; + + if (object_instance == Object_Instance_Number) { + status = characterstring_copy(object_name, &My_Object_Name); + } + + return status; } bool Device_Reinitialize( @@ -494,7 +504,7 @@ bool Device_Object_List_Identifier( } bool Device_Valid_Object_Name( - const char *object_name, + BACNET_CHARACTER_STRING *object_name1, int *object_type, uint32_t * object_instance) { @@ -503,14 +513,17 @@ bool Device_Valid_Object_Name( uint32_t instance; unsigned max_objects = 0, i = 0; bool check_id = false; - char *name = NULL; + BACNET_CHARACTER_STRING object_name2; + struct my_object_functions *pObject = NULL; max_objects = Device_Object_List_Count(); for (i = 0; i < max_objects; i++) { check_id = Device_Object_List_Identifier(i, &type, &instance); if (check_id) { - name = Device_Valid_Object_Id(type, instance); - if (strcmp(name, object_name) == 0) { + pObject = Device_Objects_Find_Functions(type); + if ((pObject != NULL) && (pObject->Object_Name != NULL) && + (pObject->Object_Name(instance, &object_name2) && + characterstring_same(object_name1, &object_name2))) { found = true; if (object_type) { *object_type = type; @@ -526,20 +539,46 @@ bool Device_Valid_Object_Name( return found; } -/* returns the name or NULL if not found */ -char *Device_Valid_Object_Id( +bool Device_Valid_Object_Id( int object_type, uint32_t object_instance) { - char *name = NULL; /* return value */ + bool status = false; /* return value */ struct my_object_functions *pObject = NULL; - pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE) object_type); - if ((pObject) && (pObject->Object_Name)) { - name = pObject->Object_Name(object_instance); + pObject = Device_Objects_Find_Functions(object_type); + if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) { + status = pObject->Object_Valid_Instance(object_instance); } - return name; + return status; +} + +bool Device_Object_Name_Copy( + int object_type, + uint32_t object_instance, + BACNET_CHARACTER_STRING *object_name) +{ + struct my_object_functions *pObject = NULL; + bool found = false; + int type = 0; + uint32_t instance; + unsigned max_objects = 0, i = 0; + bool check_id = false; + + max_objects = Device_Object_List_Count(); + for (i = 0; i < max_objects; i++) { + check_id = Device_Object_List_Identifier(i, &type, &instance); + if (check_id) { + pObject = Device_Objects_Find_Functions(type); + if ((pObject != NULL) && (pObject->Object_Name != NULL)) { + found = pObject->Object_Name(instance, object_name); + break; + } + } + } + + return found; } /* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */ diff --git a/bacnet-stack/src/bacstr.c b/bacnet-stack/src/bacstr.c index 8988491c..83b0b0fc 100644 --- a/bacnet-stack/src/bacstr.c +++ b/bacnet-stack/src/bacstr.c @@ -484,12 +484,118 @@ bool characterstring_printable( break; } } + } else { + status = true; } } 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 initialize by using value=NULL */ bool octetstring_init( diff --git a/bacnet-stack/src/whohas.c b/bacnet-stack/src/whohas.c index fbc8880a..31487955 100644 --- a/bacnet-stack/src/whohas.c +++ b/bacnet-stack/src/whohas.c @@ -63,7 +63,7 @@ int whohas_encode_apdu( encode_context_unsigned(&apdu[apdu_len], 1, data->high_limit); apdu_len += len; } - if (data->object_name) { + if (data->is_object_name) { len = encode_context_character_string(&apdu[apdu_len], 3, &data->object.name); @@ -115,7 +115,7 @@ int whohas_decode_service_request( } /* object id */ if (decode_is_context_tag(&apdu[len], 2)) { - data->object_name = false; + data->is_object_name = false; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); @@ -126,7 +126,7 @@ int whohas_decode_service_request( } /* object name */ else if (decode_is_context_tag(&apdu[len], 3)) { - data->object_name = true; + data->is_object_name = true; len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value); @@ -186,9 +186,9 @@ void testWhoHasData( ct_test(pTest, len != -1); 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.object_name == data->object_name); + ct_test(pTest, test_data.is_object_name == data->is_object_name); /* Object ID */ - if (data->object_name == false) { + if (data->is_object_name == false) { ct_test(pTest, test_data.object.identifier.type == data->object.identifier.type); ct_test(pTest, @@ -209,7 +209,7 @@ void testWhoHas( data.low_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.instance = 1; testWhoHasData(pTest, &data); @@ -218,7 +218,7 @@ void testWhoHas( data.low_limit += (BACNET_MAX_INSTANCE / 4)) { for (data.high_limit = 0; data.high_limit <= BACNET_MAX_INSTANCE; data.high_limit += (BACNET_MAX_INSTANCE / 4)) { - data.object_name = false; + data.is_object_name = false; for (data.object.identifier.type = OBJECT_ANALOG_INPUT; data.object.identifier.type < MAX_BACNET_OBJECT_TYPE; data.object.identifier.type++) { @@ -228,7 +228,7 @@ void testWhoHas( testWhoHasData(pTest, &data); } } - data.object_name = true; + data.is_object_name = true; characterstring_init_ansi(&data.object.name, "patricia"); testWhoHasData(pTest, &data); }