int bacapp_encode_device_obj_ref( uint8_t * apdu, BACNET_DEVICE_OBJECT_REFERENCE * value) { int len; int apdu_len = 0; /* Device id is optional so see if needed * (set type to BACNET_NO_DEV_TYPE or something other than OBJECT_DEVICE to * omit */ if (value->deviceIndentifier.type == OBJECT_DEVICE) { len = encode_context_object_id(&apdu[apdu_len], 0, (int) value->deviceIndentifier.type, value->deviceIndentifier.instance); apdu_len += len; } len = encode_context_object_id(&apdu[apdu_len], 1, (int) value->objectIdentifier.type, value->objectIdentifier.instance); apdu_len += len; return apdu_len; }
int wpm_error_ack_encode_apdu( uint8_t * apdu, uint8_t invoke_id, BACNET_WRITE_PROPERTY_DATA * wp_data) { int len = 0; if (apdu) { apdu[len++] = PDU_TYPE_ERROR; apdu[len++] = invoke_id; apdu[len++] = SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE; len += encode_opening_tag(&apdu[len], 0); len += encode_application_enumerated(&apdu[len], wp_data->error_class); len += encode_application_enumerated(&apdu[len], wp_data->error_code); len += encode_closing_tag(&apdu[len], 0); len += encode_opening_tag(&apdu[len], 1); len += encode_context_object_id(&apdu[len], 0, wp_data->object_type, wp_data->object_instance); len += encode_context_enumerated(&apdu[len], 1, wp_data->object_property); if (wp_data->array_index != BACNET_ARRAY_ALL) len += encode_context_unsigned(&apdu[len], 2, wp_data->array_index); len += encode_closing_tag(&apdu[len], 1); } return len; }
int bacapp_encode_device_obj_property_ref( uint8_t * apdu, BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value) { int len; int apdu_len = 0; len = encode_context_object_id(&apdu[apdu_len], 0, (int) value->objectIdentifier.type, value->objectIdentifier.instance); apdu_len += len; len = encode_context_enumerated(&apdu[apdu_len], 1, value->propertyIdentifier); apdu_len += len; /* Array index is optional so check if needed before inserting */ if (value->arrayIndex != BACNET_ARRAY_ALL) { len = encode_context_unsigned(&apdu[apdu_len], 2, value->arrayIndex); apdu_len += len; } /* Likewise, device id is optional so see if needed * (set type to BACNET_NO_DEV_TYPE or something other than OBJECT_DEVICE to * omit */ if (value->deviceIndentifier.type == OBJECT_DEVICE) { len = encode_context_object_id(&apdu[apdu_len], 3, (int) value->deviceIndentifier.type, value->deviceIndentifier.instance); apdu_len += len; } return apdu_len; }
/* encode service */ int wp_encode_apdu( uint8_t * apdu, uint8_t invoke_id, BACNET_WRITE_PROPERTY_DATA * wpdata) { int apdu_len = 0; /* total length of the apdu, return value */ int len = 0; /* total length of the apdu, return value */ if (apdu) { apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_WRITE_PROPERTY; /* service choice */ apdu_len = 4; len = encode_context_object_id(&apdu[apdu_len], 0, wpdata->object_type, wpdata->object_instance); apdu_len += len; len = encode_context_enumerated(&apdu[apdu_len], 1, wpdata->object_property); apdu_len += len; /* optional array index; ALL is -1 which is assumed when missing */ if (wpdata->array_index != BACNET_ARRAY_ALL) { len = encode_context_unsigned(&apdu[apdu_len], 2, wpdata->array_index); apdu_len += len; } /* propertyValue */ len = encode_opening_tag(&apdu[apdu_len], 3); apdu_len += len; for (len = 0; len < wpdata->application_data_len; len++) { apdu[apdu_len + len] = wpdata->application_data[len]; } apdu_len += wpdata->application_data_len; len = encode_closing_tag(&apdu[apdu_len], 3); apdu_len += len; /* optional priority - 0 if not set, 1..16 if set */ if (wpdata->priority != BACNET_NO_PRIORITY) { len = encode_context_unsigned(&apdu[apdu_len], 4, wpdata->priority); apdu_len += len; } } return apdu_len; }
int wpm_encode_apdu_object_begin( uint8_t * apdu, BACNET_OBJECT_TYPE object_type, uint32_t object_instance) { int apdu_len = 0; /* total length of the apdu, return value */ if (apdu) { apdu_len = encode_context_object_id(&apdu[0], 0, object_type, object_instance); /* Tag 1: sequence of WriteAccessSpecification */ apdu_len += encode_opening_tag(&apdu[apdu_len], 1); } return apdu_len; }
int rpm_ack_encode_apdu_object_begin( uint8_t * apdu, BACNET_RPM_DATA * rpmdata) { int apdu_len = 0; /* total length of the apdu, return value */ if (apdu) { /* Tag 0: objectIdentifier */ apdu_len = encode_context_object_id(&apdu[0], 0, rpmdata->object_type, rpmdata->object_instance); /* Tag 1: listOfResults */ apdu_len += encode_opening_tag(&apdu[apdu_len], 1); } return apdu_len; }
/*************************************************** ** ** Encodes the service data part of Event Notification ** ****************************************************/ int alarm_ack_encode_service_request( uint8_t * apdu, BACNET_ALARM_ACK_DATA * data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ if (apdu) { len = encode_context_unsigned(&apdu[apdu_len], 0, data->ackProcessIdentifier); apdu_len += len; len = encode_context_object_id(&apdu[apdu_len], 1, (int) data->eventObjectIdentifier.type, data->eventObjectIdentifier.instance); apdu_len += len; len = encode_context_enumerated(&apdu[apdu_len], 2, data->eventStateAcked); apdu_len += len; len = bacapp_encode_context_timestamp(&apdu[apdu_len], 3, &data->eventTimeStamp); apdu_len += len; len = encode_context_character_string(&apdu[apdu_len], 4, &data->ackSource); apdu_len += len; len = bacapp_encode_context_timestamp(&apdu[apdu_len], 5, &data->ackTimeStamp); apdu_len += len; } return apdu_len; }
/* encode service */ int rp_encode_apdu( uint8_t * apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ if (apdu) { apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_READ_PROPERTY; /* service choice */ apdu_len = 4; if (rpdata->object_type <= BACNET_MAX_OBJECT) { /* check bounds so that we could create malformed messages for testing */ len = encode_context_object_id(&apdu[apdu_len], 0, rpdata->object_type, rpdata->object_instance); apdu_len += len; } if (rpdata->object_property <= 4194303) { /* check bounds so that we could create malformed messages for testing */ len = encode_context_enumerated(&apdu[apdu_len], 1, rpdata->object_property); apdu_len += len; } /* optional array index */ if (rpdata->array_index != BACNET_ARRAY_ALL) { len = encode_context_unsigned(&apdu[apdu_len], 2, rpdata->array_index); apdu_len += len; } } return apdu_len; }
int lso_encode_apdu( uint8_t * apdu, uint8_t invoke_id, BACNET_LSO_DATA * data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ if (apdu && data) { apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION; apdu_len = 4; /* tag 0 - requestingProcessId */ len = encode_context_unsigned(&apdu[apdu_len], 0, data->processId); apdu_len += len; /* tag 1 - requestingSource */ len = encode_context_character_string(&apdu[apdu_len], 1, &data->requestingSrc); apdu_len += len; /* Operation */ len = encode_context_enumerated(&apdu[apdu_len], 2, data->operation); apdu_len += len; /* Object ID */ len = encode_context_object_id(&apdu[apdu_len], 3, (int) data->targetObject.type, data->targetObject.instance); apdu_len += len; } return apdu_len; }
int whohas_encode_apdu( uint8_t * apdu, BACNET_WHO_HAS_DATA * data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ if (apdu && data) { apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; apdu[1] = SERVICE_UNCONFIRMED_WHO_HAS; /* service choice */ apdu_len = 2; /* optional limits - must be used as a pair */ if ((data->low_limit >= 0) && (data->low_limit <= BACNET_MAX_INSTANCE) && (data->high_limit >= 0) && (data->high_limit <= BACNET_MAX_INSTANCE)) { len = encode_context_unsigned(&apdu[apdu_len], 0, data->low_limit); apdu_len += len; len = encode_context_unsigned(&apdu[apdu_len], 1, data->high_limit); apdu_len += len; } if (data->object_name) { len = encode_context_character_string(&apdu[apdu_len], 3, &data->object.name); apdu_len += len; } else { len = encode_context_object_id(&apdu[apdu_len], 2, (int) data->object.identifier.type, data->object.identifier.instance); apdu_len += len; } } return apdu_len; }
/* alternate method to encode the ack without extra buffer */ int rp_ack_encode_apdu_init( uint8_t * apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA * rpdata) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ if (apdu) { apdu[0] = PDU_TYPE_COMPLEX_ACK; /* complex ACK service */ apdu[1] = invoke_id; /* original invoke id from request */ apdu[2] = SERVICE_CONFIRMED_READ_PROPERTY; /* service choice */ apdu_len = 3; /* service ack follows */ len = encode_context_object_id(&apdu[apdu_len], 0, rpdata->object_type, rpdata->object_instance); apdu_len += len; len = encode_context_enumerated(&apdu[apdu_len], 1, rpdata->object_property); apdu_len += len; /* context 2 array index is optional */ if (rpdata->array_index != BACNET_ARRAY_ALL) { len = encode_context_unsigned(&apdu[apdu_len], 2, rpdata->array_index); apdu_len += len; } len = encode_opening_tag(&apdu[apdu_len], 3); apdu_len += len; } return apdu_len; }
static int cov_encode_subscription( uint8_t * apdu, int max_apdu, BACNET_COV_SUBSCRIPTION * cov_subscription) { int len = 0; int apdu_len = 0; BACNET_OCTET_STRING octet_string; /* FIXME: unused parameter */ max_apdu = max_apdu; /* Recipient [0] BACnetRecipientProcess - opening */ len = encode_opening_tag(&apdu[apdu_len], 0); apdu_len += len; /* recipient [0] BACnetRecipient - opening */ len = encode_opening_tag(&apdu[apdu_len], 0); apdu_len += len; /* CHOICE - address [1] BACnetAddress - opening */ len = encode_opening_tag(&apdu[apdu_len], 1); apdu_len += len; /* network-number Unsigned16, */ /* -- A value of 0 indicates the local network */ len = encode_application_unsigned(&apdu[apdu_len], cov_subscription->dest.net); apdu_len += len; /* mac-address OCTET STRING */ /* -- A string of length 0 indicates a broadcast */ if (cov_subscription->dest.net) { octetstring_init(&octet_string, &cov_subscription->dest.adr[0], cov_subscription->dest.len); } else { octetstring_init(&octet_string, &cov_subscription->dest.mac[0], cov_subscription->dest.mac_len); } len = encode_application_octet_string(&apdu[apdu_len], &octet_string); apdu_len += len; /* CHOICE - address [1] BACnetAddress - closing */ len = encode_closing_tag(&apdu[apdu_len], 1); apdu_len += len; /* recipient [0] BACnetRecipient - closing */ len = encode_closing_tag(&apdu[apdu_len], 0); apdu_len += len; /* processIdentifier [1] Unsigned32 */ len = encode_context_unsigned(&apdu[apdu_len], 1, cov_subscription->subscriberProcessIdentifier); apdu_len += len; /* Recipient [0] BACnetRecipientProcess - closing */ len = encode_closing_tag(&apdu[apdu_len], 0); apdu_len += len; /* MonitoredPropertyReference [1] BACnetObjectPropertyReference, */ len = encode_opening_tag(&apdu[apdu_len], 1); apdu_len += len; /* objectIdentifier [0] */ len = encode_context_object_id(&apdu[apdu_len], 0, cov_subscription->monitoredObjectIdentifier.type, cov_subscription->monitoredObjectIdentifier.instance); apdu_len += len; /* propertyIdentifier [1] */ /* FIXME: we are monitoring 2 properties! How to encode? */ len = encode_context_enumerated(&apdu[apdu_len], 1, PROP_PRESENT_VALUE); apdu_len += len; /* MonitoredPropertyReference [1] - closing */ len = encode_closing_tag(&apdu[apdu_len], 1); apdu_len += len; /* IssueConfirmedNotifications [2] BOOLEAN, */ len = encode_context_boolean(&apdu[apdu_len], 2, cov_subscription->flag.issueConfirmedNotifications); apdu_len += len; /* TimeRemaining [3] Unsigned, */ len = encode_context_unsigned(&apdu[apdu_len], 3, cov_subscription->lifetime); apdu_len += len; return apdu_len; }
/** Encode an RPM request, to be sent. * * @param apdu [in,out] Buffer to hold encoded bytes. * @param max_apdu [in] Length of apdu buffer. * @param invoke_id [in] The Invoke ID to use for this message. * @param read_access_data [in] The RPM data to be requested. * @return Length of encoded bytes, or 0 on failure. */ int rpm_encode_apdu( uint8_t * apdu, size_t max_apdu, uint8_t invoke_id, BACNET_READ_ACCESS_DATA * read_access_data) { int apdu_len = 0; /* total length of the apdu, return value */ int len = 0; /* length of the data */ BACNET_READ_ACCESS_DATA *rpm_object; /* current object */ uint8_t apdu_temp[16]; /* temp for data before copy */ BACNET_PROPERTY_REFERENCE *rpm_property; /* current property */ len = rpm_encode_apdu_init(&apdu_temp[0], invoke_id); len = (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len, (size_t) len, (size_t) max_apdu); if (len == 0) { return 0; } apdu_len += len; rpm_object = read_access_data; while (rpm_object) { len = encode_context_object_id(&apdu_temp[0], 0, rpm_object->object_type, rpm_object->object_instance); len = (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len, (size_t) len, (size_t) max_apdu); if (len == 0) { return 0; } apdu_len += len; /* Tag 1: sequence of ReadAccessSpecification */ len = encode_opening_tag(&apdu_temp[0], 1); len = (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len, (size_t) len, (size_t) max_apdu); if (len == 0) { return 0; } apdu_len += len; rpm_property = rpm_object->listOfProperties; while (rpm_property) { /* stuff as many properties into it as APDU length will allow */ len = encode_context_enumerated(&apdu_temp[0], 0, rpm_property->propertyIdentifier); len = (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len, (size_t) len, (size_t) max_apdu); if (len == 0) { return 0; } apdu_len += len; /* optional array index */ if (rpm_property->propertyArrayIndex != BACNET_ARRAY_ALL) { len = encode_context_unsigned(&apdu_temp[0], 1, rpm_property->propertyArrayIndex); len = (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len, (size_t) len, (size_t) max_apdu); if (len == 0) { return 0; } apdu_len += len; } rpm_property = rpm_property->next; } len = encode_closing_tag(&apdu_temp[0], 1); len = (int) memcopy(&apdu[0], &apdu_temp[0], (size_t) apdu_len, (size_t) len, (size_t) max_apdu); if (len == 0) { return 0; } apdu_len += len; rpm_object = rpm_object->next; } 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; }