-context specific decoders for all of the primitive times to go with the context specific encoders
-unconfirmed/confirmed EventNotificationRequest structure/encoder/decoder
-BACnetTimestamp structure/encoder/decoder
-BACnetPropertyStates structure/encoder/decoder
-BACnetDeviceObjectPropertyReference structure/encoder/decoder

Changes:
-decode_context_object_id::object_type changed to uint16_t
-explicit casts have been added to some functions to remove compiler warnings
-encode_bacnet_date::year behaviour has been changed slightly
This commit is contained in:
minack
2008-10-14 04:02:34 +00:00
parent 1dad528da8
commit 60ac0d0f8a
16 changed files with 3593 additions and 33 deletions
+56 -2
View File
@@ -107,17 +107,27 @@ extern "C" {
uint32_t len_value);
int encode_context_boolean(
uint8_t * apdu,
int tag_number,
uint8_t tag_number,
bool boolean_value);
bool decode_context_boolean(
uint8_t * apdu);
int decode_context_boolean2(
uint8_t * apdu,
uint8_t tag_number,
bool *boolean_value);
/* from clause 20.2.10 Encoding of a Bit String Value */
/* returns the number of apdu bytes consumed */
int decode_bitstring(
uint8_t * apdu,
uint32_t len_value,
BACNET_BIT_STRING * bit_string);
int decode_context_bitstring(
uint8_t * apdu,
uint8_t tag_number,
BACNET_BIT_STRING * bit_string);
/* returns the number of apdu bytes consumed */
int encode_bitstring(
uint8_t * apdu,
@@ -146,8 +156,15 @@ extern "C" {
/* returns the number of apdu bytes consumed */
int decode_object_id(
uint8_t * apdu,
int *object_type,
uint16_t * object_type,
uint32_t * instance);
int decode_context_object_id(
uint8_t * apdu,
uint8_t tag_number,
uint16_t *object_type,
uint32_t * instance);
int encode_bacnet_object_id(
uint8_t * apdu,
int object_type,
@@ -179,6 +196,10 @@ extern "C" {
uint8_t * apdu,
uint32_t len_value,
BACNET_OCTET_STRING * octet_string);
int decode_context_octet_string(
uint8_t * apdu,
uint8_t tag_number,
BACNET_OCTET_STRING * octet_string);
/* from clause 20.2.9 Encoding of a Character String Value */
@@ -198,6 +219,11 @@ extern "C" {
uint8_t * apdu,
uint32_t len_value,
BACNET_CHARACTER_STRING * char_string);
int decode_context_character_string(
uint8_t * apdu,
uint8_t tag_number,
BACNET_CHARACTER_STRING * char_string);
/* from clause 20.2.4 Encoding of an Unsigned Integer Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
@@ -216,6 +242,10 @@ extern "C" {
uint8_t * apdu,
uint32_t len_value,
uint32_t * value);
int decode_context_unsigned(
uint8_t * apdu,
uint8_t tag_number,
uint32_t * value);
/* from clause 20.2.5 Encoding of a Signed Integer Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
@@ -234,6 +264,11 @@ extern "C" {
uint8_t * apdu,
uint32_t len_value,
int32_t * value);
int decode_context_signed(
uint8_t * apdu,
uint8_t tag_number,
int32_t * value);
/* from clause 20.2.11 Encoding of an Enumerated Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
@@ -242,6 +277,10 @@ extern "C" {
uint8_t * apdu,
uint32_t len_value,
int *value);
int decode_context_enumerated(
uint8_t * apdu,
uint8_t tag_value,
int *value);
int encode_bacnet_enumerated(
uint8_t * apdu,
int value);
@@ -269,6 +308,14 @@ extern "C" {
uint8_t * apdu,
int tag_number,
BACNET_TIME * btime);
int decode_application_time(
uint8_t * apdu,
BACNET_TIME * btime);
int decode_context_bacnet_time(
uint8_t * apdu,
uint8_t tag_number,
BACNET_TIME * btime);
/* BACnet Date */
/* year = years since 1900 */
@@ -292,6 +339,13 @@ extern "C" {
int decode_date(
uint8_t * apdu,
BACNET_DATE * bdate);
int decode_application_date(
uint8_t * apdu,
BACNET_DATE * bdate);
int decode_context_date(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DATE * bdate);
/* from clause 20.1.2.4 max-segments-accepted */
/* and clause 20.1.2.5 max-APDU-length-accepted */
+76
View File
@@ -0,0 +1,76 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2006 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#ifndef _BAC_DEV_PROP_REF_H_
#define _BAC_DEV_PROP_REF_H_
typedef struct {
BACNET_OBJECT_ID objectIdentifier;
BACNET_PROPERTY_ID propertyIdentifier;
uint32_t arrayIndex;
BACNET_OBJECT_ID deviceIndentifier;
} BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bacapp_encode_device_obj_property_ref(
uint8_t * apdu,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value);
int bacapp_encode_context_device_obj_property_ref(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value);
int bacapp_decode_device_obj_property_ref(
uint8_t * apdu,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value);
int bacapp_decode_context_device_obj_property_ref(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif //_BAC_DEV_PROP_REF_H_
+105
View File
@@ -0,0 +1,105 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2006 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#ifndef _BAC_PROP_STATES_H_
#define _BAC_PROP_STATES_H_
#include "bacenum.h"
#include <stdint.h>
#include <stdbool.h>
#include "bacapp.h"
#include <time.h>
#include "timestamp.h"
typedef enum {
BOOLEAN_VALUE,
BINARY_VALUE,
EVENT_TYPE,
POLARITY,
PROGRAM_CHANGE,
PROGRAM_STATE,
REASON_FOR_HALT,
RELIABILITY,
STATE,
SYSTEM_STATUS,
UNITS,
UNSIGNED_VALUE,
LIFE_SAFETY_MODE,
LIFE_SAFETY_STATE,
} BACNET_PROPERTY_STATE_TYPE;
typedef struct {
BACNET_PROPERTY_STATE_TYPE tag;
union {
bool booleanValue;
BACNET_BINARY_PV binaryValue;
BACNET_EVENT_TYPE eventType;
BACNET_POLARITY polarity;
BACNET_PROGRAM_REQUEST programChange;
BACNET_PROGRAM_STATE programState;
BACNET_PROGRAM_ERROR programError;
BACNET_RELIABILITY reliability;
BACNET_EVENT_STATE state;
BACNET_DEVICE_STATUS systemStatus;
BACNET_ENGINEERING_UNITS units;
uint32_t unsignedValue;
BACNET_LIFE_SAFETY_MODE lifeSafetyMode;
BACNET_LIFE_SAFETY_STATE lifeSafetyState;
} state;
} BACNET_PROPERTY_STATE;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bacapp_decode_property_state(
uint8_t * apdu,
BACNET_PROPERTY_STATE * value);
int bacapp_decode_context_property_state(
uint8_t * apdu,
uint8_t tag_number,
BACNET_PROPERTY_STATE * value);
int bacapp_encode_property_state(
uint8_t * apdu,
BACNET_PROPERTY_STATE * value);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif // _BAC_PROP_STATES_H_
+5
View File
@@ -45,6 +45,11 @@ extern "C" {
int decode_real(
uint8_t * apdu,
float *real_value);
int decode_context_real(
uint8_t * apdu,
uint8_t tag_number,
float *real_value);
int encode_bacnet_real(
float value,
uint8_t * apdu);
+1 -1
View File
@@ -79,7 +79,7 @@ extern "C" {
uint8_t bitstring_bits_used(
BACNET_BIT_STRING * bit_string);
/* returns the number of bytes that a bit string is using */
int bitstring_bytes_used(
uint8_t bitstring_bytes_used(
BACNET_BIT_STRING * bit_string);
uint8_t bitstring_bits_capacity(
BACNET_BIT_STRING * bit_string);
+14
View File
@@ -138,6 +138,20 @@ extern "C" {
void datetime_time_wildcard_set(
BACNET_TIME * btime);
int bacapp_encode_context_datetime(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DATE_TIME * value);
int bacapp_decode_datetime(
uint8_t * apdu,
BACNET_DATE_TIME * value);
int bacapp_decode_context_datetime(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DATE_TIME * value);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+212
View File
@@ -0,0 +1,212 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2006 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#ifndef BACNET_EVENT_H_
#define BACNET_EVENT_H_
#include "bacenum.h"
#include <stdint.h>
#include <stdbool.h>
#include "bacapp.h"
#include "timestamp.h"
#include "bacpropstates.h"
#include "bacdevobjpropref.h"
typedef enum {
CHANGE_OF_VALUE_BITS,
CHANGE_OF_VALUE_REAL
} CHANGE_OF_VALUE_TYPE;
/*
** Based on UnconfirmedEventNotification-Request
*/
typedef struct BACnet_Event_Notification_Data {
uint32_t processIdentifier;
BACNET_OBJECT_ID initiatingObjectIdentifier;
BACNET_OBJECT_ID eventObjectIdentifier;
BACNET_TIMESTAMP timeStamp;
uint32_t notificationClass;
uint8_t priority;
BACNET_EVENT_TYPE eventType;
BACNET_CHARACTER_STRING* messageText; /* OPTIONAL - Set to NULL if not being used */
BACNET_NOTIFY_TYPE notifyType;
bool ackRequired;
BACNET_EVENT_STATE fromState;
BACNET_EVENT_STATE toState;
/*
** Each of these structures in the union maps to a particular eventtype
** Based on BACnetNotificationParameters
*/
union {
/*
** EVENT_CHANGE_OF_BITSTRING
*/
struct {
BACNET_BIT_STRING referencedBitString;
BACNET_BIT_STRING statusFlags;
} changeOfBitstring;
/*
** EVENT_CHANGE_OF_STATE
*/
struct {
BACNET_PROPERTY_STATE newState;
BACNET_BIT_STRING statusFlags;
} changeOfState;
/*
** EVENT_CHANGE_OF_VALUE
*/
struct {
union {
BACNET_BIT_STRING changedBits;
float changeValue;
} newValue;
CHANGE_OF_VALUE_TYPE tag;
BACNET_BIT_STRING statusFlags;
} changeOfValue;
/*
** EVENT_COMMAND_FAILURE
**
** Not Supported!
*/
/*
** EVENT_FLOATING_LIMIT
*/
struct {
float referenceValue;
BACNET_BIT_STRING statusFlags;
float setPointValue;
float errorLimit;
} floatingLimit;
/*
** EVENT_OUT_OF_RANGE
*/
struct {
float exceedingValue;
BACNET_BIT_STRING statusFlags;
float deadband;
float exceededLimit;
} outOfRange;
/*
** EVENT_CHANGE_OF_LIFE_SAFETY
*/
struct {
BACNET_LIFE_SAFETY_STATE newState;
BACNET_LIFE_SAFETY_MODE newMode;
BACNET_BIT_STRING statusFlags;
BACNET_LIFE_SAFETY_OPERATION operationExpected;
} changeOfLifeSafety;
/*
** EVENT_EXTENDED
**
** Not Supported!
*/
/*
** EVENT_BUFFER_READY
*/
struct {
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE bufferProperty;
uint32_t previousNotification;
uint32_t currentNotification;
} bufferReady;
/*
** EVENT_UNSIGNED_RANGE
*/
struct {
uint32_t exceedingValue;
BACNET_BIT_STRING statusFlags;
uint32_t exceededLimit;
} unsignedRange;
} notificationParams;
} BACNET_EVENT_NOTIFICATION_DATA;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/***************************************************
**
** Creates a Confirmed Event Notification APDU
**
****************************************************/
int cevent_notify_encode_apdu(
uint8_t * apdu,
uint8_t invoke_id,
BACNET_EVENT_NOTIFICATION_DATA * data);
/***************************************************
**
** Creates an Unconfirmed Event Notification APDU
**
****************************************************/
int uevent_notify_encode_apdu(
uint8_t * apdu,
BACNET_EVENT_NOTIFICATION_DATA * data);
/***************************************************
**
** Encodes the service data part of Event Notification
**
****************************************************/
int event_notify_encode_service_request(
uint8_t * apdu,
BACNET_EVENT_NOTIFICATION_DATA * data);
/***************************************************
**
** Decodes the service data part of Event Notification
**
****************************************************/
int event_notify_decode_service_request(
uint8_t * apdu,
unsigned apdu_len,
BACNET_EVENT_NOTIFICATION_DATA * data);
/***************************************************
**
** Sends an Unconfirmed Event Notifcation to a dest
**
****************************************************/
int uevent_notify_send(
uint8_t * buffer,
BACNET_EVENT_NOTIFICATION_DATA * data,
BACNET_ADDRESS *dest);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* BACNET_EVENT_H_ */
+44
View File
@@ -0,0 +1,44 @@
#ifndef _TIMESTAMP_H_
#define _TIMESTAMP_H_
#include "bacdcode.h"
typedef enum {
TIME_STAMP_TIME = 0,
TIME_STAMP_SEQUENCE = 1,
TIME_STAMP_DATETIME = 2,
} BACNET_TIMESTAMP_TAG;
typedef uint8_t TYPE_BACNET_TIMESTAMP_TYPE;
typedef struct {
TYPE_BACNET_TIMESTAMP_TYPE tag;
union {
BACNET_TIME time;
uint16_t sequenceNum;
BACNET_DATE_TIME dateTime;
} value;
} BACNET_TIMESTAMP;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int bacapp_encode_context_timestamp(
uint8_t * apdu,
uint8_t tag_number,
BACNET_TIMESTAMP * value);
int bacapp_decode_context_timestamp(
uint8_t * apdu,
uint8_t tag_number,
BACNET_TIMESTAMP * value);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+711 -25
View File
@@ -71,6 +71,24 @@
B'1110' reserved by ASHRAE
B'1111' reserved by ASHRAE
*/
/* Encoding of BACNET Length/Value/Type tag
From clause 20.2.1.3.1
B'000' interpreted as Value = FALSE if application class == BOOLEAN
B'001' interpreted as Value = TRUE if application class == BOOLEAN
B'000' interpreted as Length = 0 if application class != BOOLEAN
B'001' interpreted as Length = 1
B'010' interpreted as Length = 2
B'011' interpreted as Length = 3
B'100' interpreted as Length = 4
B'101' interpreted as Length > 4
B'110' interpreted as Type = Opening Tag
B'111' interpreted as Type = Closing Tag
*/
/* from clause 20.1.2.4 max-segments-accepted */
/* and clause 20.1.2.5 max-APDU-length-accepted */
/* returns the encoded octet */
@@ -285,7 +303,7 @@ int encode_closing_tag(
static bool decode_is_extended_tag_number(
uint8_t * apdu)
{
return ((apdu[0] & 0xF0) == 0xF0);
return (bool)((apdu[0] & 0xF0) == 0xF0);
}
/* from clause 20.2.1.3.2 Constructed Data */
@@ -293,7 +311,7 @@ static bool decode_is_extended_tag_number(
static bool decode_is_extended_value(
uint8_t * apdu)
{
return ((apdu[0] & 0x07) == 5);
return (bool)((apdu[0] & 0x07) == 5);
}
/* from clause 20.2.1.3.2 Constructed Data */
@@ -301,7 +319,7 @@ static bool decode_is_extended_value(
bool decode_is_context_specific(
uint8_t * apdu)
{
return ((apdu[0] & BIT3) == BIT3);
return (bool)((apdu[0] & BIT3) == BIT3);
}
int decode_tag_number(
@@ -319,7 +337,7 @@ int decode_tag_number(
len++;
} else {
if (tag_number) {
*tag_number = (apdu[0] >> 4);
*tag_number = (uint8_t)(apdu[0] >> 4);
}
}
@@ -329,7 +347,7 @@ int decode_tag_number(
bool decode_is_opening_tag(
uint8_t * apdu)
{
return ((apdu[0] & 0x07) == 6);
return (bool)((apdu[0] & 0x07) == 6);
}
/* from clause 20.2.1.3.2 Constructed Data */
@@ -337,7 +355,7 @@ bool decode_is_opening_tag(
bool decode_is_closing_tag(
uint8_t * apdu)
{
return ((apdu[0] & 0x07) == 7);
return (bool)((apdu[0] & 0x07) == 7);
}
/* from clause 20.2.1.3.2 Constructed Data */
@@ -398,10 +416,26 @@ bool decode_is_context_tag(
uint8_t my_tag_number = 0;
bool context_specific = false;
context_specific = decode_is_context_specific(apdu);
decode_tag_number(apdu, &my_tag_number);
return (context_specific && (my_tag_number == tag_number));
return (bool)(context_specific && (my_tag_number == tag_number));
}
bool decode_is_context_tag_with_length(
uint8_t * apdu,
uint8_t tag_number,
int * tag_length)
{
uint8_t my_tag_number = 0;
bool context_specific = false;
context_specific = decode_is_context_specific(apdu);
*tag_length = decode_tag_number(apdu, &my_tag_number);
return (bool)(context_specific && (my_tag_number == tag_number));
}
/* from clause 20.2.1.3.2 Constructed Data */
@@ -413,10 +447,10 @@ bool decode_is_opening_tag_number(
uint8_t my_tag_number = 0;
bool opening_tag = false;
opening_tag = ((apdu[0] & 0x07) == 6);
opening_tag = (bool)((apdu[0] & 0x07) == 6);
decode_tag_number(apdu, &my_tag_number);
return (opening_tag && (my_tag_number == tag_number));
return (bool)(opening_tag && (my_tag_number == tag_number));
}
/* from clause 20.2.1.3.2 Constructed Data */
@@ -428,10 +462,10 @@ bool decode_is_closing_tag_number(
uint8_t my_tag_number = 0;
bool closing_tag = false;
closing_tag = ((apdu[0] & 0x07) == 7);
closing_tag = (bool)((apdu[0] & 0x07) == 7);
decode_tag_number(apdu, &my_tag_number);
return (closing_tag && (my_tag_number == tag_number));
return (bool)(closing_tag && (my_tag_number == tag_number));
}
/* from clause 20.2.3 Encoding of a Boolean Value */
@@ -456,13 +490,13 @@ int encode_application_boolean(
/* context tagged is encoded differently */
int encode_context_boolean(
uint8_t * apdu,
int tag_number,
uint8_t tag_number,
bool boolean_value)
{
int len = 0; /* return value */
len = encode_tag(&apdu[0], (uint8_t) tag_number, true, 1);
apdu[len] = boolean_value ? 1 : 0;
apdu[len] = (bool)(boolean_value ? 1 : 0);
len++;
return len;
@@ -480,6 +514,29 @@ bool decode_context_boolean(
return boolean_value;
}
int decode_context_boolean2(
uint8_t * apdu,
uint8_t tag_number,
bool *boolean_value)
{
int len = 0;
if (decode_is_context_tag_with_length(&apdu[len], tag_number, &len)) {
if (apdu[len]) {
*boolean_value = true;
}
else
{
*boolean_value = false;
}
len++;
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.3 Encoding of a Boolean Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
@@ -567,7 +624,7 @@ int decode_bitstring(
bitstring_set_octet(bit_string, (uint8_t) i,
byte_reverse_bits(apdu[len++]));
}
unused_bits = apdu[0] & 0x07;
unused_bits = (uint8_t)(apdu[0] & 0x07);
bitstring_set_bits_used(bit_string, (uint8_t) bytes_used,
unused_bits);
}
@@ -576,6 +633,27 @@ int decode_bitstring(
return len;
}
int decode_context_bitstring(
uint8_t * apdu,
uint8_t tag_number,
BACNET_BIT_STRING * bit_string)
{
uint32_t len_value;
int len = 0;
if (decode_is_context_tag(&apdu[len], tag_number)) {
len += decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value);
len += decode_bitstring(&apdu[len], len_value, bit_string);
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.10 Encoding of a Bit String Value */
/* returns the number of apdu bytes consumed */
int encode_bitstring(
@@ -593,9 +671,9 @@ int encode_bitstring(
} else {
used_bytes = bitstring_bytes_used(bit_string);
remaining_used_bits =
bitstring_bits_used(bit_string) - ((used_bytes - 1) * 8);
(uint8_t)(bitstring_bits_used(bit_string) - ((used_bytes - 1) * 8));
/* number of unused bits in the subsequent final octet */
apdu[len++] = 8 - remaining_used_bits;
apdu[len++] = (uint8_t)(8 - remaining_used_bits);
for (i = 0; i < used_bytes; i++) {
apdu[len++] = byte_reverse_bits(bitstring_octet(bit_string, i));
}
@@ -650,12 +728,30 @@ int decode_object_id(
int len = 0;
len = decode_unsigned32(apdu, &value);
*object_type = ((value >> BACNET_INSTANCE_BITS) & BACNET_MAX_OBJECT);
*object_type = (uint16_t)(((value >> BACNET_INSTANCE_BITS) & BACNET_MAX_OBJECT));
*instance = (value & BACNET_MAX_INSTANCE);
return len;
}
int decode_context_object_id(
uint8_t * apdu,
uint8_t tag_number,
uint16_t * object_type,
uint32_t * instance)
{
int len = 0;
if (decode_is_context_tag_with_length(&apdu[len], tag_number, &len)) {
len += decode_object_id(&apdu[len], object_type, instance);
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.14 Encoding of an Object Identifier Value */
/* returns the number of apdu bytes consumed */
int encode_bacnet_object_id(
@@ -807,6 +903,34 @@ int decode_octet_string(
return len;
}
int decode_context_octet_string(
uint8_t * apdu,
uint8_t tag_number,
BACNET_OCTET_STRING * octet_string)
{
int len = 0; /* return value */
bool status = false;
uint32_t len_value = 0;
if (decode_is_context_tag(&apdu[len], tag_number))
{
len += decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value);
status = octetstring_init(octet_string, &apdu[len], len_value);
if (status) {
len += len_value;
}
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.9 Encoding of a Character String Value */
/* returns the number of apdu bytes consumed */
int encode_bacnet_character_string(
@@ -889,6 +1013,35 @@ int decode_character_string(
return len;
}
int decode_context_character_string(
uint8_t * apdu,
uint8_t tag_number,
BACNET_CHARACTER_STRING * char_string)
{
int len = 0; /* return value */
bool status = false;
uint32_t len_value = 0;
if (decode_is_context_tag(&apdu[len], tag_number))
{
len += decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value);
status =
characterstring_init(char_string, apdu[len], (char *) &apdu[len+1],
len_value - 1);
if (status) {
len += len_value;
}
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.4 Encoding of an Unsigned Integer Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
@@ -923,6 +1076,27 @@ int decode_unsigned(
return len_value;
}
int decode_context_unsigned(
uint8_t * apdu,
uint8_t tag_number,
uint32_t * value)
{
uint32_t len_value;
int len = 0;
if (decode_is_context_tag(&apdu[len], tag_number)) {
len += decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value);
len += decode_unsigned(&apdu[len], len_value, value);
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.4 Encoding of an Unsigned Integer Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
@@ -1002,6 +1176,27 @@ int decode_enumerated(
return len;
}
int decode_context_enumerated(
uint8_t * apdu,
uint8_t tag_value,
int *value)
{
int len = 0;
uint8_t tag_number;
uint32_t len_value;
if (decode_is_context_tag(&apdu[len], tag_value)) {
len += decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value);
len += decode_enumerated(&apdu[len], len_value, value);
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.11 Encoding of an Enumerated Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
@@ -1081,6 +1276,26 @@ int decode_signed(
return len_value;
}
int decode_context_signed(
uint8_t * apdu,
uint8_t tag_number,
int32_t * value)
{
uint32_t len_value;
int len = 0;
if (decode_is_context_tag(&apdu[len], tag_number)) {
len += decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value);
len += decode_signed(&apdu[len], len_value, value);
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.5 Encoding of a Signed Integer Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
@@ -1281,6 +1496,45 @@ int decode_bacnet_time(
return 4;
}
int decode_application_time(
uint8_t * apdu,
BACNET_TIME * btime)
{
int len = 0;
uint8_t tag_number;
decode_tag_number(&apdu[len], &tag_number);
if ( tag_number == BACNET_APPLICATION_TAG_TIME )
{
len++;
len += decode_bacnet_time(&apdu[len], btime);
}
else
{
len = -1;
}
return len;
}
int decode_context_bacnet_time(
uint8_t * apdu,
uint8_t tag_number,
BACNET_TIME * btime)
{
int len = 0;
if (decode_is_context_tag_with_length(&apdu[len], tag_number, &len)) {
len += decode_bacnet_time(&apdu[len], btime);
}
else
{
len = -1;
}
return len;
}
/* BACnet Date */
/* year = years since 1900 */
/* month 1=Jan */
@@ -1295,14 +1549,23 @@ int encode_bacnet_date(
BACNET_DATE * bdate)
{
/* allow 2 digit years */
if (bdate->year < 1900) {
if (bdate->year <= 38) {
bdate->year += 2000;
} else {
bdate->year += 1900;
}
if (bdate->year >= 1900) {
apdu[0] = (uint8_t)(bdate->year - 1900);
}
apdu[0] = bdate->year - 1900;
else if ( bdate->year < 0x100 )
{
apdu[0] = (uint8_t)bdate->year;
}
else
{
/*
** Don't try and guess what the user meant here. Just fail
*/
return -1;
}
apdu[1] = bdate->month;
apdu[2] = bdate->day;
apdu[3] = bdate->wday;
@@ -1310,6 +1573,7 @@ int encode_bacnet_date(
return 4;
}
/* from clause 20.2.12 Encoding of a Date Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
@@ -1353,7 +1617,7 @@ int decode_date(
uint8_t * apdu,
BACNET_DATE * bdate)
{
bdate->year = apdu[0] + 1900;
bdate->year = (uint16_t)(apdu[0] + 1900);
bdate->month = apdu[1];
bdate->day = apdu[2];
bdate->wday = apdu[3];
@@ -1361,6 +1625,45 @@ int decode_date(
return 4;
}
int decode_application_date(
uint8_t * apdu,
BACNET_DATE * bdate)
{
int len = 0;
uint8_t tag_number;
decode_tag_number(&apdu[len], &tag_number);
if ( tag_number == BACNET_APPLICATION_TAG_DATE )
{
len++;
len += decode_date(&apdu[len], bdate);
}
else
{
len = -1;
}
return len;
}
int decode_context_date(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DATE * bdate)
{
int len = 0;
if (decode_is_context_tag_with_length(&apdu[len], tag_number, &len)) {
len += decode_date(&apdu[len], bdate);
}
else
{
len = -1;
}
return len;
}
/* returns the number of apdu bytes consumed */
int encode_simple_ack(
uint8_t * apdu,
@@ -1990,6 +2293,358 @@ void testBACDCodeBitString(
}
}
void testUnsignedContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
/* 32 bit number */
uint32_t in = 0xdeadbeef;
uint32_t out;
outLen2 = decode_context_unsigned(apdu, 9, &out);
in = 0xdeadbeef;
inLen = encode_context_unsigned(apdu, 10, in);
outLen = decode_context_unsigned(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
ct_test(pTest, outLen2 == -1);
/* 16 bit number */
in = 0xdead;
inLen = encode_context_unsigned(apdu, 10, in);
outLen = decode_context_unsigned(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 8 bit number */
in = 0xde;
inLen = encode_context_unsigned(apdu, 10, in);
outLen = decode_context_unsigned(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 4 bit number */
in = 0xd;
inLen = encode_context_unsigned(apdu, 10, in);
outLen = decode_context_unsigned(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 2 bit number */
in = 0x2;
inLen = encode_context_unsigned(apdu, 10, in);
outLen = decode_context_unsigned(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
}
void testSignedContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
/* 32 bit number */
int32_t in = 0xdeadbeef;
int32_t out;
outLen2 = decode_context_signed(apdu, 9, &out);
in = 0xdeadbeef;
inLen = encode_context_signed(apdu, 10, in);
outLen = decode_context_signed(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
ct_test(pTest, outLen2 == -1);
/* 16 bit number */
in = 0xdead;
inLen = encode_context_signed(apdu, 10, in);
outLen = decode_context_signed(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 8 bit number */
in = 0xde;
inLen = encode_context_signed(apdu, 10, in);
outLen = decode_context_signed(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 4 bit number */
in = 0xd;
inLen = encode_context_signed(apdu, 10, in);
outLen = decode_context_signed(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 2 bit number */
in = 0x2;
inLen = encode_context_signed(apdu, 10, in);
outLen = decode_context_signed(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
}
void testEnumeratedContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
/* 32 bit number */
int32_t in = 0xdeadbeef;
int32_t out;
outLen2 = decode_context_enumerated(apdu, 9, &out);
in = 0xdeadbeef;
inLen = encode_context_enumerated(apdu, 10, in);
outLen = decode_context_enumerated(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
ct_test(pTest, outLen2 == -1);
/* 16 bit number */
in = 0xdead;
inLen = encode_context_enumerated(apdu, 10, in);
outLen = decode_context_enumerated(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 8 bit number */
in = 0xde;
inLen = encode_context_enumerated(apdu, 10, in);
outLen = decode_context_enumerated(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 4 bit number */
in = 0xd;
inLen = encode_context_enumerated(apdu, 10, in);
outLen = decode_context_enumerated(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
/* 2 bit number */
in = 0x2;
inLen = encode_context_enumerated(apdu, 10, in);
outLen = decode_context_enumerated(apdu, 10, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
}
void testFloatContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
/* 32 bit number */
float in;
float out;
in = 0.1234f;
inLen = encode_context_real(apdu, 10, in);
outLen = decode_context_real(apdu, 10, &out);
outLen2 = decode_context_real(apdu, 9, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
ct_test(pTest, outLen2 == -1);
in = 0.0f;
inLen = encode_context_real(apdu, 10, in);
outLen = decode_context_real(apdu, 10, &out);
outLen2 = decode_context_real(apdu, 9, &out);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in == out);
}
void testObjectIDContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
/* 32 bit number */
uint16_t in_type;
uint32_t in_id;
uint16_t out_type;
uint32_t out_id;
in_type = 0xde;
in_id = 0xbeef;
inLen = encode_context_object_id(apdu, 10, in_type, in_id);
outLen = decode_context_object_id(apdu, 10, &out_type, &out_id);
outLen2 = decode_context_object_id(apdu, 9, &out_type, &out_id);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in_type == out_type);
ct_test(pTest, in_id == out_id);
ct_test(pTest, outLen2 == -1);
}
void testCharacterStringContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
BACNET_CHARACTER_STRING in;
BACNET_CHARACTER_STRING out;
characterstring_init_ansi(&in, "This is a test");
inLen = encode_context_character_string(apdu, 10, &in);
outLen= decode_context_character_string(apdu, 10, &out);
outLen2= decode_context_character_string(apdu, 9, &out);
ct_test(pTest, outLen2 == -1);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in.length == out.length);
ct_test(pTest, in.encoding == out.encoding);
ct_test(pTest, strcmp(in.value, out.value) == 0);
}
void testBitStringContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
BACNET_BIT_STRING in;
BACNET_BIT_STRING out;
bitstring_init(&in);
bitstring_set_bit(&in, 1, true);
bitstring_set_bit(&in, 3, true);
bitstring_set_bit(&in, 6, true);
bitstring_set_bit(&in, 10, false);
bitstring_set_bit(&in, 11, true);
bitstring_set_bit(&in, 12, false);
inLen = encode_context_bitstring(apdu, 10, &in);
outLen= decode_context_bitstring(apdu, 10, &out);
outLen2= decode_context_bitstring(apdu, 9, &out);
ct_test(pTest, outLen2 == -1);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in.bits_used == out.bits_used);
ct_test(pTest, memcmp(in.value, out.value, MAX_BITSTRING_BYTES) == 0);
}
void testOctetStringContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
BACNET_OCTET_STRING in;
BACNET_OCTET_STRING out;
uint8_t initData[] = {0xde,0xad,0xbe,0xef};
octetstring_init(&in, initData, sizeof(initData));
inLen = encode_context_octet_string(apdu, 10, &in);
outLen= decode_context_octet_string(apdu, 10, &out);
outLen2= decode_context_octet_string(apdu, 9, &out);
ct_test(pTest, outLen2 == -1);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in.length == out.length);
ct_test(pTest, memcmp(in.value, out.value, MAX_APDU - 6) == 0);
}
void testTimeContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
BACNET_TIME in;
BACNET_TIME out;
in.hour = 10;
in.hundredths = 20;
in.min = 30;
in.sec = 40;
inLen = encode_context_time(apdu, 10, &in);
outLen= decode_context_bacnet_time(apdu, 10, &out);
outLen2= decode_context_bacnet_time(apdu, 9, &out);
ct_test(pTest, outLen2 == -1);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in.hour == out.hour);
ct_test(pTest, in.hundredths == out.hundredths);
ct_test(pTest, in.min == out.min);
ct_test(pTest, in.sec == out.sec);
}
void testDateContextDecodes(Test * pTest)
{
uint8_t apdu[MAX_APDU];
int inLen;
int outLen;
int outLen2;
BACNET_DATE in;
BACNET_DATE out;
in.day = 3;
in.month = 10;
in.wday = 5;
in.year = 1945;
inLen = encode_context_date(apdu, 10, &in);
outLen= decode_context_date(apdu, 10, &out);
outLen2= decode_context_date(apdu, 9, &out);
ct_test(pTest, outLen2 == -1);
ct_test(pTest, inLen == outLen);
ct_test(pTest, in.day == out.day);
ct_test(pTest, in.month == out.month);
ct_test(pTest, in.wday == out.wday);
ct_test(pTest, in.year == out.year);
}
#ifdef TEST_DECODE
int main(
void)
@@ -2023,6 +2678,37 @@ int main(
assert(rc);
rc = ct_addTestFunction(pTest, testBACDCodeBitString);
assert(rc);
rc = ct_addTestFunction(pTest, testUnsignedContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testSignedContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testEnumeratedContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testCharacterStringContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testFloatContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testObjectIDContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testBitStringContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testTimeContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testDateContextDecodes);
assert(rc);
rc = ct_addTestFunction(pTest, testOctetStringContextDecodes);
assert(rc);
/* configure output */
ct_setStream(pTest, stdout);
ct_run(pTest);
+209
View File
@@ -0,0 +1,209 @@
#include <assert.h>
#include "bacdcode.h"
#include "npdu.h"
#include "device.h"
#include "datalink.h"
#include "timestamp.h"
#include "bacdevobjpropref.h"
int bacapp_encode_context_device_obj_property_ref(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value)
{
int len;
int apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
len = bacapp_encode_device_obj_property_ref(&apdu[apdu_len], value);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
return apdu_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,
value->objectIdentifier.type,
value->objectIdentifier.instance);
apdu_len += len;
len = encode_context_enumerated(&apdu[apdu_len], 1,
value->propertyIdentifier);
apdu_len += len;
if ( value->arrayIndex > 0 )
{
len = encode_context_unsigned(&apdu[apdu_len], 2,
value->arrayIndex);
apdu_len += len;
}
len = encode_context_object_id(&apdu[apdu_len], 3,
value->deviceIndentifier.type,
value->deviceIndentifier.instance);
apdu_len += len;
return apdu_len;
}
int bacapp_decode_device_obj_property_ref(
uint8_t * apdu,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value)
{
int len;
int apdu_len = 0;
if ( -1 == ( len = decode_context_object_id(&apdu[apdu_len], 0,
&value->objectIdentifier.type,
&value->objectIdentifier.instance)) )
{
return -1;
}
apdu_len += len;
if ( -1 == ( len = decode_context_enumerated(&apdu[apdu_len], 1,
&value->propertyIdentifier)))
{
return -1;
}
apdu_len += len;
if ( decode_is_context_tag(&apdu[apdu_len], 2 ))
{
if ( -1 == ( len = decode_context_unsigned(&apdu[apdu_len], 2,
&value->arrayIndex)))
{
return -1;
}
apdu_len += len;
}
else
{
value->arrayIndex = 0;
}
if ( decode_is_context_tag(&apdu[apdu_len], 3 ))
{
if ( -1 == ( len = decode_context_object_id(&apdu[apdu_len], 3,
&value->deviceIndentifier.type,
&value->deviceIndentifier.instance)) )
{
return -1;
}
apdu_len += len;
}
else
{
value->deviceIndentifier.instance = 0;
value->deviceIndentifier.type = 0;
}
return apdu_len;
}
int bacapp_decode_context_device_obj_property_ref(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value)
{
int len = 0;
int section_length;
if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
len++;
section_length = bacapp_decode_device_obj_property_ref(
&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;
}
#ifdef TEST
void testDevIdPropRef(
Test * pTest)
{
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE inData;
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE outData;
uint8_t buffer[MAX_APDU];
int inLen;
int outLen;
inData.objectIdentifier.instance = 0x1234;
inData.objectIdentifier.type = 15;
inData.propertyIdentifier = 25;
inData.arrayIndex = 0x5678;
inData.deviceIndentifier.instance = 0x4343;
inData.deviceIndentifier.type = 28;
inLen = bacapp_encode_device_obj_property_ref(buffer, &inData);
outLen = bacapp_decode_device_obj_property_ref(buffer, &outData);
ct_test(pTest, outLen == inLen);
ct_test(pTest, inData.objectIdentifier.instance == outData.objectIdentifier.instance);
ct_test(pTest, inData.objectIdentifier.type == outData.objectIdentifier.type);
ct_test(pTest, inData.propertyIdentifier == outData.propertyIdentifier);
ct_test(pTest, inData.arrayIndex == outData.arrayIndex);
ct_test(pTest, inData.deviceIndentifier.instance == outData.deviceIndentifier.instance);
ct_test(pTest, inData.deviceIndentifier.type == outData.deviceIndentifier.type);
}
#ifdef TEST_DEV_ID_PROP_REF
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Prop Ref", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testDevIdPropRef);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif // TEST_DEV_ID_PROP_REF
#endif // TEST
+369
View File
@@ -0,0 +1,369 @@
#include <assert.h>
#include "bacdcode.h"
#include "npdu.h"
#include "device.h"
#include "datalink.h"
#include "timestamp.h"
#include "bacpropstates.h"
int bacapp_decode_property_state(
uint8_t * apdu,
BACNET_PROPERTY_STATE * value)
{
int len = 0;
uint32_t len_value_type;
int section_length;
section_length =
decode_tag_number_and_value(&apdu[len], (uint8_t*)&value->tag,
&len_value_type);
if ( -1 == section_length )
{
return -1;
}
len += section_length;
switch(value->tag)
{
case BOOLEAN_VALUE:
value->state.booleanValue = decode_boolean(len_value_type);
break;
case BINARY_VALUE:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.binaryValue)))
{
return -1;
}
break;
case EVENT_TYPE:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.eventType)))
{
return -1;
}
break;
case POLARITY:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.polarity)))
{
return -1;
}
break;
case PROGRAM_CHANGE:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.programChange)))
{
return -1;
}
break;
case PROGRAM_STATE:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.programState)))
{
return -1;
}
break;
case REASON_FOR_HALT:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.programError)))
{
return -1;
}
break;
case RELIABILITY:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.reliability)))
{
return -1;
}
break;
case STATE:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.state)))
{
return -1;
}
break;
case SYSTEM_STATUS:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.systemStatus)))
{
return -1;
}
break;
case UNITS:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.units)))
{
return -1;
}
break;
case UNSIGNED_VALUE:
if ( -1 == ( section_length = decode_unsigned(&apdu[len], len_value_type, &value->state.unsignedValue)))
{
return -1;
}
break;
case LIFE_SAFETY_MODE:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.lifeSafetyMode)))
{
return -1;
}
break;
case LIFE_SAFETY_STATE:
if ( -1 == ( section_length = decode_enumerated(&apdu[len], len_value_type, &value->state.lifeSafetyState)))
{
return -1;
}
break;
default:
return -1;
}
len += section_length;
return len;
}
int bacapp_decode_context_property_state(
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;
}
int bacapp_encode_property_state(
uint8_t * apdu,
BACNET_PROPERTY_STATE * value)
{
int len = 0; /* length of each encoding */
if (value && apdu) {
switch(value->tag)
{
case BOOLEAN_VALUE:
len = encode_context_boolean(&apdu[0], 0, value->state.booleanValue);
break;
case BINARY_VALUE:
len = encode_context_enumerated(&apdu[0], 1, value->state.binaryValue);
break;
case EVENT_TYPE:
len = encode_context_enumerated(&apdu[0], 2, value->state.eventType);
break;
case POLARITY:
len = encode_context_enumerated(&apdu[0], 3, value->state.polarity);
break;
case PROGRAM_CHANGE:
len = encode_context_enumerated(&apdu[0], 4, value->state.programChange);
break;
case PROGRAM_STATE:
len = encode_context_enumerated(&apdu[0], 5, value->state.programState);
break;
case REASON_FOR_HALT:
len = encode_context_enumerated(&apdu[0], 6, value->state.programError);
break;
case RELIABILITY:
len = encode_context_enumerated(&apdu[0], 7, value->state.reliability);
break;
case STATE:
len = encode_context_enumerated(&apdu[0], 8, value->state.state);
break;
case SYSTEM_STATUS:
len = encode_context_enumerated(&apdu[0], 9, value->state.systemStatus);
break;
case UNITS:
len = encode_context_enumerated(&apdu[0], 10, value->state.units);
break;
case UNSIGNED_VALUE:
len = encode_context_unsigned(&apdu[0], 11, value->state.unsignedValue);
break;
case LIFE_SAFETY_MODE:
len = encode_context_enumerated(&apdu[0], 12, value->state.lifeSafetyMode);
break;
case LIFE_SAFETY_STATE:
len = encode_context_enumerated(&apdu[0], 13, value->state.lifeSafetyState);
break;
default:
assert(0);
break;
}
}
return len;
}
#ifdef TEST
void testPropStates(
Test * pTest)
{
BACNET_PROPERTY_STATE inData;
BACNET_PROPERTY_STATE outData;
uint8_t appMsg[MAX_APDU];
int inLen;
int outLen;
inData.tag = BOOLEAN_VALUE;
inData.state.booleanValue = true;
inLen = bacapp_encode_property_state(appMsg, &inData);
memset(&outData, 0, sizeof(outData));
outLen = bacapp_decode_property_state(appMsg, &outData);
ct_test(pTest, outLen == inLen);
ct_test(pTest, inData.tag == outData.tag );
ct_test(pTest, inData.state.booleanValue == outData.state.booleanValue );
/****************
*****************
****************/
inData.tag = BINARY_VALUE;
inData.state.binaryValue = BINARY_ACTIVE;
inLen = bacapp_encode_property_state(appMsg, &inData);
memset(&outData, 0, sizeof(outData));
outLen = bacapp_decode_property_state(appMsg, &outData);
ct_test(pTest, outLen == inLen);
ct_test(pTest, inData.tag == outData.tag );
ct_test(pTest, inData.state.binaryValue == outData.state.binaryValue );
/****************
*****************
****************/
inData.tag = EVENT_TYPE;
inData.state.eventType = EVENT_BUFFER_READY;
inLen = bacapp_encode_property_state(appMsg, &inData);
memset(&outData, 0, sizeof(outData));
outLen = bacapp_decode_property_state(appMsg, &outData);
ct_test(pTest, outLen == inLen);
ct_test(pTest, inData.tag == outData.tag );
ct_test(pTest, inData.state.eventType == outData.state.eventType );
/****************
*****************
****************/
inData.tag = POLARITY;
inData.state.polarity = POLARITY_REVERSE;
inLen = bacapp_encode_property_state(appMsg, &inData);
memset(&outData, 0, sizeof(outData));
outLen = bacapp_decode_property_state(appMsg, &outData);
ct_test(pTest, outLen == inLen);
ct_test(pTest, inData.tag == outData.tag );
ct_test(pTest, inData.state.polarity == outData.state.polarity );
/****************
*****************
****************/
inData.tag = PROGRAM_CHANGE;
inData.state.programChange = PROGRAM_REQUEST_RESTART;
inLen = bacapp_encode_property_state(appMsg, &inData);
memset(&outData, 0, sizeof(outData));
outLen = bacapp_decode_property_state(appMsg, &outData);
ct_test(pTest, outLen == inLen);
ct_test(pTest, inData.tag == outData.tag );
ct_test(pTest, inData.state.programChange == outData.state.programChange );
/****************
*****************
****************/
inData.tag = UNSIGNED_VALUE;
inData.state.unsignedValue = 0xdeadbeef;
inLen = bacapp_encode_property_state(appMsg, &inData);
memset(&outData, 0, sizeof(outData));
outLen = bacapp_decode_property_state(appMsg, &outData);
ct_test(pTest, outLen == inLen);
ct_test(pTest, inData.tag == outData.tag );
ct_test(pTest, inData.state.unsignedValue == outData.state.unsignedValue );
}
#ifdef TEST_PROP_STATES
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Event", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testPropStates);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif // TEST_PROP_STATES
#endif // TEST
+19
View File
@@ -76,6 +76,25 @@ int decode_real(
return 4;
}
int decode_context_real(
uint8_t * apdu,
uint8_t tag_number,
float *real_value)
{
uint32_t len_value;
int len = 0;
if (decode_is_context_tag(&apdu[len], tag_number)) {
len += decode_tag_number_and_value(&apdu[len], &tag_number,
&len_value);
len += decode_real(&apdu[len], real_value);
}
else
{
len = -1;
}
return len;
}
/* from clause 20.2.6 Encoding of a Real Number Value */
/* returns the number of apdu bytes consumed */
int encode_bacnet_real(
+2 -2
View File
@@ -96,10 +96,10 @@ uint8_t bitstring_bits_used(
}
/* returns the number of bytes that a bit string is using */
int bitstring_bytes_used(
uint8_t bitstring_bytes_used(
BACNET_BIT_STRING * bit_string)
{
int len = 0; /* return value */
uint8_t len = 0; /* return value */
uint8_t used_bytes = 0;
uint8_t last_bit = 0;
+134 -3
View File
@@ -38,6 +38,7 @@
#include <stdlib.h>
#include <ctype.h>
#include "datetime.h"
#include "bacdcode.h"
/* BACnet Date */
/* year = years since 1900 */
@@ -52,6 +53,7 @@
time or date may be interpreted as "any" or "don't care"
*/
static bool is_leap_year(
uint16_t year)
{
@@ -73,7 +75,7 @@ static uint8_t month_days(
if ((month == 2) && is_leap_year(year))
return 29;
else if (month >= 1 && month <= 12)
return month_days[month];
return (uint8_t)month_days[month];
else
return 0;
}
@@ -128,7 +130,7 @@ static void days_since_epoch_into_ymd(
month++;
}
day += ((uint8_t) days);
day = (uint8_t) (day + days);
if (pYear)
*pYear = year;
@@ -148,7 +150,7 @@ static uint8_t day_of_week(
uint8_t month,
uint8_t day)
{
return ((uint8_t) (days_since_epoch(year, month, day) % 7) + 1);
return (uint8_t) ((days_since_epoch(year, month, day) % 7) + 1);
}
/* if the date1 is the same as date2, return is 0
@@ -428,6 +430,93 @@ void datetime_wildcard_set(
}
}
int bacapp_encode_context_datetime(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DATE_TIME * value)
{
int len = 0;
int apdu_len = 0;
if ( apdu && value )
{
len = encode_opening_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
len = encode_application_date(&apdu[apdu_len], &value->date);
apdu_len += len;
len = encode_application_time(&apdu[apdu_len], &value->time);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
}
return apdu_len;
}
int bacapp_decode_datetime(
uint8_t * apdu,
BACNET_DATE_TIME * value)
{
int len = 0;
int section_len;
if ( -1 == ( section_len = decode_application_date(&apdu[len], &value->date) ) )
{
return -1;
}
len += section_len;
if ( -1 == ( section_len = decode_application_time(&apdu[len], &value->time) ) )
{
return -1;
}
len += section_len;
return len;
}
int bacapp_decode_context_datetime(
uint8_t * apdu,
uint8_t tag_number,
BACNET_DATE_TIME * value)
{
int apdu_len = 0;
int len;
if (decode_is_opening_tag_number(&apdu[apdu_len], tag_number)) {
apdu_len++;
}
else
{
return -1;
}
if ( -1 == (len = bacapp_decode_datetime(&apdu[apdu_len], value)))
{
return -1;
}
else
{
apdu_len += len;
}
if (decode_is_closing_tag_number(&apdu[apdu_len], tag_number))
{
apdu_len++;
}
else
{
return -1;
}
return apdu_len;
}
#ifdef TEST
#include <assert.h>
@@ -744,6 +833,43 @@ void testBACnetDayOfWeek(
ct_test(pTest, dow == 3);
}
void testDatetimeCodec(
Test * pTest)
{
uint8_t apdu[MAX_APDU];
BACNET_DATE_TIME datetimeIn;
BACNET_DATE_TIME datetimeOut;
int inLen;
int outLen;
datetimeIn.date.day = 1;
datetimeIn.date.month = 2;
datetimeIn.date.wday = 3;
datetimeIn.date.year = 1904;
datetimeIn.time.hour = 5;
datetimeIn.time.min = 6;
datetimeIn.time.sec = 7;
datetimeIn.time.hundredths = 8;
inLen = bacapp_encode_context_datetime(apdu, 10, &datetimeIn);
outLen = bacapp_decode_context_datetime(apdu, 10, &datetimeOut);
ct_test(pTest, inLen == outLen );
ct_test(pTest, datetimeIn.date.day == datetimeOut.date.day);
ct_test(pTest, datetimeIn.date.month == datetimeOut.date.month);
ct_test(pTest, datetimeIn.date.wday == datetimeOut.date.wday);
ct_test(pTest, datetimeIn.date.year == datetimeOut.date.year);
ct_test(pTest, datetimeIn.time.hour == datetimeOut.time.hour);
ct_test(pTest, datetimeIn.time.min == datetimeOut.time.min);
ct_test(pTest, datetimeIn.time.sec == datetimeOut.time.sec);
ct_test(pTest, datetimeIn.time.hundredths == datetimeOut.time.hundredths);
}
#ifdef TEST_DATE_TIME
int main(
void)
@@ -769,6 +895,8 @@ int main(
assert(rc);
rc = ct_addTestFunction(pTest, testBACnetDateTimeWildcard);
assert(rc);
rc = ct_addTestFunction(pTest, testDatetimeCodec);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
@@ -777,5 +905,8 @@ int main(
return 0;
}
#endif /* TEST_DATE_TIME */
#endif /* TEST */
File diff suppressed because it is too large Load Diff
+249
View File
@@ -0,0 +1,249 @@
#include "assert.h"
#include "timestamp.h"
int bacapp_encode_context_timestamp(
uint8_t * apdu,
uint8_t tag_number,
BACNET_TIMESTAMP * value)
{
int len = 0; /* length of each encoding */
int apdu_len = 0;
if (value && apdu) {
len = encode_opening_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
switch(value->tag)
{
case TIME_STAMP_TIME:
len = encode_context_time(&apdu[apdu_len], 0, &value->value.time);
break;
case TIME_STAMP_SEQUENCE:
len = encode_context_unsigned(&apdu[apdu_len], 1, value->value.sequenceNum);
break;
case TIME_STAMP_DATETIME:
len = bacapp_encode_context_datetime(&apdu[apdu_len], 2, &value->value.dateTime);
break;
default:
len = 0;
assert(0);
break;
}
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
}
return apdu_len;
}
int bacapp_decode_context_timestamp(
uint8_t * apdu,
uint8_t tag_number,
BACNET_TIMESTAMP * value)
{
int len = 0;
int section_len;
uint32_t len_value_type;
uint32_t sequenceNum;
if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
len++;
section_len =
decode_tag_number_and_value(&apdu[len], &value->tag,
&len_value_type);
if ( -1 == section_len )
{
return -1;
}
switch( value->tag )
{
case TIME_STAMP_TIME:
if ( (section_len = decode_context_bacnet_time(&apdu[len], TIME_STAMP_TIME, &value->value.time)) == -1 )
{
return -1;
}
else
{
len += section_len;
}
break;
case TIME_STAMP_SEQUENCE:
if ( (section_len = decode_context_unsigned(&apdu[len], TIME_STAMP_SEQUENCE, &sequenceNum)) == -1 )
{
return -1;
}
else
{
if ( sequenceNum <= 0xffff )
{
len += section_len;
value->value.sequenceNum = (uint16_t)sequenceNum;
}
else
{
return -1;
}
}
break;
case TIME_STAMP_DATETIME:
if ( (section_len = bacapp_decode_context_datetime(&apdu[len], TIME_STAMP_DATETIME, &value->value.dateTime)) == -1 )
{
return -1;
}
else
{
len += section_len;
}
break;
default:
return -1;
}
if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
len++;
}
else
{
return -1;
}
}
return len;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
void testTimestampSequence(
Test * pTest)
{
BACNET_TIMESTAMP testTimestampIn;
BACNET_TIMESTAMP testTimestampOut;
uint8_t buffer[MAX_APDU];
int inLen;
int outLen;
testTimestampIn.tag = TIME_STAMP_SEQUENCE;
testTimestampIn.value.sequenceNum = 0x1234;
memset(&testTimestampOut, 0, sizeof(testTimestampOut));
inLen = bacapp_encode_context_timestamp(buffer, 2, &testTimestampIn);
outLen = bacapp_decode_context_timestamp(buffer, 2, &testTimestampOut);
ct_test(pTest, inLen == outLen);
ct_test(pTest, testTimestampIn.tag == testTimestampOut.tag);
ct_test(pTest, testTimestampIn.value.sequenceNum == testTimestampOut.value.sequenceNum);
}
void testTimestampTime(
Test * pTest)
{
BACNET_TIMESTAMP testTimestampIn;
BACNET_TIMESTAMP testTimestampOut;
uint8_t buffer[MAX_APDU];
int inLen;
int outLen;
testTimestampIn.tag = TIME_STAMP_TIME;
testTimestampIn.value.time.hour = 1;
testTimestampIn.value.time.min = 2;
testTimestampIn.value.time.sec = 3;
testTimestampIn.value.time.hundredths = 4;
memset(&testTimestampOut, 0, sizeof(testTimestampOut));
inLen = bacapp_encode_context_timestamp(buffer, 2, &testTimestampIn);
outLen = bacapp_decode_context_timestamp(buffer, 2, &testTimestampOut);
ct_test(pTest, inLen == outLen);
ct_test(pTest, testTimestampIn.tag == testTimestampOut.tag);
ct_test(pTest, testTimestampIn.value.time.hour == testTimestampOut.value.time.hour);
ct_test(pTest, testTimestampIn.value.time.min == testTimestampOut.value.time.min);
ct_test(pTest, testTimestampIn.value.time.sec == testTimestampOut.value.time.sec);
ct_test(pTest, testTimestampIn.value.time.hundredths == testTimestampOut.value.time.hundredths);
}
void testTimestampTimeDate(
Test * pTest)
{
BACNET_TIMESTAMP testTimestampIn;
BACNET_TIMESTAMP testTimestampOut;
uint8_t buffer[MAX_APDU];
int inLen;
int outLen;
testTimestampIn.tag = TIME_STAMP_DATETIME;
testTimestampIn.value.dateTime.time.hour = 1;
testTimestampIn.value.dateTime.time.min = 2;
testTimestampIn.value.dateTime.time.sec = 3;
testTimestampIn.value.dateTime.time.hundredths = 4;
testTimestampIn.value.dateTime.date.year = 1901;
testTimestampIn.value.dateTime.date.month = 1;
testTimestampIn.value.dateTime.date.wday = 2;
testTimestampIn.value.dateTime.date.day = 3;
memset(&testTimestampOut, 0, sizeof(testTimestampOut));
inLen = bacapp_encode_context_timestamp(buffer, 2, &testTimestampIn);
outLen = bacapp_decode_context_timestamp(buffer, 2, &testTimestampOut);
ct_test(pTest, inLen == outLen);
ct_test(pTest, testTimestampIn.tag == testTimestampOut.tag);
ct_test(pTest, testTimestampIn.value.dateTime.time.hour == testTimestampOut.value.dateTime.time.hour);
ct_test(pTest, testTimestampIn.value.dateTime.time.min == testTimestampOut.value.dateTime.time.min);
ct_test(pTest, testTimestampIn.value.dateTime.time.sec == testTimestampOut.value.dateTime.time.sec);
ct_test(pTest, testTimestampIn.value.dateTime.time.hundredths == testTimestampOut.value.dateTime.time.hundredths);
ct_test(pTest, testTimestampIn.value.dateTime.date.year == testTimestampOut.value.dateTime.date.year);
ct_test(pTest, testTimestampIn.value.dateTime.date.month == testTimestampOut.value.dateTime.date.month);
ct_test(pTest, testTimestampIn.value.dateTime.date.wday == testTimestampOut.value.dateTime.date.wday);
ct_test(pTest, testTimestampIn.value.dateTime.date.day == testTimestampOut.value.dateTime.date.day);
}
#ifdef TEST_TIME_STAMP
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet Time Stamp", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testTimestampSequence);
assert(rc);
rc = ct_addTestFunction(pTest, testTimestampTime);
assert(rc);
rc = ct_addTestFunction(pTest, testTimestampTimeDate);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif // TEST_TIME_STAMP
#endif // TEST