/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA * rpdata) { int apdu_len = 0; /* return value */ int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string = { 0 }; BACNET_CHARACTER_STRING char_string = { 0 }; unsigned i = 0; int object_type = 0; uint32_t instance = 0; unsigned count = 0; uint8_t *apdu = NULL; struct my_object_functions *pObject = NULL; if ((rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch ((int) rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], rpdata->object_type, rpdata->object_instance); break; case PROP_OBJECT_NAME: Device_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], rpdata->object_type); break; case PROP_DESCRIPTION: bacnet_name(NVM_DEVICE_DESCRIPTION, &char_string, "default description"); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_LOCATION: bacnet_name(NVM_DEVICE_LOCATION, &char_string, "default location"); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_SYSTEM_STATUS: apdu_len = encode_application_enumerated(&apdu[0], Device_System_Status()); break; case PROP_VENDOR_NAME: characterstring_init_ansi(&char_string, Device_Vendor_Name()); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_VENDOR_IDENTIFIER: apdu_len = encode_application_unsigned(&apdu[0], BACNET_VENDOR_ID); break; case PROP_MODEL_NAME: characterstring_init_ansi(&char_string, Device_Model_Name()); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_FIRMWARE_REVISION: characterstring_init_ansi(&char_string, Device_Firmware_Revision()); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_APPLICATION_SOFTWARE_VERSION: characterstring_init_ansi(&char_string, Device_Application_Software_Version()); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_PROTOCOL_VERSION: apdu_len = encode_application_unsigned(&apdu[0], BACNET_PROTOCOL_VERSION); break; case PROP_PROTOCOL_REVISION: apdu_len = encode_application_unsigned(&apdu[0], BACNET_PROTOCOL_REVISION); break; case PROP_PROTOCOL_SERVICES_SUPPORTED: /* Note: list of services that are executed, not initiated. */ bitstring_init(&bit_string); for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) { /* automatic lookup based on handlers set */ bitstring_set_bit(&bit_string, (uint8_t) i, apdu_service_supported((BACNET_SERVICES_SUPPORTED) i)); } apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: /* Note: this is the list of objects that can be in this device, not a list of objects that this device can access */ bitstring_init(&bit_string); for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { /* initialize all the object types to not-supported */ bitstring_set_bit(&bit_string, (uint8_t) i, false); } /* set the object types with objects to supported */ i = 0; pObject = &Object_Table[i]; while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) { bitstring_set_bit(&bit_string, pObject->Object_Type, true); } pObject++; } apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); /* Array element zero is the number of objects in the list */ if (rpdata->array_index == 0) apdu_len = encode_application_unsigned(&apdu[0], count); /* if no index was specified, then try to encode the entire list */ /* into one packet. Note that more than likely you will have */ /* to return an error if the number of encoded objects exceeds */ /* your maximum APDU size. */ else if (rpdata->array_index == BACNET_ARRAY_ALL) { for (i = 1; i <= count; i++) { if (Device_Object_List_Identifier(i, &object_type, &instance)) { len = encode_application_object_id(&apdu[apdu_len], object_type, instance); apdu_len += len; /* assume next one is the same size as this one */ /* can we all fit into the APDU? */ if ((apdu_len + len) >= MAX_APDU) { /* Abort response */ rpdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; apdu_len = BACNET_STATUS_ABORT; break; } } else { /* error: internal error? */ rpdata->error_class = ERROR_CLASS_SERVICES; rpdata->error_code = ERROR_CODE_OTHER; apdu_len = BACNET_STATUS_ERROR; break; } } } else { if (Device_Object_List_Identifier(rpdata->array_index, &object_type, &instance)) apdu_len = encode_application_object_id(&apdu[0], object_type, instance); else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: apdu_len = encode_application_unsigned(&apdu[0], MAX_APDU); break; case PROP_SEGMENTATION_SUPPORTED: apdu_len = encode_application_enumerated(&apdu[0], Device_Segmentation_Supported()); break; case PROP_APDU_TIMEOUT: apdu_len = encode_application_unsigned(&apdu[0], apdu_timeout()); break; case PROP_NUMBER_OF_APDU_RETRIES: apdu_len = encode_application_unsigned(&apdu[0], apdu_retries()); break; case PROP_DEVICE_ADDRESS_BINDING: /* FIXME: encode the list here, if it exists */ break; case PROP_DATABASE_REVISION: apdu_len = encode_application_unsigned(&apdu[0], Device_Database_Revision()); break; case PROP_MAX_INFO_FRAMES: apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_info_frames()); break; case PROP_MAX_MASTER: apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_master()); break; case 512: apdu_len = encode_application_unsigned(&apdu[0], stack_size()); break; case 513: apdu_len = encode_application_unsigned(&apdu[0], stack_unused()); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_OBJECT_LIST) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/* return the length of the apdu encoded or -1 for error */ int Device_Encode_Property_APDU( uint8_t * apdu, uint32_t object_instance, BACNET_PROPERTY_ID property, int32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) { int apdu_len = 0; /* return value */ int len = 0; /* apdu len intermediate value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; unsigned i = 0; int object_type = 0; uint32_t instance = 0; unsigned count = 0; object_instance = object_instance; /* FIXME: change the hardcoded names to suit your application */ switch (property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_DEVICE, Object_Instance_Number); break; case PROP_OBJECT_NAME: characterstring_init_ansi(&char_string, 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_SYSTEM_STATUS: apdu_len = encode_application_enumerated(&apdu[0], System_Status); break; case PROP_VENDOR_NAME: characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_VENDOR_IDENTIFIER: apdu_len = encode_application_unsigned(&apdu[0], Device_Vendor_Identifier()); break; case PROP_MODEL_NAME: characterstring_init_ansi(&char_string, "GNU Demo"); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_FIRMWARE_REVISION: characterstring_init_ansi(&char_string, BACNET_VERSION_TEXT); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_APPLICATION_SOFTWARE_VERSION: characterstring_init_ansi(&char_string, "1.0"); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_PROTOCOL_VERSION: apdu_len = encode_application_unsigned(&apdu[0], 1); break; case PROP_PROTOCOL_REVISION: apdu_len = encode_application_unsigned(&apdu[0], 5); break; case PROP_PROTOCOL_SERVICES_SUPPORTED: /* Note: list of services that are executed, not initiated. */ bitstring_init(&bit_string); for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) { /* automatic lookup based on handlers set */ bitstring_set_bit(&bit_string, (uint8_t) i, apdu_service_supported((BACNET_SERVICES_SUPPORTED) i)); } apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: /* Note: this is the list of objects that can be in this device, not a list of objects that this device can access */ bitstring_init(&bit_string); /* must have the bit string as big as it can be */ for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { /* initialize all the object types to not-supported */ bitstring_set_bit(&bit_string, (uint8_t) i, false); } /* FIXME: indicate the objects that YOU support */ bitstring_set_bit(&bit_string, OBJECT_DEVICE, true); bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true); bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_OBJECT_LIST: count = Device_Object_List_Count(); /* Array element zero is the number of objects in the list */ if (array_index == 0) apdu_len = encode_application_unsigned(&apdu[0], count); /* if no index was specified, then try to encode the entire list */ /* into one packet. Note that more than likely you will have */ /* to return an error if the number of encoded objects exceeds */ /* your maximum APDU size. */ else if (array_index == BACNET_ARRAY_ALL) { for (i = 1; i <= count; i++) { Device_Object_List_Identifier(i, &object_type, &instance); len = encode_application_object_id(&apdu[apdu_len], object_type, instance); apdu_len += len; /* assume next one is the same size as this one */ /* can we all fit into the APDU? */ if ((apdu_len + len) >= MAX_APDU) { *error_class = ERROR_CLASS_SERVICES; *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; apdu_len = -1; break; } } } else { if (Device_Object_List_Identifier(array_index, &object_type, &instance)) apdu_len = encode_application_object_id(&apdu[0], object_type, instance); else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = -1; } } break; case PROP_MAX_APDU_LENGTH_ACCEPTED: apdu_len = encode_application_unsigned(&apdu[0], MAX_APDU); break; case PROP_SEGMENTATION_SUPPORTED: apdu_len = encode_application_enumerated(&apdu[0], SEGMENTATION_NONE); break; case PROP_APDU_TIMEOUT: apdu_len = encode_application_unsigned(&apdu[0], 60000); break; case PROP_NUMBER_OF_APDU_RETRIES: apdu_len = encode_application_unsigned(&apdu[0], 0); break; case PROP_DEVICE_ADDRESS_BINDING: /* FIXME: encode the list here, if it exists */ break; case PROP_DATABASE_REVISION: apdu_len = encode_application_unsigned(&apdu[0], 0); break; case PROP_MAX_INFO_FRAMES: apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_info_frames()); break; case PROP_MAX_MASTER: apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_master()); break; case 9600: apdu_len = encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate()); break; case 512: apdu_len = encode_application_unsigned(&apdu[0], stack_size()); break; case 513: apdu_len = encode_application_unsigned(&apdu[0], stack_unused()); break; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } return apdu_len; }