/** * @file * @brief BACnet property state encode and decode functions * @author Steve Karg * @author John Minack * @date 2008 * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */ #include #include "bacnet/bacdcode.h" #include "bacnet/npdu.h" #include "bacnet/timestamp.h" #include "bacnet/bacpropstates.h" /** * @brief Decodes BACnetPropertyState from bytes into a data structure * * BACnetPropertyStates ::= CHOICE { * -- This production represents the possible datatypes for properties that * -- have discrete or enumerated values. The choice shall be consistent with * -- the datatype of the property referenced in the Event Enrollment Object. * boolean-value [0] BOOLEAN, * binary-value [1] BACnetBinaryPV, * ... * extended-value [63] Unsigned32, * -- example-one [256] BACnetExampleTypeOne, * -- example-two [257] BACnetExampleTypeTwo, * ... * } * -- Tag values greater than 254 are not encoded as ASN context tags. * -- In these cases, the tag value is multiplied by 100000 and is added * -- to the enumeration value and the sum is encoded using context tag 63, * -- the extended-value choice. * -- Tag values 0-63 are reserved for definition by ASHRAE. * -- Tag values of 64-254 may be used by others to * -- accommodate vendor specific properties that have discrete * -- or enumerated values, subject to the constraints * -- described in Clause 23. * * @param apdu - buffer of data to be decoded * @param apdu_size - number of bytes in the buffer * @param value - decoded value, if decoded * * @return number of bytes decoded, or #BACNET_STATUS_ERROR (-1) if malformed */ int bacapp_property_state_decode( const uint8_t *apdu, uint32_t apdu_size, BACNET_PROPERTY_STATE *value) { BACNET_TAG tag = { 0 }; uint32_t enum_value = 0; int32_t integer_value = 0; int apdu_len = 0; int len = 0; len = bacnet_tag_decode(apdu, apdu_size, &tag); if (len <= 0) { return BACNET_STATUS_ERROR; } if (!tag.context) { return BACNET_STATUS_ERROR; } apdu_len += len; if (value) { value->tag = (BACNET_PROPERTY_STATES)tag.number; } if (tag.number == PROP_STATE_BOOLEAN_VALUE) { if (tag.len_value_type != 1) { return BACNET_STATUS_ERROR; } if (value) { value->state.booleanValue = decode_context_boolean(&apdu[apdu_len]); apdu_len++; } } else if (tag.number == PROP_STATE_INTEGER_VALUE) { len = bacnet_signed_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, &integer_value); if (len <= 0) { return BACNET_STATUS_ERROR; } apdu_len += len; if (value) { value->state.integerValue = integer_value; } } else { len = bacnet_enumerated_decode( &apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type, &enum_value); if (len <= 0) { return BACNET_STATUS_ERROR; } apdu_len += len; if (!value) { return apdu_len; } switch (value->tag) { case PROP_STATE_BINARY_VALUE: value->state.binaryValue = (BACNET_BINARY_PV)enum_value; break; case PROP_STATE_EVENT_TYPE: value->state.eventType = (BACNET_EVENT_TYPE)enum_value; break; case PROP_STATE_POLARITY: value->state.polarity = (BACNET_POLARITY)enum_value; break; case PROP_STATE_PROGRAM_CHANGE: value->state.programChange = (BACNET_PROGRAM_REQUEST)enum_value; break; case PROP_STATE_PROGRAM_STATE: value->state.programState = (BACNET_PROGRAM_STATE)enum_value; break; case PROP_STATE_REASON_FOR_HALT: value->state.programError = (BACNET_PROGRAM_ERROR)enum_value; break; case PROP_STATE_RELIABILITY: value->state.reliability = (BACNET_RELIABILITY)enum_value; break; case PROP_STATE_EVENT_STATE: value->state.state = (BACNET_EVENT_STATE)enum_value; break; case PROP_STATE_SYSTEM_STATUS: value->state.systemStatus = (BACNET_DEVICE_STATUS)enum_value; break; case PROP_STATE_UNITS: value->state.units = (BACNET_ENGINEERING_UNITS)enum_value; break; case PROP_STATE_UNSIGNED_VALUE: value->state.unsignedValue = (BACNET_UNSIGNED_INTEGER)enum_value; break; case PROP_STATE_LIFE_SAFETY_MODE: value->state.lifeSafetyMode = (BACNET_LIFE_SAFETY_MODE)enum_value; break; case PROP_STATE_LIFE_SAFETY_STATE: value->state.lifeSafetyState = (BACNET_LIFE_SAFETY_STATE)enum_value; break; case PROP_STATE_RESTART_REASON: value->state.restartReason = (BACNET_RESTART_REASON)enum_value; break; case PROP_STATE_DOOR_ALARM_STATE: value->state.doorAlarmState = (BACNET_DOOR_ALARM_STATE)enum_value; break; case PROP_STATE_ACTION: value->state.action = (BACNET_ACTION)enum_value; break; case PROP_STATE_DOOR_SECURED_STATUS: value->state.doorSecuredStatus = (BACNET_DOOR_SECURED_STATUS)enum_value; break; case PROP_STATE_DOOR_STATUS: value->state.doorStatus = (BACNET_DOOR_STATUS)enum_value; break; case PROP_STATE_DOOR_VALUE: value->state.doorValue = (BACNET_DOOR_VALUE)enum_value; break; case PROP_STATE_FILE_ACCESS_METHOD: value->state.fileAccessMethod = (BACNET_FILE_ACCESS_METHOD)enum_value; break; case PROP_STATE_LOCK_STATUS: value->state.lockStatus = (BACNET_LOCK_STATUS)enum_value; break; case PROP_STATE_LIFE_SAFETY_OPERATION: value->state.lifeSafetyOperation = (BACNET_LIFE_SAFETY_OPERATION)enum_value; break; case PROP_STATE_MAINTENANCE: value->state.maintenance = (BACNET_MAINTENANCE)enum_value; break; case PROP_STATE_NODE_TYPE: value->state.nodeType = (BACNET_NODE_TYPE)enum_value; break; case PROP_STATE_NOTIFY_TYPE: value->state.notifyType = (BACNET_NOTIFY_TYPE)enum_value; break; case PROP_STATE_SECURITY_LEVEL: value->state.securityLevel = (BACNET_SECURITY_LEVEL)enum_value; break; case PROP_STATE_SHED_STATE: value->state.shedState = (BACNET_SHED_STATE)enum_value; break; case PROP_STATE_SILENCED_STATE: value->state.silencedState = (BACNET_SILENCED_STATE)enum_value; break; case PROP_STATE_ACCESS_EVENT: value->state.accessEvent = (BACNET_ACCESS_EVENT)enum_value; break; case PROP_STATE_ZONE_OCCUPANCY_STATE: value->state.zoneOccupancyState = (BACNET_ACCESS_ZONE_OCCUPANCY_STATE)enum_value; break; case PROP_STATE_ACCESS_CRED_DISABLE_REASON: value->state.accessCredDisableReason = (BACNET_ACCESS_CREDENTIAL_DISABLE_REASON)enum_value; break; case PROP_STATE_ACCESS_CRED_DISABLE: value->state.accessCredDisable = (BACNET_ACCESS_CREDENTIAL_DISABLE)enum_value; break; case PROP_STATE_AUTHENTICATION_STATUS: value->state.authenticationStatus = (BACNET_AUTHENTICATION_STATUS)enum_value; break; case PROP_STATE_BACKUP_STATE: value->state.backupState = (BACNET_BACKUP_STATE)enum_value; break; case PROP_STATE_WRITE_STATUS: value->state.writeStatus = (BACNET_WRITE_STATUS)enum_value; break; case PROP_STATE_LIGHTING_IN_PROGRESS: value->state.lightingInProgress = (BACNET_LIGHTING_IN_PROGRESS)enum_value; break; case PROP_STATE_LIGHTING_OPERATION: value->state.lightingOperation = (BACNET_LIGHTING_OPERATION)enum_value; break; case PROP_STATE_LIGHTING_TRANSITION: value->state.lightingTransition = (BACNET_LIGHTING_TRANSITION)enum_value; break; case PROP_STATE_BINARY_LIGHTING_VALUE: value->state.binaryLightingValue = (BACNET_BINARY_LIGHTING_PV)enum_value; break; case PROP_STATE_TIMER_STATE: value->state.timerState = (BACNET_TIMER_STATE)enum_value; break; case PROP_STATE_TIMER_TRANSITION: value->state.timerTransition = (BACNET_TIMER_TRANSITION)enum_value; break; case PROP_STATE_BACNET_IP_MODE: value->state.bacnetIPMode = (BACNET_IP_MODE)enum_value; break; case PROP_STATE_NETWORK_PORT_COMMAND: value->state.networkPortCommand = (BACNET_PORT_COMMAND)enum_value; break; case PROP_STATE_NETWORK_TYPE: value->state.networkType = (BACNET_PORT_TYPE)enum_value; break; case PROP_STATE_NETWORK_NUMBER_QUALITY: value->state.networkNumberQuality = (BACNET_PORT_QUALITY)enum_value; break; case PROP_STATE_ESCALATOR_OPERATION_DIRECTION: value->state.escalatorOperationDirection = (BACNET_ESCALATOR_OPERATION_DIRECTION)enum_value; break; case PROP_STATE_ESCALATOR_FAULT: value->state.escalatorFault = (BACNET_ESCALATOR_FAULT)enum_value; break; case PROP_STATE_ESCALATOR_MODE: value->state.escalatorMode = (BACNET_ESCALATOR_MODE)enum_value; break; case PROP_STATE_LIFT_CAR_DIRECTION: value->state.liftCarDirection = (BACNET_LIFT_CAR_DIRECTION)enum_value; break; case PROP_STATE_LIFT_CAR_DOOR_COMMAND: value->state.liftCarDoorCommand = (BACNET_LIFT_CAR_DOOR_COMMAND)enum_value; break; case PROP_STATE_LIFT_CAR_DRIVE_STATUS: value->state.liftCarDriveStatus = (BACNET_LIFT_CAR_DRIVE_STATUS)enum_value; break; case PROP_STATE_LIFT_CAR_MODE: value->state.liftCarMode = (BACNET_LIFT_CAR_MODE)enum_value; break; case PROP_STATE_LIFT_GROUP_MODE: value->state.liftGroupMode = (BACNET_LIFT_GROUP_MODE)enum_value; break; case PROP_STATE_LIFT_FAULT: value->state.liftFault = (BACNET_LIFT_FAULT)enum_value; break; case PROP_STATE_PROTOCOL_LEVEL: value->state.protocolLevel = (BACNET_PROTOCOL_LEVEL)enum_value; break; case PROP_STATE_AUDIT_LEVEL: value->state.auditLevel = (BACNET_AUDIT_LEVEL)enum_value; break; case PROP_STATE_AUDIT_OPERATION: value->state.auditOperation = (BACNET_AUDIT_OPERATION)enum_value; break; case PROP_STATE_EXTENDED_VALUE: value->state.extendedValue = enum_value; break; default: break; } } return apdu_len; } int bacapp_decode_property_state( const uint8_t *apdu, BACNET_PROPERTY_STATE *value) { return bacapp_property_state_decode(apdu, MAX_APDU, value); } int bacapp_decode_context_property_state( const uint8_t *apdu, uint8_t tag_number, BACNET_PROPERTY_STATE *value) { int len = 0; int section_length; if (decode_is_opening_tag_number(&apdu[len], tag_number)) { len++; section_length = bacapp_decode_property_state(&apdu[len], value); if (section_length == -1) { len = -1; } else { len += section_length; if (decode_is_closing_tag_number(&apdu[len], tag_number)) { len++; } else { len = -1; } } } else { len = -1; } return len; } /** * @brief Encode the BACnetPropertyState * @param apdu Pointer to the buffer for encoding into, or NULL for length * @param value Pointer to the value used for encoding * @return number of bytes encoded, or zero if unable to encode */ int bacapp_encode_property_state( uint8_t *apdu, const BACNET_PROPERTY_STATE *value) { int len = 0; /* length of each encoding */ if (value) { switch (value->tag) { case PROP_STATE_BOOLEAN_VALUE: len = encode_context_boolean( apdu, value->tag, value->state.booleanValue); break; case PROP_STATE_BINARY_VALUE: len = encode_context_enumerated( apdu, value->tag, value->state.binaryValue); break; case PROP_STATE_EVENT_TYPE: len = encode_context_enumerated( apdu, value->tag, value->state.eventType); break; case PROP_STATE_POLARITY: len = encode_context_enumerated( apdu, value->tag, value->state.polarity); break; case PROP_STATE_PROGRAM_CHANGE: len = encode_context_enumerated( apdu, value->tag, value->state.programChange); break; case PROP_STATE_PROGRAM_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.programState); break; case PROP_STATE_REASON_FOR_HALT: len = encode_context_enumerated( apdu, value->tag, value->state.programError); break; case PROP_STATE_RELIABILITY: len = encode_context_enumerated( apdu, value->tag, value->state.reliability); break; case PROP_STATE_EVENT_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.state); break; case PROP_STATE_SYSTEM_STATUS: len = encode_context_enumerated( apdu, value->tag, value->state.systemStatus); break; case PROP_STATE_UNITS: len = encode_context_enumerated( apdu, value->tag, value->state.units); break; case PROP_STATE_UNSIGNED_VALUE: len = encode_context_unsigned( apdu, value->tag, value->state.unsignedValue); break; case PROP_STATE_LIFE_SAFETY_MODE: len = encode_context_enumerated( apdu, value->tag, value->state.lifeSafetyMode); break; case PROP_STATE_LIFE_SAFETY_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.lifeSafetyState); break; case PROP_STATE_RESTART_REASON: len = encode_context_enumerated( apdu, value->tag, value->state.restartReason); break; case PROP_STATE_DOOR_ALARM_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.doorAlarmState); break; case PROP_STATE_ACTION: len = encode_context_enumerated( apdu, value->tag, value->state.action); break; case PROP_STATE_DOOR_SECURED_STATUS: len = encode_context_enumerated( apdu, value->tag, value->state.doorSecuredStatus); break; case PROP_STATE_DOOR_STATUS: len = encode_context_enumerated( apdu, value->tag, value->state.doorStatus); break; case PROP_STATE_DOOR_VALUE: len = encode_context_enumerated( apdu, value->tag, value->state.doorValue); break; case PROP_STATE_FILE_ACCESS_METHOD: len = encode_context_enumerated( apdu, value->tag, value->state.fileAccessMethod); break; case PROP_STATE_LOCK_STATUS: len = encode_context_enumerated( apdu, value->tag, value->state.lockStatus); break; case PROP_STATE_LIFE_SAFETY_OPERATION: len = encode_context_enumerated( apdu, value->tag, value->state.lifeSafetyOperation); break; case PROP_STATE_MAINTENANCE: len = encode_context_enumerated( apdu, value->tag, value->state.maintenance); break; case PROP_STATE_NODE_TYPE: len = encode_context_enumerated( apdu, value->tag, value->state.nodeType); break; case PROP_STATE_NOTIFY_TYPE: len = encode_context_enumerated( apdu, value->tag, value->state.notifyType); break; case PROP_STATE_SECURITY_LEVEL: len = encode_context_enumerated( apdu, value->tag, value->state.securityLevel); break; case PROP_STATE_SHED_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.shedState); break; case PROP_STATE_SILENCED_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.silencedState); break; case PROP_STATE_ACCESS_EVENT: len = encode_context_enumerated( apdu, value->tag, value->state.accessEvent); break; case PROP_STATE_ZONE_OCCUPANCY_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.zoneOccupancyState); break; case PROP_STATE_ACCESS_CRED_DISABLE_REASON: len = encode_context_enumerated( apdu, value->tag, value->state.accessCredDisableReason); break; case PROP_STATE_ACCESS_CRED_DISABLE: len = encode_context_enumerated( apdu, value->tag, value->state.accessCredDisable); break; case PROP_STATE_AUTHENTICATION_STATUS: len = encode_context_enumerated( apdu, value->tag, value->state.authenticationStatus); break; case PROP_STATE_BACKUP_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.backupState); break; case PROP_STATE_WRITE_STATUS: len = encode_context_enumerated( apdu, value->tag, value->state.writeStatus); break; case PROP_STATE_LIGHTING_IN_PROGRESS: len = encode_context_enumerated( apdu, value->tag, value->state.lightingInProgress); break; case PROP_STATE_LIGHTING_OPERATION: len = encode_context_enumerated( apdu, value->tag, value->state.lightingOperation); break; case PROP_STATE_LIGHTING_TRANSITION: len = encode_context_enumerated( apdu, value->tag, value->state.lightingTransition); break; case PROP_STATE_INTEGER_VALUE: len = encode_context_signed( apdu, value->tag, value->state.integerValue); break; case PROP_STATE_BINARY_LIGHTING_VALUE: len = encode_context_enumerated( apdu, value->tag, value->state.binaryLightingValue); break; case PROP_STATE_TIMER_STATE: len = encode_context_enumerated( apdu, value->tag, value->state.timerState); break; case PROP_STATE_TIMER_TRANSITION: len = encode_context_enumerated( apdu, value->tag, value->state.timerTransition); break; case PROP_STATE_BACNET_IP_MODE: len = encode_context_enumerated( apdu, value->tag, value->state.bacnetIPMode); break; case PROP_STATE_NETWORK_PORT_COMMAND: len = encode_context_enumerated( apdu, value->tag, value->state.networkPortCommand); break; case PROP_STATE_NETWORK_TYPE: len = encode_context_enumerated( apdu, value->tag, value->state.networkType); break; case PROP_STATE_NETWORK_NUMBER_QUALITY: len = encode_context_enumerated( apdu, value->tag, value->state.networkNumberQuality); break; case PROP_STATE_ESCALATOR_OPERATION_DIRECTION: len = encode_context_enumerated( apdu, value->tag, value->state.escalatorOperationDirection); break; case PROP_STATE_ESCALATOR_FAULT: len = encode_context_enumerated( apdu, value->tag, value->state.escalatorFault); break; case PROP_STATE_ESCALATOR_MODE: len = encode_context_enumerated( apdu, value->tag, value->state.escalatorMode); break; case PROP_STATE_LIFT_CAR_DIRECTION: len = encode_context_enumerated( apdu, value->tag, value->state.liftCarDirection); break; case PROP_STATE_LIFT_CAR_DOOR_COMMAND: len = encode_context_enumerated( apdu, value->tag, value->state.liftCarDoorCommand); break; case PROP_STATE_LIFT_CAR_DRIVE_STATUS: len = encode_context_enumerated( apdu, value->tag, value->state.liftCarDriveStatus); break; case PROP_STATE_LIFT_CAR_MODE: len = encode_context_enumerated( apdu, value->tag, value->state.liftCarMode); break; case PROP_STATE_LIFT_GROUP_MODE: len = encode_context_enumerated( apdu, value->tag, value->state.liftGroupMode); break; case PROP_STATE_LIFT_FAULT: len = encode_context_enumerated( apdu, value->tag, value->state.liftFault); break; case PROP_STATE_PROTOCOL_LEVEL: len = encode_context_enumerated( apdu, value->tag, value->state.protocolLevel); break; case PROP_STATE_AUDIT_LEVEL: len = encode_context_enumerated( apdu, value->tag, value->state.auditLevel); break; case PROP_STATE_AUDIT_OPERATION: len = encode_context_enumerated( apdu, value->tag, value->state.auditOperation); break; default: break; } } return len; }