Cosmetic changes to comments.

Print on output every change of Event_State for analog-value objects.
Added write_property_function for analog-input objects.
Created descriptor for analog-input objects.
Possible to write Present_Value for analog-inputs when Out_Of_Service is true.
This commit is contained in:
k001a
2011-07-11 19:48:21 +00:00
parent ff393a665a
commit 7f291e3041
9 changed files with 1281 additions and 918 deletions
+11 -11
View File
@@ -97,7 +97,7 @@ void handler_write_property_multiple(
decode_len = 0;
do
{
/* decode Object Identifier
/* decode Object Identifier */
len = wpm_decode_object_id(&service_request[decode_len],
service_len - decode_len, &wp_data);
if (len > 0)
@@ -105,13 +105,13 @@ void handler_write_property_multiple(
uint8_t tag_number = 0;
decode_len += len;
decode_len += len;
/* Opening tag 1 - List of Properties */
if (decode_is_opening_tag_number(&service_request[decode_len++], 1))
{
do
{
do
{
/* decode a 'Property Identifier'; (3) an optional 'Property Array Index' */
/* (4) a 'Property Value'; and (5) an optional 'Priority'. */
len = wpm_decode_object_property(&service_request[decode_len],
service_len - decode_len, &wp_data);
if (len > 0)
@@ -120,7 +120,7 @@ void handler_write_property_multiple(
if (Device_Write_Property(&wp_data) == false)
{
error = true;
decode_len += len;
break; /* do while (decoding List of Properties) */
}
}
else
@@ -131,23 +131,23 @@ void handler_write_property_multiple(
wp_data.error_class = ERROR_CLASS_PROPERTY;
wp_data.error_code = ERROR_CODE_OTHER;
error = true;
fprintf(stderr, "Bad Encoding!\n");
break; /* do while (decoding List of Properties) */
}
wp_data.error_code = ERROR_CODE_OTHER;
/* Closing tag 1 - List of Properties */
if (decode_is_closing_tag_number(&service_request[decode_len], 1))
{
tag_number = 1;
decode_len++;
}
else
*/
tag_number = 0; /* it was not tag 1, decode next Property Identifier ... */
}
tag_number = 1;
while(tag_number != 1); /* end decoding List of Properties for "that" object */
if (error)
else
break; /*do while (decode service request) */
}
}
else
@@ -158,7 +158,7 @@ void handler_write_property_multiple(
wp_data.error_class = ERROR_CLASS_OBJECT;
wp_data.error_code = ERROR_CODE_OTHER;
error = true;
}
break; /*do while (decode service request) */
}
}
while(decode_len < service_len);
+369 -12
View File
@@ -1,6 +1,7 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
* Copyright (C) 2011 Krzysztof Malorny <malornykrzysztof@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -28,17 +29,22 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "config.h" /* the custom stuff */
#include "handlers.h"
#include "timestamp.h"
#include "ai.h"
#ifndef MAX_ANALOG_INPUTS
#define MAX_ANALOG_INPUTS 4
#endif
static float Present_Value[MAX_ANALOG_INPUTS];
ANALOG_INPUT_DESCR AI_Descr[MAX_ANALOG_INPUTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
@@ -55,6 +61,18 @@ static const int Properties_Required[] = {
static const int Properties_Optional[] = {
PROP_DESCRIPTION,
#if defined(INTRINSIC_REPORTING)
PROP_TIME_DELAY,
PROP_NOTIFICATION_CLASS,
PROP_HIGH_LIMIT,
PROP_LOW_LIMIT,
PROP_DEADBAND,
PROP_LIMIT_ENABLE,
PROP_EVENT_ENABLE,
PROP_ACKED_TRANSITIONS,
PROP_NOTIFY_TYPE,
PROP_EVENT_TIME_STAMPS,
#endif
-1
};
@@ -80,6 +98,29 @@ void Analog_Input_Property_Lists(
return;
}
void Analog_Input_Init(
void)
{
unsigned i, j;
for (i = 0; i < MAX_ANALOG_INPUTS; i++) {
AI_Descr[i].Present_Value = 0.0f;
AI_Descr[i].Out_Of_Service = false;
AI_Descr[i].Units = UNITS_PERCENT;
AI_Descr[i].Reliability = RELIABILITY_NO_FAULT_DETECTED;
#if defined(INTRINSIC_REPORTING)
AI_Descr[i].Event_State = EVENT_STATE_NORMAL;
/* notification class not connected */
AI_Descr[i].Notification_Class = BACNET_MAX_INSTANCE;
/* initialize Event time stamps using wildcards */
for (j = 0; j < MAX_BACNET_EVENT_TRANSITION; j++) {
datetime_wildcard_set(&AI_Descr[i].Event_Time_Stamps[j]);
}
#endif
}
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
@@ -134,7 +175,7 @@ float Analog_Input_Present_Value(
index = Analog_Input_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_INPUTS) {
value = Present_Value[index];
value = AI_Descr[index].Present_Value;
}
return value;
@@ -148,7 +189,7 @@ void Analog_Input_Present_Value_Set(
index = Analog_Input_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_INPUTS) {
Present_Value[index] = value;
AI_Descr[index].Present_Value = value;
}
}
@@ -174,15 +215,26 @@ bool Analog_Input_Object_Name(
int Analog_Input_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
BACNET_CHARACTER_STRING char_string;
ANALOG_INPUT_DESCR *CurrentAI;
unsigned object_index = 0;
unsigned i = 0;
uint8_t *apdu = NULL;
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
object_index = Analog_Input_Instance_To_Index(rpdata->object_instance);
if (object_index < MAX_ANALOG_INPUTS)
CurrentAI = &AI_Descr[object_index];
else
return BACNET_STATUS_ERROR;
apdu = rpdata->application_data;
switch ((int) rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
@@ -190,39 +242,168 @@ int Analog_Input_Read_Property(
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
Analog_Input_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_INPUT);
break;
case PROP_PRESENT_VALUE:
apdu_len =
encode_application_real(&apdu[0],
Analog_Input_Present_Value(rpdata->object_instance));
break;
case PROP_STATUS_FLAGS:
bitstring_init(&bit_string);
#if defined(INTRINSIC_REPORTING)
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM,
CurrentAI->Event_State ? true : false);
#else
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
#endif
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, CurrentAI->Out_Of_Service);
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_EVENT_STATE:
apdu_len =
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
#if defined(INTRINSIC_REPORTING)
apdu_len = encode_application_enumerated(&apdu[0],
CurrentAI->Event_State);
#else
apdu_len = encode_application_enumerated(&apdu[0],
EVENT_STATE_NORMAL);
#endif
break;
case PROP_RELIABILITY:
apdu_len = encode_application_enumerated(&apdu[0], CurrentAI->Reliability);
break;
case PROP_OUT_OF_SERVICE:
apdu_len = encode_application_boolean(&apdu[0], false);
apdu_len = encode_application_boolean(&apdu[0], CurrentAI->Out_Of_Service);
break;
case PROP_UNITS:
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
apdu_len = encode_application_enumerated(&apdu[0], CurrentAI->Units);
break;
#if defined(INTRINSIC_REPORTING)
case PROP_TIME_DELAY:
apdu_len = encode_application_unsigned(&apdu[0], CurrentAI->Time_Delay);
break;
case PROP_NOTIFICATION_CLASS:
apdu_len = encode_application_unsigned(&apdu[0], CurrentAI->Notification_Class);
break;
case PROP_HIGH_LIMIT:
apdu_len = encode_application_real(&apdu[0], CurrentAI->High_Limit);
break;
case PROP_LOW_LIMIT:
apdu_len = encode_application_real(&apdu[0], CurrentAI->Low_Limit);
break;
case PROP_DEADBAND:
apdu_len = encode_application_real(&apdu[0], CurrentAI->Deadband);
break;
case PROP_LIMIT_ENABLE:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, 0,
(CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE ) ? true : false );
bitstring_set_bit(&bit_string, 1,
(CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) ? true : false );
apdu_len = encode_application_bitstring(&apdu[0],&bit_string);
break;
case PROP_EVENT_ENABLE:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL,
(CurrentAI->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) ? true : false );
bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT,
(CurrentAI->Event_Enable & EVENT_ENABLE_TO_FAULT ) ? true : false );
bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL,
(CurrentAI->Event_Enable & EVENT_ENABLE_TO_NORMAL ) ? true : false );
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_ACKED_TRANSITIONS:
bitstring_init(&bit_string);
bitstring_set_bit(&bit_string, TRANSITION_TO_OFFNORMAL, true);
bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, true);
bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, true);
/* Fixme: finish it */
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_NOTIFY_TYPE:
apdu_len = encode_application_enumerated(&apdu[0],
CurrentAI->Notify_Type ? NOTIFY_EVENT : NOTIFY_ALARM);
break;
case PROP_EVENT_TIME_STAMPS:
/* Array element zero is the number of elements in the array */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0],
MAX_BACNET_EVENT_TRANSITION);
/* if no index was specified, then try to encode the entire list */
/* into one packet. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 0; i < MAX_BACNET_EVENT_TRANSITION; i++) {;
len = encode_opening_tag(&apdu[apdu_len],
TIME_STAMP_DATETIME);
len += encode_application_date(&apdu[apdu_len + len],
&CurrentAI->Event_Time_Stamps[i].date);
len += encode_application_time(&apdu[apdu_len + len],
&CurrentAI->Event_Time_Stamps[i].time);
len += encode_closing_tag(&apdu[apdu_len + len],
TIME_STAMP_DATETIME);
/* add it if we have room */
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
}
else if (rpdata->array_index <= MAX_BACNET_EVENT_TRANSITION) {
apdu_len = encode_opening_tag(&apdu[apdu_len],
TIME_STAMP_DATETIME);
apdu_len += encode_application_date(&apdu[apdu_len],
&CurrentAI->Event_Time_Stamps[rpdata->array_index].date);
apdu_len += encode_application_time(&apdu[apdu_len],
&CurrentAI->Event_Time_Stamps[rpdata->array_index].time);
apdu_len += encode_closing_tag(&apdu[apdu_len],
TIME_STAMP_DATETIME);
}
else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
break;
#endif
case 9997:
/* test case for real encoding-decoding unsigned value correctly */
apdu_len = encode_application_real(&apdu[0], 90.510F);
@@ -242,20 +423,196 @@ int Analog_Input_Read_Property(
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
if ((apdu_len >= 0) &&
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
void Analog_Input_Init(
void)
/* returns true if successful */
bool Analog_Input_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int object_index = 0;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
ANALOG_INPUT_DESCR *CurrentAI;
/* decode the some of the request */
len =
bacapp_decode_application_data(wp_data->application_data,
wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
object_index = Analog_Input_Instance_To_Index(wp_data->object_instance);
if (object_index < MAX_ANALOG_INPUTS)
CurrentAI = &AI_Descr[object_index];
else
return false;
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL,
&wp_data->error_class, &wp_data->error_code);
if (status) {
if (CurrentAI->Out_Of_Service == true) {
Analog_Input_Present_Value_Set(wp_data->object_instance,
value.type.Real);
}
else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
status = false;
}
}
break;
case PROP_OUT_OF_SERVICE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAI->Out_Of_Service = value.type.Boolean;
}
break;
case PROP_UNITS:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAI->Units = value.type.Enumerated;
}
break;
#if defined(INTRINSIC_REPORTING)
case PROP_TIME_DELAY:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAI->Time_Delay = value.type.Unsigned_Int;
CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay;
}
break;
case PROP_NOTIFICATION_CLASS:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAI->Notification_Class = value.type.Unsigned_Int;
}
break;
case PROP_HIGH_LIMIT:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAI->High_Limit = value.type.Real;
}
break;
case PROP_LOW_LIMIT:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAI->Low_Limit = value.type.Real;
}
break;
case PROP_DEADBAND:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL,
&wp_data->error_class, &wp_data->error_code);
if (status) {
CurrentAI->Deadband = value.type.Real;
}
break;
case PROP_LIMIT_ENABLE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BIT_STRING,
&wp_data->error_class, &wp_data->error_code);
if (status) {
if(value.type.Bit_String.bits_used == 2) {
CurrentAI->Limit_Enable = value.type.Bit_String.value[0];
}
else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = false;
}
}
break;
case PROP_EVENT_ENABLE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BIT_STRING,
&wp_data->error_class, &wp_data->error_code);
if (status) {
if(value.type.Bit_String.bits_used == 3) {
CurrentAI->Event_Enable = value.type.Bit_String.value[0];
}
else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = false;
}
}
break;
case PROP_NOTIFY_TYPE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
&wp_data->error_class, &wp_data->error_code);
if (status) {
if(value.type.Bit_String.bits_used > NOTIFY_EVENT) {
CurrentAI->Event_Enable = value.type.Enumerated;
}
else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
status = false;
}
}
break;
#endif
default:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
}
return status;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
+27
View File
@@ -1,6 +1,7 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
* Copyright (C) 2011 Krzysztof Malorny <malornykrzysztof@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -34,6 +35,32 @@
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct analog_input_descr {
uint8_t Event_State : 3;
float Present_Value;
BACNET_RELIABILITY Reliability;
bool Out_Of_Service;
uint8_t Units;
#if defined(INTRINSIC_REPORTING)
uint32_t Time_Delay;
uint32_t Notification_Class;
float High_Limit;
float Low_Limit;
float Deadband;
uint8_t Limit_Enable : 2;
uint8_t Event_Enable : 3;
uint8_t Acked_Transitions : 3;
uint8_t Notify_Type : 1;
BACNET_DATE_TIME Event_Time_Stamps[MAX_BACNET_EVENT_TRANSITION];
/* time to generate event notification */
uint32_t Remaining_Time_Delay;
#endif
} ANALOG_INPUT_DESCR;
void Analog_Input_Property_Lists(
const int **pRequired,
const int **pOptional,
+8 -1
View File
@@ -35,6 +35,7 @@
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "bactext.h"
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "rp.h"
@@ -435,7 +436,7 @@ int Analog_Value_Read_Property(
bitstring_set_bit(&bit_string, TRANSITION_TO_FAULT, true);
bitstring_set_bit(&bit_string, TRANSITION_TO_NORMAL, true);
/*/ Fixme: finish it */
/* Fixme: finish it */
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
@@ -877,6 +878,12 @@ void Analog_Value_Intrinsic_Reporting(uint32_t object_instance)
break;
} /* switch (ToState) */
#if defined(PRINT_ENABLED)
fprintf(stderr, "Event_State for (Analog-Value,%d) goes from %s to %s.\n",
object_instance, bactext_event_state_name(FromState),
bactext_event_state_name(ToState));
#endif /* defined(PRINT_ENABLED) */
/* Event Object Identifier */
event_data.eventObjectIdentifier.type = OBJECT_ANALOG_VALUE;
+2 -2
View File
@@ -92,7 +92,7 @@ static object_functions_t Object_Table[] = {
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
Analog_Input_Object_Name, Analog_Input_Read_Property,
NULL, Analog_Input_Property_Lists,
Analog_Input_Write_Property, Analog_Input_Property_Lists,
NULL, NULL, NULL, NULL}, {
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance,
@@ -1485,7 +1485,7 @@ bool Device_Encode_Value_List(
}
void Device_local_reporting(uint32_t milliseconds)
void Device_local_reporting(void)
{
#if defined(INTRINSIC_REPORTING)
struct object_functions *pObject;
+1 -1
View File
@@ -337,7 +337,7 @@ extern "C" {
bool Device_Write_Property_Local(
BACNET_WRITE_PROPERTY_DATA * wp_data);
void Device_local_reporting(uint32_t milliseconds);
void Device_local_reporting(void);
/* Prototypes for Routing functionality in the Device Object.
* Enable by defining BAC_ROUTING in config.h and including gw_device.c
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -121,4 +121,4 @@ typedef struct Notification_Class_info {
Notification_Class_Write_Property, Notification_Class_Property_Lists, \
NULL, NULL, NULL
#endif /* NC_H
#endif /* NC_H */
+1 -1
View File
@@ -206,7 +206,7 @@ int main(
tsm_timer_milliseconds(elapsed_milliseconds);
trend_log_timer(elapsed_seconds);
#if defined(INTRINSIC_REPORTING)
Device_local_reporting(elapsed_seconds * 1000);
Device_local_reporting();
#endif
}
/* scan cache address */