/* returns true if value has changed */ bool Binary_Input_Encode_Value_List( uint32_t object_instance, BACNET_PROPERTY_VALUE * value_list) { bool status = false; if (value_list) { value_list->propertyIdentifier = PROP_PRESENT_VALUE; value_list->propertyArrayIndex = BACNET_ARRAY_ALL; value_list->value.context_specific = false; value_list->value.tag = BACNET_APPLICATION_TAG_ENUMERATED; value_list->value.type.Enumerated = Binary_Input_Present_Value(object_instance); value_list->priority = BACNET_NO_PRIORITY; value_list = value_list->next; } if (value_list) { value_list->propertyIdentifier = PROP_STATUS_FLAGS; value_list->propertyArrayIndex = BACNET_ARRAY_ALL; value_list->value.context_specific = false; value_list->value.tag = BACNET_APPLICATION_TAG_BIT_STRING; bitstring_init(&value_list->value.type.Bit_String); bitstring_set_bit(&value_list->value.type.Bit_String, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&value_list->value.type.Bit_String, STATUS_FLAG_FAULT, false); bitstring_set_bit(&value_list->value.type.Bit_String, STATUS_FLAG_OVERRIDDEN, false); if (Binary_Input_Out_Of_Service(object_instance)) { bitstring_set_bit(&value_list->value.type.Bit_String, STATUS_FLAG_OUT_OF_SERVICE, true); } else { bitstring_set_bit(&value_list->value.type.Bit_String, STATUS_FLAG_OUT_OF_SERVICE, false); } value_list->priority = BACNET_NO_PRIORITY; } status = Binary_Input_Change_Of_Value(object_instance); return status; }
int Analog_Value_Alarm_Summary( unsigned index, BACNET_GET_ALARM_SUMMARY_DATA * getalarm_data) { /* check index */ if (index < MAX_ANALOG_VALUES) { /* Event_State is not equal to NORMAL and Notify_Type property value is ALARM */ if ((AV_Descr[index].Event_State != EVENT_STATE_NORMAL) && (AV_Descr[index].Notify_Type == NOTIFY_ALARM)) { /* Object Identifier */ getalarm_data->objectIdentifier.type = OBJECT_ANALOG_VALUE; getalarm_data->objectIdentifier.instance = Analog_Value_Index_To_Instance(index); /* Alarm State */ getalarm_data->alarmState = AV_Descr[index].Event_State; /* Acknowledged Transitions */ bitstring_init(&getalarm_data->acknowledgedTransitions); bitstring_set_bit(&getalarm_data->acknowledgedTransitions, TRANSITION_TO_OFFNORMAL, AV_Descr[index].Acked_Transitions[TRANSITION_TO_OFFNORMAL]. bIsAcked); bitstring_set_bit(&getalarm_data->acknowledgedTransitions, TRANSITION_TO_FAULT, AV_Descr[index]. Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked); bitstring_set_bit(&getalarm_data->acknowledgedTransitions, TRANSITION_TO_NORMAL, AV_Descr[index]. Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked); return 1; /* active alarm */ } else return 0; /* no active alarm at this index */ } else return -1; /* end of list */ }
int Schedule_Read_Property(BACNET_READ_PROPERTY_DATA * rpdata) { int apdu_len = 0; unsigned object_index = 0; SCHEDULE_DESCR *CurrentSC; uint8_t *apdu = NULL; BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; int i; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } object_index = Schedule_Instance_To_Index(rpdata->object_instance); if (object_index < MAX_SCHEDULES) CurrentSC = &Schedule_Descr[object_index]; else return BACNET_STATUS_ERROR; apdu = rpdata->application_data; switch ((int) rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_SCHEDULE, rpdata->object_instance); break; case PROP_OBJECT_NAME: Schedule_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_SCHEDULE); break; case PROP_PRESENT_VALUE: apdu_len = bacapp_encode_data(&apdu[0], CurrentSC->Present_Value); break; case PROP_EFFECTIVE_PERIOD: apdu_len = encode_bacnet_date(&apdu[0], &CurrentSC->Start_Date); apdu_len += encode_bacnet_date(&apdu[apdu_len], &CurrentSC->End_Date); break; case PROP_WEEKLY_SCHEDULE: if (rpdata->array_index == 0) /* count, always 7 */ apdu_len = encode_application_unsigned(&apdu[0], 7); else if (rpdata->array_index == BACNET_ARRAY_ALL) { /* full array */ int day; for (day = 0; day < 7; day++) { apdu_len += encode_opening_tag(&apdu[apdu_len], 0); for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count; i++) { apdu_len += bacapp_encode_time_value(&apdu[apdu_len], &CurrentSC->Weekly_Schedule[day].Time_Values[i]); } apdu_len += encode_closing_tag(&apdu[apdu_len], 0); } } else if (rpdata->array_index <= 7) { /* some array element */ int day = rpdata->array_index - 1; apdu_len += encode_opening_tag(&apdu[apdu_len], 0); for (i = 0; i < CurrentSC->Weekly_Schedule[day].TV_Count; i++) { apdu_len += bacapp_encode_time_value(&apdu[apdu_len], &CurrentSC->Weekly_Schedule[day].Time_Values[i]); } apdu_len += encode_closing_tag(&apdu[apdu_len], 0); } else { /* out of bounds */ rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } break; case PROP_SCHEDULE_DEFAULT: apdu_len = bacapp_encode_data(&apdu[0], &CurrentSC->Schedule_Default); break; case PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES: for (i = 0; i < CurrentSC->obj_prop_ref_cnt; i++) { apdu_len += bacapp_encode_device_obj_property_ref(&apdu[apdu_len], &CurrentSC->Object_Property_References[i]); } break; case PROP_PRIORITY_FOR_WRITING: apdu_len = encode_application_unsigned(&apdu[0], CurrentSC->Priority_For_Writing); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_RELIABILITY: apdu_len = encode_application_enumerated(&apdu[0], RELIABILITY_NO_FAULT_DETECTED); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], false); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } if ((apdu_len >= 0) && (rpdata->object_property != PROP_WEEKLY_SCHEDULE) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/* return apdu len, or -1 on error */ int Binary_Value_Encode_Property_APDU( uint8_t * apdu, uint32_t object_instance, BACNET_PROPERTY_ID property, uint32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) { int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; BACNET_BINARY_PV present_value = BINARY_INACTIVE; BACNET_POLARITY polarity = POLARITY_NORMAL; switch (property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE, object_instance); break; /* note: Name and Description don't have to be the same. You could make Description writable and different */ case PROP_OBJECT_NAME: characterstring_init_ansi(&char_string, Binary_Value_Name(object_instance)); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE); break; case PROP_PRESENT_VALUE: present_value = Binary_Value_Present_Value(object_instance); apdu_len = encode_application_enumerated(&apdu[0], present_value); break; case PROP_STATUS_FLAGS: /* note: see the details in the standard on how to use these */ bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: /* note: see the details in the standard on how to use this */ apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], false); break; case PROP_POLARITY: /* FIXME: figure out the polarity */ apdu_len = encode_application_enumerated(&apdu[0], polarity); break; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = -1; } return apdu_len; }
/* assumption - object already exists, and has been bounds checked */ int Binary_Input_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 */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; BACNET_POLARITY polarity = POLARITY_NORMAL; BACNET_BINARY_PV value = BINARY_INACTIVE; (void) array_index; Binary_Input_Initialize(); switch (property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT, object_instance); break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: /* note: object name must be unique in our device */ characterstring_init_ansi(&char_string, Binary_Input_Name(object_instance)); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_INPUT); break; case PROP_PRESENT_VALUE: value = Binary_Input_Present_Value(object_instance); apdu_len = encode_application_enumerated(&apdu[0], value); break; case PROP_STATUS_FLAGS: /* note: see the details in the standard on how to use these */ bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: /* note: see the details in the standard on how to use this */ apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], false); break; case PROP_POLARITY: apdu_len = encode_application_enumerated(&apdu[0], polarity); break; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } return apdu_len; }
int Notification_Class_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { NOTIFICATION_CLASS_INFO *CurrentNotify; BACNET_CHARACTER_STRING char_string; BACNET_OCTET_STRING octet_string; BACNET_BIT_STRING bit_string; uint8_t *apdu = NULL; uint8_t u8Val; int idx; int apdu_len = 0; /* return value */ if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; CurrentNotify = &NC_Info[Notification_Class_Instance_To_Index(rpdata-> object_instance)]; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_NOTIFICATION_CLASS, rpdata->object_instance); break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: Notification_Class_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_NOTIFICATION_CLASS); break; case PROP_NOTIFICATION_CLASS: apdu_len += encode_application_unsigned(&apdu[0], rpdata->object_instance); break; case PROP_PRIORITY: if (rpdata->array_index == 0) apdu_len += encode_application_unsigned(&apdu[0], 3); else { if (rpdata->array_index == BACNET_ARRAY_ALL) { apdu_len += encode_application_unsigned(&apdu[apdu_len], CurrentNotify->Priority[TRANSITION_TO_OFFNORMAL]); apdu_len += encode_application_unsigned(&apdu[apdu_len], CurrentNotify->Priority[TRANSITION_TO_FAULT]); apdu_len += encode_application_unsigned(&apdu[apdu_len], CurrentNotify->Priority[TRANSITION_TO_NORMAL]); } else if (rpdata->array_index <= MAX_BACNET_EVENT_TRANSITION) { apdu_len += encode_application_unsigned(&apdu[apdu_len], CurrentNotify->Priority[rpdata->array_index - 1]); } else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = -1; } } break; case PROP_ACK_REQUIRED: u8Val = CurrentNotify->Ack_Required; bitstring_init(&bit_string); bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, (u8Val & TRANSITION_TO_OFFNORMAL_MASKED) ? true : false); bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, (u8Val & TRANSITION_TO_FAULT_MASKED) ? true : false); bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, (u8Val & TRANSITION_TO_NORMAL_MASKED) ? true : false); /* encode bitstring */ apdu_len += encode_application_bitstring(&apdu[apdu_len], &bit_string); break; case PROP_RECIPIENT_LIST: /* encode all entry of Recipient_List */ for (idx = 0; idx < NC_MAX_RECIPIENTS; idx++) { BACNET_DESTINATION *RecipientEntry; int i = 0; /* get pointer of current element for Recipient_List - easier for use */ RecipientEntry = &CurrentNotify->Recipient_List[idx]; if (RecipientEntry->Recipient.RecipientType != RECIPIENT_TYPE_NOTINITIALIZED) { /* Valid Days - BACnetDaysOfWeek - [bitstring] monday-sunday */ u8Val = 0x01; bitstring_init(&bit_string); for (i = 0; i < MAX_BACNET_DAYS_OF_WEEK; i++) { if (RecipientEntry->ValidDays & u8Val) bitstring_set_bit(&bit_string, i, true); else bitstring_set_bit(&bit_string, i, false); u8Val <<= 1; /* next day */ } apdu_len += encode_application_bitstring(&apdu[apdu_len], &bit_string); /* From Time */ apdu_len += encode_application_time(&apdu[apdu_len], &RecipientEntry->FromTime); /* To Time */ apdu_len += encode_application_time(&apdu[apdu_len], &RecipientEntry->ToTime); /* BACnetRecipient ::= CHOICE { device [0] BACnetObjectIdentifier, address [1] BACnetAddress } */ /* CHOICE - device [0] BACnetObjectIdentifier */ if (RecipientEntry->Recipient.RecipientType == RECIPIENT_TYPE_DEVICE) { apdu_len += encode_context_object_id(&apdu[apdu_len], 0, OBJECT_DEVICE, RecipientEntry->Recipient._.DeviceIdentifier); } /* CHOICE - address [1] BACnetAddress */ else if (RecipientEntry->Recipient.RecipientType == RECIPIENT_TYPE_ADDRESS) { /* opening tag 1 */ apdu_len += encode_opening_tag(&apdu[apdu_len], 1); /* network-number Unsigned16, */ apdu_len += encode_application_unsigned(&apdu[apdu_len], RecipientEntry->Recipient._.Address.net); /* mac-address OCTET STRING */ if (RecipientEntry->Recipient._.Address.net) { octetstring_init(&octet_string, RecipientEntry->Recipient._.Address.adr, RecipientEntry->Recipient._.Address.len); } else { octetstring_init(&octet_string, RecipientEntry->Recipient._.Address.mac, RecipientEntry->Recipient._.Address.mac_len); } apdu_len += encode_application_octet_string(&apdu[apdu_len], &octet_string); /* closing tag 1 */ apdu_len += encode_closing_tag(&apdu[apdu_len], 1); } else {; } /* shouldn't happen */ /* Process Identifier - Unsigned32 */ apdu_len += encode_application_unsigned(&apdu[apdu_len], RecipientEntry->ProcessIdentifier); /* Issue Confirmed Notifications - boolean */ apdu_len += encode_application_boolean(&apdu[apdu_len], RecipientEntry->ConfirmedNotify); /* Transitions - BACnet Event Transition Bits [bitstring] */ u8Val = RecipientEntry->Transitions; bitstring_init(&bit_string); bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, (u8Val & TRANSITION_TO_OFFNORMAL_MASKED) ? true : false); bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, (u8Val & TRANSITION_TO_FAULT_MASKED) ? true : false); bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, (u8Val & TRANSITION_TO_NORMAL_MASKED) ? true : false); apdu_len += encode_application_bitstring(&apdu[apdu_len], &bit_string); } } break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY) && (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 or -2 for abort message */ 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; 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, 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_DESCRIPTION: characterstring_init_ansi(&char_string, Description); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_SYSTEM_STATUS: apdu_len = encode_application_enumerated(&apdu[0], System_Status); break; case PROP_VENDOR_NAME: characterstring_init_ansi(&char_string, Vendor_Name); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_VENDOR_IDENTIFIER: apdu_len = encode_application_unsigned(&apdu[0], Vendor_Identifier); break; case PROP_MODEL_NAME: characterstring_init_ansi(&char_string, Model_Name); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_FIRMWARE_REVISION: characterstring_init_ansi(&char_string, BACnet_Version); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_APPLICATION_SOFTWARE_VERSION: characterstring_init_ansi(&char_string, Application_Software_Version); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_LOCATION: characterstring_init_ansi(&char_string, Location); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; /* FIXME: if you support time */ case PROP_LOCAL_TIME: /* FIXME: get the actual value */ Local_Time.hour = 7; Local_Time.min = 0; Local_Time.sec = 3; Local_Time.hundredths = 1; apdu_len = encode_application_time(&apdu[0], &Local_Time); break; /* FIXME: if you support time */ case PROP_UTC_OFFSET: apdu_len = encode_application_signed(&apdu[0], UTC_Offset); break; /* FIXME: if you support date */ case PROP_LOCAL_DATE: /* FIXME: get the actual value instead of April Fool's Day */ Local_Date.year = 2006; /* AD */ Local_Date.month = 4; /* 1=Jan */ Local_Date.day = 1; /* 1..31 */ Local_Date.wday = 6; /* 1=Monday */ apdu_len = encode_application_date(&apdu[0], &Local_Date); break; case PROP_DAYLIGHT_SAVINGS_STATUS: apdu_len = encode_application_boolean(&apdu[0], Daylight_Savings_Status); break; case PROP_PROTOCOL_VERSION: apdu_len = encode_application_unsigned(&apdu[0], Device_Protocol_Version()); break; case PROP_PROTOCOL_REVISION: apdu_len = encode_application_unsigned(&apdu[0], Device_Protocol_Revision()); break; /* BACnet Legacy Support */ case PROP_PROTOCOL_CONFORMANCE_CLASS: apdu_len = encode_application_unsigned(&apdu[0], 1); 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++) { if ((i == OBJECT_DEVICE) || Object_Count[i]) { bitstring_set_bit(&bit_string, i, true); } else { /* initialize all the object types to not-supported */ bitstring_set_bit(&bit_string, (uint8_t) i, false); } } 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++) { 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) { /* reject message */ apdu_len = -2; break; } } else { /* error: internal error? */ *error_class = ERROR_CLASS_SERVICES; *error_code = ERROR_CODE_OTHER; 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], 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: the real max apdu remaining should be passed into function */ apdu_len = address_list_encode(&apdu[0], MAX_APDU); break; case PROP_DATABASE_REVISION: apdu_len = encode_application_unsigned(&apdu[0], Database_Revision); break; #if defined(BACDL_MSTP) 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; #endif case PROP_ACTIVE_COV_SUBSCRIPTIONS: /* FIXME: the real max apdu should be passed into function */ apdu_len = handler_cov_encode_subscriptions(&apdu[0], MAX_APDU); break; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } return apdu_len; }
/* return apdu len, or BACNET_STATUS_ERROR on error */ int Multistate_Input_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint32_t present_value = 0; unsigned i = 0; uint32_t max_states = 0; bool state = false; uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_MULTI_STATE_INPUT, rpdata->object_instance); break; /* note: Name and Description don't have to be the same. You could make Description writable and different */ case PROP_OBJECT_NAME: Multistate_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, Multistate_Input_Description(rpdata->object_instance)); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_MULTI_STATE_INPUT); break; case PROP_PRESENT_VALUE: present_value = Multistate_Input_Present_Value(rpdata->object_instance); apdu_len = encode_application_unsigned(&apdu[0], present_value); break; case PROP_STATUS_FLAGS: /* note: see the details in the standard on how to use these */ bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); if (Multistate_Input_Out_Of_Service(rpdata->object_instance)) { bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, true); } else { bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); } apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: /* note: see the details in the standard on how to use this */ apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: state = Multistate_Input_Out_Of_Service(rpdata->object_instance); apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_NUMBER_OF_STATES: apdu_len = encode_application_unsigned(&apdu[apdu_len], Multistate_Input_Max_States(rpdata->object_instance)); break; case PROP_STATE_TEXT: if (rpdata->array_index == 0) { /* Array element zero is the number of elements in the array */ apdu_len = encode_application_unsigned(&apdu[0], Multistate_Input_Max_States(rpdata->object_instance)); } else if (rpdata->array_index == BACNET_ARRAY_ALL) { /* if no index was specified, then try to encode the entire list */ /* into one packet. */ max_states = Multistate_Input_Max_States(rpdata->object_instance); for (i = 1; i <= max_states; i++) { characterstring_init_ansi(&char_string, Multistate_Input_State_Text(rpdata->object_instance, i)); /* FIXME: this might go beyond MAX_APDU length! */ len = encode_application_character_string(&apdu[apdu_len], &char_string); /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) { apdu_len += len; } else { rpdata->error_class = ERROR_CLASS_SERVICES; rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; apdu_len = BACNET_STATUS_ERROR; break; } } } else { max_states = Multistate_Input_Max_States(rpdata->object_instance); if (rpdata->array_index <= max_states) { characterstring_init_ansi(&char_string, Multistate_Input_State_Text(rpdata->object_instance, rpdata->array_index)); apdu_len = encode_application_character_string(&apdu[0], &char_string); } else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } } break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_STATE_TEXT) && (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; }
/* assumption - object has already exists */ int Analog_Input_Encode_Property_APDU( uint8_t * apdu, uint32_t object_instance, BACNET_PROPERTY_ID property, uint32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) { int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; unsigned object_index; switch (property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT, object_instance); break; /* note: Name and Description don't have to be the same. You could make Description writable and different. Note that Object-Name must be unique in this device */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, Analog_Input_Name(object_instance)); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_INPUT); break; case PROP_PRESENT_VALUE: object_index = Analog_Input_Instance_To_Index(object_instance); apdu_len = encode_application_real(&apdu[0], Present_Value[object_index]); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], false); break; case PROP_UNITS: apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT); break; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = -1; } return apdu_len; }
/* return apdu len, or -1 on error */ int Binary_Value_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; BACNET_BINARY_PV present_value = BINARY_INACTIVE; BACNET_POLARITY polarity = POLARITY_NORMAL; unsigned object_index = 0; unsigned i = 0; bool state = false; uint8_t *apdu = NULL; Binary_Value_Initialize(); if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE, rpdata->object_instance); break; /* note: Name and Description don't have to be the same. You could make Description writable and different */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, Binary_Value_Name(rpdata->object_instance)); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE); break; case PROP_PRESENT_VALUE: present_value = Binary_Value_Present_Value(rpdata->object_instance); apdu_len = encode_application_enumerated(&apdu[0], present_value); break; case PROP_STATUS_FLAGS: /* note: see the details in the standard on how to use these */ bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: /* note: see the details in the standard on how to use this */ apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], false); break; case PROP_POLARITY: /* FIXME: figure out the polarity */ apdu_len = encode_application_enumerated(&apdu[0], polarity); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = -1; } return apdu_len; }
/* return apdu len, or BACNET_STATUS_ERROR on error */ int Credential_Data_Input_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; unsigned object_index = 0; unsigned i = 0; bool state = false; uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; object_index = Credential_Data_Input_Instance_To_Index(rpdata->object_instance); switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_CREDENTIAL_DATA_INPUT, rpdata->object_instance); break; case PROP_OBJECT_NAME: Credential_Data_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_CREDENTIAL_DATA_INPUT); break; case PROP_PRESENT_VALUE: apdu_len = bacapp_encode_authentication_factor(&apdu[apdu_len], &cdi_descr[object_index].present_value); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); state = Credential_Data_Input_Out_Of_Service(rpdata->object_instance); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_RELIABILITY: apdu_len = encode_application_enumerated(&apdu[0], cdi_descr[object_index].reliability); break; case PROP_OUT_OF_SERVICE: state = Credential_Data_Input_Out_Of_Service(rpdata->object_instance); apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_SUPPORTED_FORMATS: if (rpdata->array_index == 0) { apdu_len = encode_application_unsigned(&apdu[0], cdi_descr[object_index].supported_formats_count); } else if (rpdata->array_index == BACNET_ARRAY_ALL) { for (i = 0; i < cdi_descr[object_index].supported_formats_count; i++) { len = bacapp_encode_authentication_factor_format(&apdu[0], &cdi_descr[object_index].supported_formats[i]); if (apdu_len + len < MAX_APDU) apdu_len += len; else { rpdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; apdu_len = BACNET_STATUS_ABORT; break; } } } else { if (rpdata->array_index <= cdi_descr[object_index].supported_formats_count) { apdu_len = bacapp_encode_authentication_factor_format(&apdu[0], &cdi_descr[object_index]. supported_formats[rpdata->array_index - 1]); } else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } } break; case PROP_UPDATE_TIME: apdu_len = bacapp_encode_timestamp(&apdu[0], &cdi_descr[object_index].timestamp); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_SUPPORTED_FORMATS) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/* 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; BACNET_TIME local_time; BACNET_DATE local_date; uint8_t year = 0; char string_buffer[24]; int16_t TimeZone = 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: (void) strcpypgm2ram(&string_buffer[0], "PIC18F6720 Device"); characterstring_init_ansi(&char_string, string_buffer); 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_DESCRIPTION: (void) strcpypgm2ram(&string_buffer[0], "BACnet Demo"); characterstring_init_ansi(&char_string, string_buffer); 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: (void) strcpypgm2ram(&string_buffer[0], BACNET_VENDOR_NAME); characterstring_init_ansi(&char_string, string_buffer); 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: (void) strcpypgm2ram(&string_buffer[0], "GNU Demo"); characterstring_init_ansi(&char_string, string_buffer); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_FIRMWARE_REVISION: characterstring_init_ansi(&char_string, BACnet_Version); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_APPLICATION_SOFTWARE_VERSION: (void) strcpypgm2ram(&string_buffer[0], "1.0"); characterstring_init_ansi(&char_string, string_buffer); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_LOCATION: (void) strcpypgm2ram(&string_buffer[0], "USA"); characterstring_init_ansi(&char_string, string_buffer); 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()); break; case PROP_PROTOCOL_REVISION: apdu_len = encode_application_unsigned(&apdu[0], Device_Protocol_Revision()); break; /* BACnet Legacy Support */ case PROP_PROTOCOL_CONFORMANCE_CLASS: apdu_len = encode_application_unsigned(&apdu[0], 1); 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(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); } /* 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); bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true); bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, 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++) { 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) { *error_class = ERROR_CLASS_SERVICES; *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; apdu_len = -1; break; } } else { /* error: internal error? */ *error_class = ERROR_CLASS_SERVICES; *error_code = ERROR_CODE_OTHER; 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], 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 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()); break; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } return apdu_len; }
/* return apdu len, or BACNET_STATUS_ERROR on error */ int Life_Safety_Point_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; BACNET_LIFE_SAFETY_STATE present_value = LIFE_SAFETY_STATE_QUIET; BACNET_LIFE_SAFETY_MODE mode = LIFE_SAFETY_MODE_DEFAULT; BACNET_SILENCED_STATE silenced_state = SILENCED_STATE_UNSILENCED; BACNET_LIFE_SAFETY_OPERATION operation = LIFE_SAFETY_OP_NONE; unsigned object_index = 0; bool state = false; BACNET_RELIABILITY reliability = RELIABILITY_NO_FAULT_DETECTED; uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_LIFE_SAFETY_POINT, rpdata->object_instance); break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: Life_Safety_Point_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_LIFE_SAFETY_POINT); break; case PROP_PRESENT_VALUE: present_value = Life_Safety_Point_Present_Value(rpdata->object_instance); apdu_len = encode_application_enumerated(&apdu[0], present_value); break; case PROP_TRACKING_VALUE: /* FIXME: tracking value is a local matter how it is derived */ present_value = Life_Safety_Point_Present_Value(rpdata->object_instance); apdu_len = encode_application_enumerated(&apdu[0], present_value); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: object_index = Life_Safety_Point_Instance_To_Index(rpdata->object_instance); state = Life_Safety_Point_Out_Of_Service[object_index]; apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_RELIABILITY: /* see standard for details about this property */ reliability = RELIABILITY_NO_FAULT_DETECTED; apdu_len = encode_application_enumerated(&apdu[0], reliability); break; case PROP_MODE: object_index = Life_Safety_Point_Instance_To_Index(rpdata->object_instance); mode = Life_Safety_Point_Mode[object_index]; apdu_len = encode_application_enumerated(&apdu[0], mode); break; case PROP_ACCEPTED_MODES: for (mode = MIN_LIFE_SAFETY_MODE; mode < MAX_LIFE_SAFETY_MODE; mode++) { len = encode_application_enumerated(&apdu[apdu_len], mode); apdu_len += len; } break; case PROP_SILENCED: object_index = Life_Safety_Point_Instance_To_Index(rpdata->object_instance); silenced_state = Life_Safety_Point_Silenced_State[object_index]; apdu_len = encode_application_enumerated(&apdu[0], silenced_state); break; case PROP_OPERATION_EXPECTED: object_index = Life_Safety_Point_Instance_To_Index(rpdata->object_instance); operation = Life_Safety_Point_Operation[object_index]; apdu_len = encode_application_enumerated(&apdu[0], operation); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
int rr_address_list_encode( uint8_t * apdu, BACNET_READ_RANGE_DATA * pRequest) { int iLen = 0; int32_t iTemp = 0; struct Address_Cache_Entry *pMatch = NULL; BACNET_OCTET_STRING MAC_Address; uint32_t uiTotal = 0; /* Number of bound entries in the cache */ uint32_t uiIndex = 0; /* Current entry number */ uint32_t uiFirst = 0; /* Entry number we started encoding from */ uint32_t uiLast = 0; /* Entry number we finished encoding on */ uint32_t uiTarget = 0; /* Last entry we are required to encode */ uint32_t uiRemaining = 0; /* Amount of unused space in packet */ /* Initialise result flags to all false */ bitstring_init(&pRequest->ResultFlags); bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_FIRST_ITEM, false); bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_LAST_ITEM, false); bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS, false); /* See how much space we have */ uiRemaining = (uint32_t) (MAX_APDU - pRequest->Overhead); pRequest->ItemCount = 0; /* Start out with nothing */ uiTotal = address_count(); /* What do we have to work with here ? */ if (uiTotal == 0) /* Bail out now if nowt */ return (0); if (pRequest->RequestType == RR_READ_ALL) { /* * Read all the array or as much as will fit in the buffer by selecting * a range that covers the whole list and falling through to the next * section of code */ pRequest->Count = uiTotal; /* Full list */ pRequest->Range.RefIndex = 1; /* Starting at the beginning */ } if (pRequest->Count < 0) { /* negative count means work from index backwards */ /* * Convert from end index/negative count to * 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. * * Note: We need to be careful about how we convert these * values due to the mix of signed and unsigned types - don't * try to optimise the code unless you understand all the * implications of the data type conversions! */ iTemp = pRequest->Range.RefIndex; /* pull out and convert to signed */ iTemp += pRequest->Count + 1; /* Adjust backwards, remember count is -ve */ if (iTemp < 1) { /* if count is too much, return from 1 to start index */ pRequest->Count = pRequest->Range.RefIndex; pRequest->Range.RefIndex = 1; } else { /* Otherwise adjust the start index and make count +ve */ pRequest->Range.RefIndex = iTemp; pRequest->Count = -pRequest->Count; } } /* From here on in we only have a starting point and a positive count */ if (pRequest->Range.RefIndex > uiTotal) /* Nothing to return as we are past the end of the list */ return (0); uiTarget = pRequest->Range.RefIndex + pRequest->Count - 1; /* Index of last required entry */ if (uiTarget > uiTotal) /* Capped at end of list if necessary */ uiTarget = uiTotal; pMatch = Address_Cache; uiIndex = 1; while ((pMatch->Flags & (BAC_ADDR_IN_USE | BAC_ADDR_BIND_REQ)) != BAC_ADDR_IN_USE) /* Find first bound entry */ pMatch++; /* Seek to start position */ while (uiIndex != pRequest->Range.RefIndex) { if ((pMatch->Flags & (BAC_ADDR_IN_USE | BAC_ADDR_BIND_REQ)) == BAC_ADDR_IN_USE) { /* Only count bound entries */ pMatch++; uiIndex++; } else pMatch++; } uiFirst = uiIndex; /* Record where we started from */ while (uiIndex <= uiTarget) { if (uiRemaining < ACACHE_MAX_ENC) { /* * 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, true); break; } iTemp = (int32_t) encode_application_object_id(&apdu[iLen], OBJECT_DEVICE, pMatch->device_id); iTemp += encode_application_unsigned(&apdu[iLen + iTemp], pMatch->address.net); /* pick the appropriate type of entry from the cache */ if (pMatch->address.len != 0) { octetstring_init(&MAC_Address, pMatch->address.adr, pMatch->address.len); iTemp += encode_application_octet_string(&apdu[iLen + iTemp], &MAC_Address); } else { octetstring_init(&MAC_Address, pMatch->address.mac, pMatch->address.mac_len); iTemp += encode_application_octet_string(&apdu[iLen + iTemp], &MAC_Address); } uiRemaining -= iTemp; /* Reduce the remaining space */ iLen += iTemp; /* and increase the length consumed */ uiLast = uiIndex; /* Record the last entry encoded */ uiIndex++; /* and get ready for next one */ pMatch++; pRequest->ItemCount++; /* Chalk up another one for the response count */ while ((pMatch->Flags & (BAC_ADDR_IN_USE | BAC_ADDR_BIND_REQ)) != BAC_ADDR_IN_USE) /* Find next bound entry */ pMatch++; } /* Set remaining result flags if necessary */ if (uiFirst == 1) bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_FIRST_ITEM, true); if (uiLast == uiTotal) bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_LAST_ITEM, true); return (iLen); }
/* assumption - object has already exists */ int Analog_Input_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT, rpdata->object_instance); break; /* note: Name and Description don't have to be the same. You could make Description writable and different */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, Analog_Input_Name(rpdata->object_instance)); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_INPUT); break; case PROP_PRESENT_VALUE: apdu_len = encode_application_real(&apdu[0], Analog_Input_Present_Value(rpdata->object_instance)); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], false); break; case PROP_UNITS: apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = -1; } return apdu_len; }
/* return apdu len, or -1 on error */ int Analog_Value_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 len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; float real_value = (float) 1.414; unsigned object_index = 0; unsigned i = 0; bool state = false; Analog_Value_Init(); switch (property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE, object_instance); break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: characterstring_init_ansi(&char_string, Analog_Value_Name(object_instance)); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE); break; case PROP_PRESENT_VALUE: real_value = Analog_Value_Present_Value(object_instance); apdu_len = encode_application_real(&apdu[0], real_value); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: #if 0 object_index = Analog_Value_Instance_To_Index(object_instance); state = Analog_Value_Out_Of_Service[object_index]; #endif apdu_len = encode_application_boolean(&apdu[0], false); break; case PROP_UNITS: apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT); break; #if 0 case PROP_PRIORITY_ARRAY: /* Array element zero is the number of elements in the array */ if (array_index == 0) apdu_len = encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); /* if no index was specified, then try to encode the entire list */ /* into one packet. */ else if (array_index == BACNET_ARRAY_ALL) { object_index = Analog_Value_Instance_To_Index(object_instance); for (i = 0; i < BACNET_MAX_PRIORITY; i++) { /* FIXME: check if we have room before adding it to APDU */ if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL) len = encode_application_null(&apdu[apdu_len]); else { real_value = Present_Value[object_index][i]; len = encode_application_real(&apdu[apdu_len], real_value); } /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) apdu_len += len; else { *error_class = ERROR_CLASS_SERVICES; *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; apdu_len = -1; break; } } } else { object_index = Analog_Value_Instance_To_Index(object_instance); if (array_index <= BACNET_MAX_PRIORITY) { if (Present_Value[object_index][array_index - 1] == ANALOG_LEVEL_NULL) apdu_len = encode_application_null(&apdu[0]); else { real_value = Present_Value[object_index][array_index - 1]; apdu_len = encode_application_real(&apdu[0], real_value); } } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = -1; } } break; case PROP_RELINQUISH_DEFAULT: real_value = ANALOG_RELINQUISH_DEFAULT; apdu_len = encode_application_real(&apdu[0], real_value); break; #endif default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } return apdu_len; }
/* assumption - object already exists, and has been bounds checked */ int Binary_Input_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT, rpdata->object_instance); break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: /* note: object name must be unique in our device */ Binary_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_INPUT); break; case PROP_PRESENT_VALUE: /* note: you need to look up the actual value */ apdu_len = encode_application_enumerated(&apdu[0], Binary_Input_Present_Value(rpdata->object_instance)); break; case PROP_STATUS_FLAGS: /* note: see the details in the standard on how to use these */ bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); if (Binary_Input_Out_Of_Service(rpdata->object_instance)) { bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, true); } else { bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); } apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: /* note: see the details in the standard on how to use this */ apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], Binary_Input_Out_Of_Service(rpdata->object_instance)); break; case PROP_POLARITY: apdu_len = encode_application_enumerated(&apdu[0], Binary_Input_Polarity(rpdata->object_instance)); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/* assumption - object already exists */ int Analog_Input_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int apdu_len = 0; /* return value */ BACNET_CHARACTER_STRING char_string = { 0 }; BACNET_BIT_STRING bit_string = { 0 }; uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], rpdata->object_type, rpdata->object_instance); break; case PROP_OBJECT_NAME: Analog_Input_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], rpdata->object_type); break; case PROP_PRESENT_VALUE: apdu_len = encode_application_real(&apdu[0], Analog_Input_Present_Value(rpdata->object_instance)); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, Analog_Input_Out_Of_Service(rpdata->object_instance)); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], Analog_Input_Out_Of_Service(rpdata->object_instance)); break; case PROP_UNITS: apdu_len = encode_application_enumerated(&apdu[0], Analog_Input_Units(rpdata->object_instance)); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/* return apdu len, or -1 on error */ int Binary_Output_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; BACNET_BINARY_PV present_value = BINARY_INACTIVE; unsigned object_index = 0; unsigned i = 0; bool state = false; uint8_t *apdu = NULL; if ((rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { /* object id, object name, object type are handled in Device object */ case PROP_PRESENT_VALUE: present_value = Binary_Output_Present_Value(rpdata->object_instance); apdu_len = encode_application_enumerated(&apdu[0], present_value); break; case PROP_STATUS_FLAGS: /* note: see the details in the standard on how to use these */ bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: /* note: see the details in the standard on how to use this */ apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: object_index = Binary_Output_Instance_To_Index(rpdata->object_instance); state = Out_Of_Service[object_index]; apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_POLARITY: object_index = Binary_Output_Instance_To_Index(rpdata->object_instance); apdu_len = encode_application_enumerated(&apdu[0], Polarity[object_index]); break; case PROP_PRIORITY_ARRAY: /* Array element zero is the number of elements in the array */ if (rpdata->array_index == 0) apdu_len = encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); /* if no index was specified, then try to encode the entire list */ /* into one packet. */ else if (rpdata->array_index == BACNET_ARRAY_ALL) { object_index = Binary_Output_Instance_To_Index(rpdata->object_instance); for (i = 0; i < BACNET_MAX_PRIORITY; i++) { /* FIXME: check if we have room before adding it to APDU */ present_value = (BACNET_BINARY_PV) Binary_Output_Level[object_index][i]; if (present_value == BINARY_NULL) { len = encode_application_null(&apdu[apdu_len]); } else { len = encode_application_enumerated(&apdu[apdu_len], present_value); } /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) apdu_len += len; else { rpdata->error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; apdu_len = BACNET_STATUS_ABORT; break; } } } else { object_index = Binary_Output_Instance_To_Index(rpdata->object_instance); if (rpdata->array_index <= BACNET_MAX_PRIORITY) { present_value = (BACNET_BINARY_PV) Binary_Output_Level[object_index][rpdata->array_index - 1]; if (present_value == BINARY_NULL) { apdu_len = encode_application_null(&apdu[apdu_len]); } else { apdu_len = encode_application_enumerated(&apdu[apdu_len], present_value); } } else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } } break; case PROP_RELINQUISH_DEFAULT: present_value = RELINQUISH_DEFAULT; apdu_len = encode_application_enumerated(&apdu[0], present_value); break; case PROP_ACTIVE_TEXT: characterstring_init_ansi(&char_string, "on"); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_INACTIVE_TEXT: characterstring_init_ansi(&char_string, "off"); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) && (rpdata->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 apdu len, or -1 on error */ int Analog_Value_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; float real_value = (float) 1.414; #if 0 int len = 0; unsigned object_index = 0; unsigned i = 0; bool state = false; #endif uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE, rpdata->object_instance); break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: Analog_Value_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE); break; case PROP_PRESENT_VALUE: real_value = Analog_Value_Present_Value(rpdata->object_instance); apdu_len = encode_application_real(&apdu[0], real_value); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: #if 0 object_index = Analog_Value_Instance_To_Index(rpdata->object_instance); state = Analog_Value_Out_Of_Service[object_index]; #endif apdu_len = encode_application_boolean(&apdu[0], false); break; case PROP_UNITS: apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT); break; #if 0 case PROP_PRIORITY_ARRAY: /* Array element zero is the number of elements in the array */ if (rpdata->array_index == 0) apdu_len = encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); /* if no index was specified, then try to encode the entire list */ /* into one packet. */ else if (rpdata->array_index == BACNET_ARRAY_ALL) { object_index = Analog_Value_Instance_To_Index(rpdata->object_instance); for (i = 0; i < BACNET_MAX_PRIORITY; i++) { /* FIXME: check if we have room before adding it to APDU */ if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL) len = encode_application_null(&apdu[apdu_len]); else { real_value = Present_Value[object_index][i]; len = encode_application_real(&apdu[apdu_len], real_value); } /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) apdu_len += len; else { rpdata->error_class = ERROR_CLASS_SERVICES; rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; apdu_len = BACNET_STATUS_ERROR; break; } } } else { object_index = Analog_Value_Instance_To_Index(object_instance); if (rpdata->array_index <= BACNET_MAX_PRIORITY) { if (Present_Value[object_index][rpdata->array_index - 1] == ANALOG_LEVEL_NULL) apdu_len = encode_application_null(&apdu[0]); else { real_value = Present_Value[object_index][rpdata->array_index - 1]; apdu_len = encode_application_real(&apdu[0], real_value); } } else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } } break; case PROP_RELINQUISH_DEFAULT: real_value = ANALOG_RELINQUISH_DEFAULT; apdu_len = encode_application_real(&apdu[0], real_value); break; #endif default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && #if 0 (rpdata->object_property != PROP_PRIORITY_ARRAY) && #endif (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/** * ReadProperty handler for this object. For the given ReadProperty * data, the application_data is loaded or the error flags are set. * * @param rpdata - BACNET_READ_PROPERTY_DATA data, including * requested data and space for the reply, or error response. * * @return number of APDU bytes in the response, or * BACNET_STATUS_ERROR on error. */ int Integer_Value_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; uint8_t *apdu = NULL; uint32_t units = 0; int32_t integer_value = 0.0; bool state = false; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_INTEGER_VALUE, rpdata->object_instance); break; case PROP_OBJECT_NAME: Integer_Value_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_INTEGER_VALUE); break; case PROP_PRESENT_VALUE: integer_value = Integer_Value_Present_Value(rpdata->object_instance); apdu_len = encode_application_signed(&apdu[0], integer_value); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); state = Integer_Value_Out_Of_Service(rpdata->object_instance); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_OUT_OF_SERVICE: state = Integer_Value_Out_Of_Service(rpdata->object_instance); apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_UNITS: units = Integer_Value_Units(rpdata->object_instance); apdu_len = encode_application_enumerated(&apdu[0], units); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) && (rpdata->object_property != PROP_EVENT_TIME_STAMPS) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/* 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, uint32_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], 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); /* 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); #if MAX_ANALOG_VALUES bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true); #endif #if MAX_BINARY_VALUES bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true); #endif 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_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; apdu_len = BACNET_STATUS_ABORT; 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 = 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], 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; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (property != PROP_OBJECT_LIST) && (array_index != BACNET_ARRAY_ALL)) { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/* return apdu len, or BACNET_STATUS_ERROR on error */ int Analog_Value_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; float real_value = (float) 1.414; unsigned object_index = 0; unsigned i = 0; bool state = false; uint8_t *apdu = NULL; ANALOG_VALUE_DESCR *CurrentAV; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; object_index = Analog_Value_Instance_To_Index(rpdata->object_instance); if (object_index < MAX_ANALOG_VALUES) CurrentAV = &AV_Descr[object_index]; else return BACNET_STATUS_ERROR; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE, rpdata->object_instance); break; case PROP_OBJECT_NAME: case PROP_DESCRIPTION: Analog_Value_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE); break; case PROP_PRESENT_VALUE: real_value = Analog_Value_Present_Value(rpdata->object_instance); apdu_len = encode_application_real(&apdu[0], real_value); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); #if defined(INTRINSIC_REPORTING) bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, CurrentAV->Event_State ? true : false); #else bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); #endif bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, CurrentAV->Out_Of_Service); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: #if defined(INTRINSIC_REPORTING) apdu_len = encode_application_enumerated(&apdu[0], CurrentAV->Event_State); #else apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); #endif break; case PROP_OUT_OF_SERVICE: state = CurrentAV->Out_Of_Service; apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_UNITS: apdu_len = encode_application_enumerated(&apdu[0], CurrentAV->Units); break; #if defined(INTRINSIC_REPORTING) case PROP_TIME_DELAY: apdu_len = encode_application_unsigned(&apdu[0], CurrentAV->Time_Delay); break; case PROP_NOTIFICATION_CLASS: apdu_len = encode_application_unsigned(&apdu[0], CurrentAV->Notification_Class); break; case PROP_HIGH_LIMIT: apdu_len = encode_application_real(&apdu[0], CurrentAV->High_Limit); break; case PROP_LOW_LIMIT: apdu_len = encode_application_real(&apdu[0], CurrentAV->Low_Limit); break; case PROP_DEADBAND: apdu_len = encode_application_real(&apdu[0], CurrentAV->Deadband); break; case PROP_LIMIT_ENABLE: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, 0, (CurrentAV-> Limit_Enable & EVENT_LOW_LIMIT_ENABLE) ? true : false); bitstring_set_bit(&bit_string, 1, (CurrentAV-> Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) ? true : false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_ENABLE: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, (CurrentAV-> Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) ? true : false); bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, (CurrentAV-> Event_Enable & EVENT_ENABLE_TO_FAULT) ? true : false); bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, (CurrentAV-> Event_Enable & EVENT_ENABLE_TO_NORMAL) ? true : false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_ACKED_TRANSITIONS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL]. bIsAcked); bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked); bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_NOTIFY_TYPE: apdu_len = encode_application_enumerated(&apdu[0], CurrentAV->Notify_Type ? NOTIFY_EVENT : NOTIFY_ALARM); break; case PROP_EVENT_TIME_STAMPS: /* Array element zero is the number of elements in the array */ if (rpdata->array_index == 0) apdu_len = encode_application_unsigned(&apdu[0], MAX_BACNET_EVENT_TRANSITION); /* if no index was specified, then try to encode the entire list */ /* into one packet. */ else if (rpdata->array_index == BACNET_ARRAY_ALL) { for (i = 0; i < MAX_BACNET_EVENT_TRANSITION; i++) {; len = encode_opening_tag(&apdu[apdu_len], TIME_STAMP_DATETIME); len += encode_application_date(&apdu[apdu_len + len], &CurrentAV->Event_Time_Stamps[i].date); len += encode_application_time(&apdu[apdu_len + len], &CurrentAV->Event_Time_Stamps[i].time); len += encode_closing_tag(&apdu[apdu_len + len], TIME_STAMP_DATETIME); /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) apdu_len += len; else { rpdata->error_class = ERROR_CLASS_SERVICES; rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; apdu_len = BACNET_STATUS_ERROR; break; } } } else if (rpdata->array_index <= MAX_BACNET_EVENT_TRANSITION) { apdu_len = encode_opening_tag(&apdu[apdu_len], TIME_STAMP_DATETIME); apdu_len += encode_application_date(&apdu[apdu_len], &CurrentAV->Event_Time_Stamps[rpdata->array_index].date); apdu_len += encode_application_time(&apdu[apdu_len], &CurrentAV->Event_Time_Stamps[rpdata->array_index].time); apdu_len += encode_closing_tag(&apdu[apdu_len], TIME_STAMP_DATETIME); } else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } break; #endif default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) && (rpdata->object_property != PROP_EVENT_TIME_STAMPS) && (rpdata->array_index != BACNET_ARRAY_ALL)) { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = BACNET_STATUS_ERROR; } return apdu_len; }
/* return apdu len, or -1 on error */ int Analog_Value_Encode_Property_APDU( uint8_t * apdu, uint32_t object_instance, BACNET_PROPERTY_ID property, uint32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) { int apdu_len = 0; /* return value */ BACNET_BIT_STRING xdata bit_string; BACNET_CHARACTER_STRING xdata char_string; unsigned object_index; switch (property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE, object_instance); break; case PROP_OBJECT_NAME: characterstring_init_ansi(&char_string, // vars[object_instance].label Analog_Value_Name(object_instance) ); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE); break; case PROP_PRESENT_VALUE: object_index = Analog_Value_Instance_To_Index(object_instance); apdu_len = encode_application_real(&apdu[0], AV_Present_Value[object_index]); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: apdu_len = encode_application_boolean(&apdu[0], false); break; case PROP_UNITS: apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT); break; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = -1; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY; apdu_len = -1; } return apdu_len; }
void Analog_Value_Intrinsic_Reporting( uint32_t object_instance) { #if defined(INTRINSIC_REPORTING) BACNET_EVENT_NOTIFICATION_DATA event_data; BACNET_CHARACTER_STRING msgText; ANALOG_VALUE_DESCR *CurrentAV; unsigned int object_index; uint8_t FromState = 0; uint8_t ToState; float ExceededLimit = 0.0f; float PresentVal = 0.0f; bool SendNotify = false; object_index = Analog_Value_Instance_To_Index(object_instance); if (object_index < MAX_ANALOG_VALUES) CurrentAV = &AV_Descr[object_index]; else return; /* check limits */ if (!CurrentAV->Limit_Enable) return; /* limits are not configured */ if (CurrentAV->Ack_notify_data.bSendAckNotify) { /* clean bSendAckNotify flag */ CurrentAV->Ack_notify_data.bSendAckNotify = false; /* copy toState */ ToState = CurrentAV->Ack_notify_data.EventState; #if PRINT_ENABLED fprintf(stderr, "Send Acknotification for (%s,%d).\n", bactext_object_type_name(OBJECT_ANALOG_VALUE), object_instance); #endif /* PRINT_ENABLED */ characterstring_init_ansi(&msgText, "AckNotification"); /* Notify Type */ event_data.notifyType = NOTIFY_ACK_NOTIFICATION; /* Send EventNotification. */ SendNotify = true; } else { /* actual Present_Value */ PresentVal = Analog_Value_Present_Value(object_instance); FromState = CurrentAV->Event_State; switch (CurrentAV->Event_State) { case EVENT_STATE_NORMAL: /* A TO-OFFNORMAL event is generated under these conditions: (a) the Present_Value must exceed the High_Limit for a minimum period of time, specified in the Time_Delay property, and (b) the HighLimitEnable flag must be set in the Limit_Enable property, and (c) the TO-OFFNORMAL flag must be set in the Event_Enable property. */ if ((PresentVal > CurrentAV->High_Limit) && ((CurrentAV->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) == EVENT_HIGH_LIMIT_ENABLE) && ((CurrentAV->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) == EVENT_ENABLE_TO_OFFNORMAL)) { if (!CurrentAV->Remaining_Time_Delay) CurrentAV->Event_State = EVENT_STATE_HIGH_LIMIT; else CurrentAV->Remaining_Time_Delay--; break; } /* A TO-OFFNORMAL event is generated under these conditions: (a) the Present_Value must exceed the Low_Limit plus the Deadband for a minimum period of time, specified in the Time_Delay property, and (b) the LowLimitEnable flag must be set in the Limit_Enable property, and (c) the TO-NORMAL flag must be set in the Event_Enable property. */ if ((PresentVal < CurrentAV->Low_Limit) && ((CurrentAV->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) == EVENT_LOW_LIMIT_ENABLE) && ((CurrentAV->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) == EVENT_ENABLE_TO_OFFNORMAL)) { if (!CurrentAV->Remaining_Time_Delay) CurrentAV->Event_State = EVENT_STATE_LOW_LIMIT; else CurrentAV->Remaining_Time_Delay--; break; } /* value of the object is still in the same event state */ CurrentAV->Remaining_Time_Delay = CurrentAV->Time_Delay; break; case EVENT_STATE_HIGH_LIMIT: /* Once exceeded, the Present_Value must fall below the High_Limit minus the Deadband before a TO-NORMAL event is generated under these conditions: (a) the Present_Value must fall below the High_Limit minus the Deadband for a minimum period of time, specified in the Time_Delay property, and (b) the HighLimitEnable flag must be set in the Limit_Enable property, and (c) the TO-NORMAL flag must be set in the Event_Enable property. */ if ((PresentVal < CurrentAV->High_Limit - CurrentAV->Deadband) && ((CurrentAV->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) == EVENT_HIGH_LIMIT_ENABLE) && ((CurrentAV->Event_Enable & EVENT_ENABLE_TO_NORMAL) == EVENT_ENABLE_TO_NORMAL)) { if (!CurrentAV->Remaining_Time_Delay) CurrentAV->Event_State = EVENT_STATE_NORMAL; else CurrentAV->Remaining_Time_Delay--; break; } /* value of the object is still in the same event state */ CurrentAV->Remaining_Time_Delay = CurrentAV->Time_Delay; break; case EVENT_STATE_LOW_LIMIT: /* Once the Present_Value has fallen below the Low_Limit, the Present_Value must exceed the Low_Limit plus the Deadband before a TO-NORMAL event is generated under these conditions: (a) the Present_Value must exceed the Low_Limit plus the Deadband for a minimum period of time, specified in the Time_Delay property, and (b) the LowLimitEnable flag must be set in the Limit_Enable property, and (c) the TO-NORMAL flag must be set in the Event_Enable property. */ if ((PresentVal > CurrentAV->Low_Limit + CurrentAV->Deadband) && ((CurrentAV->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) == EVENT_LOW_LIMIT_ENABLE) && ((CurrentAV->Event_Enable & EVENT_ENABLE_TO_NORMAL) == EVENT_ENABLE_TO_NORMAL)) { if (!CurrentAV->Remaining_Time_Delay) CurrentAV->Event_State = EVENT_STATE_NORMAL; else CurrentAV->Remaining_Time_Delay--; break; } /* value of the object is still in the same event state */ CurrentAV->Remaining_Time_Delay = CurrentAV->Time_Delay; break; default: return; /* shouldn't happen */ } /* switch (FromState) */ ToState = CurrentAV->Event_State; if (FromState != ToState) { /* Event_State has changed. Need to fill only the basic parameters of this type of event. Other parameters will be filled in common function. */ switch (ToState) { case EVENT_STATE_HIGH_LIMIT: ExceededLimit = CurrentAV->High_Limit; characterstring_init_ansi(&msgText, "Goes to high limit"); break; case EVENT_STATE_LOW_LIMIT: ExceededLimit = CurrentAV->Low_Limit; characterstring_init_ansi(&msgText, "Goes to low limit"); break; case EVENT_STATE_NORMAL: if (FromState == EVENT_STATE_HIGH_LIMIT) { ExceededLimit = CurrentAV->High_Limit; characterstring_init_ansi(&msgText, "Back to normal state from high limit"); } else { ExceededLimit = CurrentAV->Low_Limit; characterstring_init_ansi(&msgText, "Back to normal state from low limit"); } break; default: ExceededLimit = 0; break; } /* switch (ToState) */ #if PRINT_ENABLED fprintf(stderr, "Event_State for (%s,%d) goes from %s to %s.\n", bactext_object_type_name(OBJECT_ANALOG_VALUE), object_instance, bactext_event_state_name(FromState), bactext_event_state_name(ToState)); #endif /* PRINT_ENABLED */ /* Notify Type */ event_data.notifyType = CurrentAV->Notify_Type; /* Send EventNotification. */ SendNotify = true; } } if (SendNotify) { /* Event Object Identifier */ event_data.eventObjectIdentifier.type = OBJECT_ANALOG_VALUE; event_data.eventObjectIdentifier.instance = object_instance; /* Time Stamp */ event_data.timeStamp.tag = TIME_STAMP_DATETIME; Device_getCurrentDateTime(&event_data.timeStamp.value.dateTime); if (event_data.notifyType != NOTIFY_ACK_NOTIFICATION) { /* fill Event_Time_Stamps */ switch (ToState) { case EVENT_STATE_HIGH_LIMIT: case EVENT_STATE_LOW_LIMIT: CurrentAV->Event_Time_Stamps[TRANSITION_TO_OFFNORMAL] = event_data.timeStamp.value.dateTime; break; case EVENT_STATE_FAULT: CurrentAV->Event_Time_Stamps[TRANSITION_TO_FAULT] = event_data.timeStamp.value.dateTime; break; case EVENT_STATE_NORMAL: CurrentAV->Event_Time_Stamps[TRANSITION_TO_NORMAL] = event_data.timeStamp.value.dateTime; break; } } /* Notification Class */ event_data.notificationClass = CurrentAV->Notification_Class; /* Event Type */ event_data.eventType = EVENT_OUT_OF_RANGE; /* Message Text */ event_data.messageText = &msgText; /* Notify Type */ /* filled before */ /* From State */ if (event_data.notifyType != NOTIFY_ACK_NOTIFICATION) event_data.fromState = FromState; /* To State */ event_data.toState = CurrentAV->Event_State; /* Event Values */ if (event_data.notifyType != NOTIFY_ACK_NOTIFICATION) { /* Value that exceeded a limit. */ event_data.notificationParams.outOfRange.exceedingValue = PresentVal; /* Status_Flags of the referenced object. */ bitstring_init(&event_data.notificationParams.outOfRange. statusFlags); bitstring_set_bit(&event_data.notificationParams.outOfRange. statusFlags, STATUS_FLAG_IN_ALARM, CurrentAV->Event_State ? true : false); bitstring_set_bit(&event_data.notificationParams.outOfRange. statusFlags, STATUS_FLAG_FAULT, false); bitstring_set_bit(&event_data.notificationParams.outOfRange. statusFlags, STATUS_FLAG_OVERRIDDEN, false); bitstring_set_bit(&event_data.notificationParams.outOfRange. statusFlags, STATUS_FLAG_OUT_OF_SERVICE, CurrentAV->Out_Of_Service); /* Deadband used for limit checking. */ event_data.notificationParams.outOfRange.deadband = CurrentAV->Deadband; /* Limit that was exceeded. */ event_data.notificationParams.outOfRange.exceededLimit = ExceededLimit; } /* add data from notification class */ Notification_Class_common_reporting_function(&event_data); /* Ack required */ if ((event_data.notifyType != NOTIFY_ACK_NOTIFICATION) && (event_data.ackRequired == true)) { switch (event_data.toState) { case EVENT_STATE_OFFNORMAL: case EVENT_STATE_HIGH_LIMIT: case EVENT_STATE_LOW_LIMIT: CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL]. bIsAcked = false; CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL]. Time_Stamp = event_data.timeStamp.value.dateTime; break; case EVENT_STATE_FAULT: CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT]. bIsAcked = false; CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT]. Time_Stamp = event_data.timeStamp.value.dateTime; break; case EVENT_STATE_NORMAL: CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL]. bIsAcked = false; CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL]. Time_Stamp = event_data.timeStamp.value.dateTime; break; } } } #endif /* defined(INTRINSIC_REPORTING) */ }
/* return apdu len, or BACNET_STATUS_ERROR on error */ int Binary_Value_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; BACNET_BINARY_PV present_value = BINARY_INACTIVE; unsigned object_index = 0; unsigned i = 0; bool state = false; uint8_t *apdu = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE, rpdata->object_instance); break; /* note: Name and Description don't have to be the same. You could make Description writable and different */ case PROP_OBJECT_NAME: case PROP_DESCRIPTION: Binary_Value_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE); break; case PROP_PRESENT_VALUE: present_value = Binary_Value_Present_Value(rpdata->object_instance); apdu_len = encode_application_enumerated(&apdu[0], present_value); break; case PROP_STATUS_FLAGS: /* note: see the details in the standard on how to use these */ bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); state = Binary_Value_Out_Of_Service[object_index]; bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_EVENT_STATE: /* note: see the details in the standard on how to use this */ apdu_len = encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_OUT_OF_SERVICE: object_index = Binary_Value_Instance_To_Index(rpdata->object_instance); state = Binary_Value_Out_Of_Service[object_index]; apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_PRIORITY_ARRAY: /* Array element zero is the number of elements in the array */ if (rpdata->array_index == 0) apdu_len = encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); /* if no index was specified, then try to encode the entire list */ /* into one packet. */ else if (rpdata->array_index == BACNET_ARRAY_ALL) { object_index = Binary_Value_Instance_To_Index(rpdata->object_instance); for (i = 0; i < BACNET_MAX_PRIORITY; i++) { /* FIXME: check if we have room before adding it to APDU */ if (Binary_Value_Level[object_index][i] == BINARY_NULL) len = encode_application_null(&apdu[apdu_len]); else { present_value = Binary_Value_Level[object_index][i]; len = encode_application_enumerated(&apdu[apdu_len], present_value); } /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) apdu_len += len; else { rpdata->error_class = ERROR_CLASS_SERVICES; rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; apdu_len = BACNET_STATUS_ERROR; break; } } } else { object_index = Binary_Value_Instance_To_Index(rpdata->object_instance); if (rpdata->array_index <= BACNET_MAX_PRIORITY) { if (Binary_Value_Level[object_index][rpdata->array_index] == BINARY_NULL) apdu_len = encode_application_null(&apdu[apdu_len]); else { present_value = Binary_Value_Level[object_index] [rpdata->array_index]; apdu_len = encode_application_enumerated(&apdu[apdu_len], present_value); } } else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } } break; case PROP_RELINQUISH_DEFAULT: present_value = RELINQUISH_DEFAULT; apdu_len = encode_application_enumerated(&apdu[0], present_value); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) && (rpdata->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; }
int Analog_Value_Event_Information( unsigned index, BACNET_GET_EVENT_INFORMATION_DATA * getevent_data) { bool IsNotAckedTransitions; bool IsActiveEvent; int i; /* check index */ if (index < MAX_ANALOG_VALUES) { /* Event_State not equal to NORMAL */ IsActiveEvent = (AV_Descr[index].Event_State != EVENT_STATE_NORMAL); /* Acked_Transitions property, which has at least one of the bits (TO-OFFNORMAL, TO-FAULT, TONORMAL) set to FALSE. */ IsNotAckedTransitions = (AV_Descr[index].Acked_Transitions[TRANSITION_TO_OFFNORMAL]. bIsAcked == false) | (AV_Descr[index].Acked_Transitions[TRANSITION_TO_FAULT]. bIsAcked == false) | (AV_Descr[index].Acked_Transitions[TRANSITION_TO_NORMAL]. bIsAcked == false); } else return -1; /* end of list */ if ((IsActiveEvent) || (IsNotAckedTransitions)) { /* Object Identifier */ getevent_data->objectIdentifier.type = OBJECT_ANALOG_VALUE; getevent_data->objectIdentifier.instance = Analog_Value_Index_To_Instance(index); /* Event State */ getevent_data->eventState = AV_Descr[index].Event_State; /* Acknowledged Transitions */ bitstring_init(&getevent_data->acknowledgedTransitions); bitstring_set_bit(&getevent_data->acknowledgedTransitions, TRANSITION_TO_OFFNORMAL, AV_Descr[index].Acked_Transitions[TRANSITION_TO_OFFNORMAL]. bIsAcked); bitstring_set_bit(&getevent_data->acknowledgedTransitions, TRANSITION_TO_FAULT, AV_Descr[index].Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked); bitstring_set_bit(&getevent_data->acknowledgedTransitions, TRANSITION_TO_NORMAL, AV_Descr[index].Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked); /* Event Time Stamps */ for (i = 0; i < 3; i++) { getevent_data->eventTimeStamps[i].tag = TIME_STAMP_DATETIME; getevent_data->eventTimeStamps[i].value.dateTime = AV_Descr[index].Event_Time_Stamps[i]; } /* Notify Type */ getevent_data->notifyType = AV_Descr[index].Notify_Type; /* Event Enable */ bitstring_init(&getevent_data->eventEnable); bitstring_set_bit(&getevent_data->eventEnable, TRANSITION_TO_OFFNORMAL, (AV_Descr[index]. Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) ? true : false); bitstring_set_bit(&getevent_data->eventEnable, TRANSITION_TO_FAULT, (AV_Descr[index]. Event_Enable & EVENT_ENABLE_TO_FAULT) ? true : false); bitstring_set_bit(&getevent_data->eventEnable, TRANSITION_TO_NORMAL, (AV_Descr[index]. Event_Enable & EVENT_ENABLE_TO_NORMAL) ? true : false); /* Event Priorities */ Notification_Class_Get_Priorities(AV_Descr[index].Notification_Class, getevent_data->eventPriorities); return 1; /* active event */ } else return 0; /* no active event at this index */ }
/* 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; }
/** * ReadProperty handler for this object. For the given ReadProperty * data, the application_data is loaded or the error flags are set. * * @param rpdata - ReadProperty data, including requested data and * data for the reply, or error response. * * @return number of APDU bytes in the response, or * BACNET_STATUS_ERROR on error. */ int Lighting_Output_Read_Property( BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; BACNET_LIGHTING_COMMAND lighting_command; float real_value = (float) 1.414; uint32_t unsigned_value = 0; unsigned i = 0; bool state = false; uint8_t *apdu = NULL; const int *pRequired = NULL, *pOptional = NULL, *pProprietary = NULL; if ((rpdata == NULL) || (rpdata->application_data == NULL) || (rpdata->application_data_len == 0)) { return 0; } apdu = rpdata->application_data; switch (rpdata->object_property) { case PROP_OBJECT_IDENTIFIER: apdu_len = encode_application_object_id(&apdu[0], OBJECT_LIGHTING_OUTPUT, rpdata->object_instance); break; case PROP_OBJECT_NAME: Lighting_Output_Object_Name(rpdata->object_instance, &char_string); apdu_len = encode_application_character_string(&apdu[0], &char_string); break; case PROP_OBJECT_TYPE: apdu_len = encode_application_enumerated(&apdu[0], OBJECT_LIGHTING_OUTPUT); break; case PROP_PRESENT_VALUE: real_value = Lighting_Output_Present_Value(rpdata->object_instance); apdu_len = encode_application_real(&apdu[0], real_value); break; case PROP_TRACKING_VALUE: real_value = Lighting_Output_Tracking_Value(rpdata->object_instance); apdu_len = encode_application_real(&apdu[0], real_value); break; case PROP_LIGHTING_COMMAND: Lighting_Output_Lighting_Command( rpdata->object_instance, &lighting_command); apdu_len = lighting_command_encode(&apdu[0], &lighting_command); break; case PROP_IN_PROGRESS: unsigned_value = Lighting_Output_In_Progress( rpdata->object_instance); apdu_len = encode_application_enumerated(&apdu[0], unsigned_value); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); state = Lighting_Output_Out_Of_Service(rpdata->object_instance); bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, state); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); break; case PROP_OUT_OF_SERVICE: state = Lighting_Output_Out_Of_Service(rpdata->object_instance); apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_BLINK_WARN_ENABLE: state = Lighting_Output_Blink_Warn_Enable(rpdata->object_instance); apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_EGRESS_TIME: unsigned_value = Lighting_Output_Egress_Time( rpdata->object_instance); apdu_len = encode_application_unsigned(&apdu[0], unsigned_value); break; case PROP_EGRESS_ACTIVE: state = Lighting_Output_Egress_Active(rpdata->object_instance); apdu_len = encode_application_boolean(&apdu[0], state); break; case PROP_DEFAULT_FADE_TIME: unsigned_value = Lighting_Output_Default_Fade_Time( rpdata->object_instance); apdu_len = encode_application_unsigned(&apdu[0], unsigned_value); break; case PROP_DEFAULT_RAMP_RATE: real_value = Lighting_Output_Default_Ramp_Rate(rpdata->object_instance); apdu_len = encode_application_real(&apdu[0], real_value); break; case PROP_DEFAULT_STEP_INCREMENT: real_value = Lighting_Output_Default_Step_Increment(rpdata->object_instance); apdu_len = encode_application_real(&apdu[0], real_value); break; case PROP_PRIORITY_ARRAY: /* Array element zero is the number of elements in the array */ if (rpdata->array_index == 0) { apdu_len = encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); /* if no index was specified, then try to encode the entire list */ /* into one packet. */ } else if (rpdata->array_index == BACNET_ARRAY_ALL) { for (i = 1; i <= BACNET_MAX_PRIORITY; i++) { if (Lighting_Output_Priority_Active( rpdata->object_instance, i)) { real_value = Lighting_Output_Priority_Value( rpdata->object_instance, i); len = encode_application_real(&apdu[apdu_len], real_value); } else { len = encode_application_null(&apdu[apdu_len]); } /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) apdu_len += len; else { rpdata->error_class = ERROR_CLASS_SERVICES; rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; apdu_len = BACNET_STATUS_ERROR; break; } } } else { if (rpdata->array_index <= BACNET_MAX_PRIORITY) { if (Lighting_Output_Priority_Active( rpdata->object_instance, rpdata->array_index)) { real_value = Lighting_Output_Priority_Value( rpdata->object_instance, rpdata->array_index); len = encode_application_real(&apdu[apdu_len], real_value); } else { len = encode_application_null(&apdu[apdu_len]); } } else { rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = BACNET_STATUS_ERROR; } } break; case PROP_RELINQUISH_DEFAULT: real_value = Lighting_Output_Relinquish_Default( rpdata->object_instance); apdu_len = encode_application_real(&apdu[0], real_value); break; case PROP_LIGHTING_COMMAND_DEFAULT_PRIORITY: unsigned_value = Lighting_Output_Default_Priority( rpdata->object_instance); apdu_len = encode_application_unsigned(&apdu[0], unsigned_value); break; case PROP_PROPERTY_LIST: Lighting_Output_Property_Lists(&pRequired, &pOptional, &pProprietary); apdu_len = property_list_encode( rpdata, pRequired, pOptional, pProprietary); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; apdu_len = BACNET_STATUS_ERROR; break; } /* only array properties can have array options */ if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) && (rpdata->object_property != PROP_PROPERTY_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; }