Add support for Event_Message_Texts and Fault Event Notifications in Analog Input objects (#1188)

This commit is contained in:
Ryan Mulder
2025-12-12 23:44:44 -05:00
committed by GitHub
parent 380540635c
commit 602111059a
3 changed files with 362 additions and 150 deletions
+349 -148
View File
@@ -55,6 +55,7 @@ static const int32_t Properties_Optional[] = {
PROP_NOTIFY_TYPE, PROP_NOTIFY_TYPE,
PROP_EVENT_TIME_STAMPS, PROP_EVENT_TIME_STAMPS,
PROP_EVENT_DETECTION_ENABLE, PROP_EVENT_DETECTION_ENABLE,
PROP_EVENT_MESSAGE_TEXTS,
#endif #endif
-1 -1
}; };
@@ -462,6 +463,21 @@ bool Analog_Input_Notify_Type_Set(
return status; return status;
} }
static void
Analog_Input_Reset_Event_Properties(struct analog_input_descr *pObject)
{
unsigned j;
/* initialize Event time stamps using wildcards
and set Acked_transitions */
for (j = 0; j < MAX_BACNET_EVENT_TRANSITION; j++) {
datetime_wildcard_set(&pObject->Event_Time_Stamps[j]);
pObject->Acked_Transitions[j].bIsAcked = true;
pObject->Event_Message_Texts[j] = NULL;
}
pObject->Event_State = EVENT_STATE_NORMAL;
pObject->Last_ToFault_Event_Reliability = RELIABILITY_NO_FAULT_DETECTED;
}
/** /**
* For a given object instance-number, gets the event-detection-enable property * For a given object instance-number, gets the event-detection-enable property
* value * value
@@ -500,6 +516,13 @@ bool Analog_Input_Event_Detection_Enable_Set(
if (pObject) { if (pObject) {
pObject->Event_Detection_Enable = value; pObject->Event_Detection_Enable = value;
if (!pObject->Event_Detection_Enable) {
/*When this property is FALSE, Event_State shall be NORMAL, and the
properties Acked_Transitions, Event_Time_Stamps, and
Event_Message_Texts shall be equal to their respective initial
conditions.*/
Analog_Input_Reset_Event_Properties(pObject);
}
retval = true; retval = true;
} }
@@ -808,6 +831,59 @@ void Analog_Input_Out_Of_Service_Set(uint32_t object_instance, bool value)
} }
#if defined(INTRINSIC_REPORTING) #if defined(INTRINSIC_REPORTING)
/**
* @brief For a given object instance-number and event transition, returns the
* event message text
* @param object_instance - object-instance number of the object
* @param transition - transition type
* @return event message text or NULL if object not found or transition invalid
*/
const char *Analog_Input_Event_Message_Text(
const uint32_t object_instance,
const enum BACnetEventTransitionBits transition)
{
const char *text = NULL;
const struct analog_input_descr *pObject;
pObject = Analog_Input_Object(object_instance);
if (pObject && transition < MAX_BACNET_EVENT_TRANSITION) {
text = pObject->Event_Message_Texts[transition];
if (!text) {
text = "";
}
}
return text;
}
/**
* @brief For a given object instance-number and event transition, sets the
* custom event message text
* NOTE: Event_Message_Text will be generated on event if custom_text is null
* @param object_instance - object-instance number of the object
* @param transition - transition type
* @param custom_text - holds the event message text to be set
* @return true if custom event message text was set
*/
bool Analog_Input_Event_Message_Text_Custom_Set(
const uint32_t object_instance,
const enum BACnetEventTransitionBits transition,
const char *const custom_text)
{
bool status = false; /* return value */
struct analog_input_descr *pObject;
pObject = Analog_Input_Object(object_instance);
if (pObject && transition < MAX_BACNET_EVENT_TRANSITION) {
pObject->Event_Message_Texts_Custom[transition] = custom_text;
status = true;
}
return status;
}
/** /**
* @brief Encode a EventTimeStamps property element * @brief Encode a EventTimeStamps property element
* @param object_instance [in] BACnet network port object instance number * @param object_instance [in] BACnet network port object instance number
@@ -855,6 +931,32 @@ static int Analog_Input_Event_Time_Stamps_Encode(
return apdu_len; return apdu_len;
} }
/**
* @brief Encode a BACnetARRAY property element
* @param object_instance [in] object instance number
* @param index [in] array index requested:
* 0 to N for individual array members
* @param apdu [out] Buffer in which the APDU contents are built, or NULL to
* return the length of buffer if it had been built
* @return The length of the apdu encoded or
* BACNET_STATUS_ERROR for ERROR_CODE_INVALID_ARRAY_INDEX
*/
static int Analog_Input_Event_Message_Texts_Encode(
uint32_t object_instance, BACNET_ARRAY_INDEX index, uint8_t *apdu)
{
int apdu_len = BACNET_STATUS_ERROR;
const char *text = NULL; /* return value */
BACNET_CHARACTER_STRING char_string = { 0 };
text = Analog_Input_Event_Message_Text(object_instance, index);
if (text) {
characterstring_init_ansi(&char_string, text);
apdu_len = encode_application_character_string(apdu, &char_string);
}
return apdu_len;
}
#endif #endif
/** /**
@@ -1021,6 +1123,19 @@ int Analog_Input_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX; rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
} }
break; break;
case PROP_EVENT_MESSAGE_TEXTS:
apdu_len = bacnet_array_encode(
rpdata->object_instance, rpdata->array_index,
Analog_Input_Event_Message_Texts_Encode,
MAX_BACNET_EVENT_TRANSITION, apdu, apdu_size);
if (apdu_len == BACNET_STATUS_ABORT) {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
} else if (apdu_len == BACNET_STATUS_ERROR) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
}
break;
#endif #endif
default: default:
rpdata->error_class = ERROR_CLASS_PROPERTY; rpdata->error_class = ERROR_CLASS_PROPERTY;
@@ -1216,6 +1331,20 @@ bool Analog_Input_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
return status; return status;
} }
#if defined(INTRINSIC_REPORTING)
static const char *Analog_Input_Event_Message(
struct analog_input_descr *pObject,
enum BACnetEventTransitionBits transition,
const char *default_text)
{
if (pObject && transition < MAX_BACNET_EVENT_TRANSITION &&
pObject->Event_Message_Texts_Custom[transition]) {
return pObject->Event_Message_Texts_Custom[transition];
}
return default_text;
}
#endif
/** /**
* @brief Handles the Intrinsic Reporting Service for the Analog Input Object * @brief Handles the Intrinsic Reporting Service for the Analog Input Object
* @param object_instance - object-instance number of the object * @param object_instance - object-instance number of the object
@@ -1224,12 +1353,15 @@ void Analog_Input_Intrinsic_Reporting(uint32_t object_instance)
{ {
#if defined(INTRINSIC_REPORTING) #if defined(INTRINSIC_REPORTING)
BACNET_EVENT_NOTIFICATION_DATA event_data = { 0 }; BACNET_EVENT_NOTIFICATION_DATA event_data = { 0 };
BACNET_CHARACTER_STRING msgText = { 0 }; const char *msgText = NULL;
BACNET_CHARACTER_STRING msgCharString = { 0 };
struct analog_input_descr *CurrentAI = NULL; struct analog_input_descr *CurrentAI = NULL;
uint8_t FromState = 0; uint8_t FromState = 0;
uint8_t ToState = 0; uint8_t ToState = 0;
float ExceededLimit = 0.0f; float ExceededLimit = 0.0f;
float PresentVal = 0.0f; float PresentVal = 0.0f;
BACNET_RELIABILITY Reliability = RELIABILITY_NO_FAULT_DETECTED;
BACNET_PROPERTY_VALUE propertyValues = { 0 };
bool SendNotify = false; bool SendNotify = false;
CurrentAI = Analog_Input_Object(object_instance); CurrentAI = Analog_Input_Object(object_instance);
@@ -1249,151 +1381,184 @@ void Analog_Input_Intrinsic_Reporting(uint32_t object_instance)
ToState = CurrentAI->Ack_notify_data.EventState; ToState = CurrentAI->Ack_notify_data.EventState;
debug_printf( debug_printf(
"Analog-Input[%d]: Send AckNotification.\n", object_instance); "Analog-Input[%d]: Send AckNotification.\n", object_instance);
characterstring_init_ansi(&msgText, "AckNotification"); msgText = "AckNotification";
/* Notify Type */ /* Notify Type */
event_data.notifyType = NOTIFY_ACK_NOTIFICATION; event_data.notifyType = NOTIFY_ACK_NOTIFICATION;
/* Send EventNotification. */ /* Send EventNotification. */
SendNotify = true; SendNotify = true;
} else { } else {
/* actual Present_Value */ PresentVal = CurrentAI->Present_Value;
PresentVal = Analog_Input_Present_Value(object_instance);
FromState = CurrentAI->Event_State; FromState = CurrentAI->Event_State;
switch (CurrentAI->Event_State) { Reliability = CurrentAI->Reliability;
case EVENT_STATE_NORMAL: if (Reliability != RELIABILITY_NO_FAULT_DETECTED) {
/* A TO-OFFNORMAL event is generated under these conditions: /*Fault detection takes precedence over the detection of normal and
(a) the Present_Value must exceed the High_Limit for a offnormal states. As such, when Reliability has a value other than
minimum period of time, specified in the Time_Delay property, NO_FAULT_DETECTED, the event-state-detection process will determine
and (b) the HighLimitEnable flag must be set in the the object's event state to be FAULT.*/
Limit_Enable property, and CurrentAI->Event_State = EVENT_STATE_FAULT;
(c) the TO-OFFNORMAL flag must be set in the Event_Enable } else if (FromState == EVENT_STATE_FAULT) {
property. */ CurrentAI->Event_State = EVENT_STATE_NORMAL;
if ((PresentVal > CurrentAI->High_Limit) && } else {
((CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) == switch (CurrentAI->Event_State) {
EVENT_HIGH_LIMIT_ENABLE) && case EVENT_STATE_NORMAL:
((CurrentAI->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) == /* A TO-OFFNORMAL event is generated under these conditions:
EVENT_ENABLE_TO_OFFNORMAL)) { (a) the Present_Value must exceed the High_Limit for a
if (!CurrentAI->Remaining_Time_Delay) { minimum period of time, specified in the Time_Delay
CurrentAI->Event_State = EVENT_STATE_HIGH_LIMIT; property, and (b) the HighLimitEnable flag must be set in
} else { the Limit_Enable property, and (c) the TO-OFFNORMAL flag
CurrentAI->Remaining_Time_Delay--; must be set in the Event_Enable property. */
if ((PresentVal > CurrentAI->High_Limit) &&
((CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) ==
EVENT_HIGH_LIMIT_ENABLE) &&
((CurrentAI->Event_Enable &
EVENT_ENABLE_TO_OFFNORMAL) ==
EVENT_ENABLE_TO_OFFNORMAL)) {
if (!CurrentAI->Remaining_Time_Delay) {
CurrentAI->Event_State = EVENT_STATE_HIGH_LIMIT;
} else {
CurrentAI->Remaining_Time_Delay--;
}
break;
} }
break; /* A TO-OFFNORMAL event is generated under these conditions:
} (a) the Present_Value must exceed the Low_Limit plus the
/* A TO-OFFNORMAL event is generated under these conditions: Deadband for a minimum period of time, specified in the
(a) the Present_Value must exceed the Low_Limit plus the Time_Delay property, and (b) the LowLimitEnable flag must be
Deadband for a minimum period of time, specified in the set in the Limit_Enable property, and
Time_Delay property, and (b) the LowLimitEnable flag must be (c) the TO-NORMAL flag must be set in the Event_Enable
set in the Limit_Enable property, and property. */
(c) the TO-NORMAL flag must be set in the Event_Enable if ((PresentVal < CurrentAI->Low_Limit) &&
property. */ ((CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) ==
if ((PresentVal < CurrentAI->Low_Limit) && EVENT_LOW_LIMIT_ENABLE) &&
((CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) == ((CurrentAI->Event_Enable &
EVENT_LOW_LIMIT_ENABLE) && EVENT_ENABLE_TO_OFFNORMAL) ==
((CurrentAI->Event_Enable & EVENT_ENABLE_TO_OFFNORMAL) == EVENT_ENABLE_TO_OFFNORMAL)) {
EVENT_ENABLE_TO_OFFNORMAL)) { if (!CurrentAI->Remaining_Time_Delay) {
if (!CurrentAI->Remaining_Time_Delay) { CurrentAI->Event_State = EVENT_STATE_LOW_LIMIT;
CurrentAI->Event_State = EVENT_STATE_LOW_LIMIT; } else {
} else { CurrentAI->Remaining_Time_Delay--;
CurrentAI->Remaining_Time_Delay--; }
break;
} }
/* value of the object is still in the same event state */
CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay;
break; break;
} case EVENT_STATE_HIGH_LIMIT:
/* value of the object is still in the same event state */ /* Once exceeded, the Present_Value must fall below the
CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay; High_Limit minus the Deadband before a TO-NORMAL event is
break; generated under these conditions: (a) the Present_Value must
case EVENT_STATE_HIGH_LIMIT: fall below the High_Limit minus the Deadband for a minimum
/* Once exceeded, the Present_Value must fall below the period of time, specified in the Time_Delay property, and
High_Limit minus the Deadband before a TO-NORMAL event is (b) the HighLimitEnable flag must be set in the Limit_Enable
generated under these conditions: (a) the Present_Value must property, and (c) the TO-NORMAL flag must be set in the
fall below the High_Limit minus the Deadband for a minimum Event_Enable property. */
period of time, specified in the Time_Delay property, and (b) if (((PresentVal <
the HighLimitEnable flag must be set in the Limit_Enable CurrentAI->High_Limit - CurrentAI->Deadband) &&
property, and (c) the TO-NORMAL flag must be set in the ((CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) ==
Event_Enable property. */ EVENT_HIGH_LIMIT_ENABLE) &&
if (((PresentVal < ((CurrentAI->Event_Enable & EVENT_ENABLE_TO_NORMAL) ==
CurrentAI->High_Limit - CurrentAI->Deadband) && EVENT_ENABLE_TO_NORMAL)) ||
((CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE) == /* 13.3.6 (c) If pCurrentState is HIGH_LIMIT, and the
EVENT_HIGH_LIMIT_ENABLE) && * HighLimitEnable flag of pLimitEnable is FALSE, then
((CurrentAI->Event_Enable & EVENT_ENABLE_TO_NORMAL) == * indicate a transition to the NORMAL event state. */
EVENT_ENABLE_TO_NORMAL)) ||
/* 13.3.6 (c) If pCurrentState is HIGH_LIMIT, and the
* HighLimitEnable flag of pLimitEnable is FALSE, then
* indicate a transition to the NORMAL event state. */
(!(CurrentAI->Limit_Enable & EVENT_HIGH_LIMIT_ENABLE))) {
if ((!CurrentAI->Remaining_Time_Delay) ||
(!(CurrentAI->Limit_Enable & (!(CurrentAI->Limit_Enable &
EVENT_HIGH_LIMIT_ENABLE))) { EVENT_HIGH_LIMIT_ENABLE))) {
CurrentAI->Event_State = EVENT_STATE_NORMAL; if ((!CurrentAI->Remaining_Time_Delay) ||
} else { (!(CurrentAI->Limit_Enable &
CurrentAI->Remaining_Time_Delay--; EVENT_HIGH_LIMIT_ENABLE))) {
CurrentAI->Event_State = EVENT_STATE_NORMAL;
} else {
CurrentAI->Remaining_Time_Delay--;
}
break;
} }
/* value of the object is still in the same event state */
CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay;
break; break;
} case EVENT_STATE_LOW_LIMIT:
/* value of the object is still in the same event state */ /* Once the Present_Value has fallen below the Low_Limit,
CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay; the Present_Value must exceed the Low_Limit plus the
break; Deadband before a TO-NORMAL event is generated under these
case EVENT_STATE_LOW_LIMIT: conditions: (a) the Present_Value must exceed the Low_Limit
/* Once the Present_Value has fallen below the Low_Limit, plus the Deadband for a minimum period of time, specified in
the Present_Value must exceed the Low_Limit plus the Deadband the Time_Delay property, and (b) the LowLimitEnable flag
before a TO-NORMAL event is generated under these conditions: must be set in the Limit_Enable property, and (c) the
(a) the Present_Value must exceed the Low_Limit plus the TO-NORMAL flag must be set in the Event_Enable property. */
Deadband for a minimum period of time, specified in the if (((PresentVal >
Time_Delay property, and (b) the LowLimitEnable flag must be CurrentAI->Low_Limit + CurrentAI->Deadband) &&
set in the Limit_Enable property, and ((CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) ==
(c) the TO-NORMAL flag must be set in the Event_Enable EVENT_LOW_LIMIT_ENABLE) &&
property. */ ((CurrentAI->Event_Enable & EVENT_ENABLE_TO_NORMAL) ==
if (((PresentVal > EVENT_ENABLE_TO_NORMAL)) ||
CurrentAI->Low_Limit + CurrentAI->Deadband) && /* 13.3.6 (f) If pCurrentState is LOW_LIMIT, and the
((CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE) == * LowLimitEnable flag of pLimitEnable is FALSE, then
EVENT_LOW_LIMIT_ENABLE) && * indicate a transition to the NORMAL event state. */
((CurrentAI->Event_Enable & EVENT_ENABLE_TO_NORMAL) ==
EVENT_ENABLE_TO_NORMAL)) ||
/* 13.3.6 (f) If pCurrentState is LOW_LIMIT, and the
* LowLimitEnable flag of pLimitEnable is FALSE, then
* indicate a transition to the NORMAL event state. */
(!(CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE))) {
if ((!CurrentAI->Remaining_Time_Delay) ||
(!(CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE))) { (!(CurrentAI->Limit_Enable & EVENT_LOW_LIMIT_ENABLE))) {
CurrentAI->Event_State = EVENT_STATE_NORMAL; if ((!CurrentAI->Remaining_Time_Delay) ||
} else { (!(CurrentAI->Limit_Enable &
CurrentAI->Remaining_Time_Delay--; EVENT_LOW_LIMIT_ENABLE))) {
CurrentAI->Event_State = EVENT_STATE_NORMAL;
} else {
CurrentAI->Remaining_Time_Delay--;
}
break;
} }
/* value of the object is still in the same event state */
CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay;
break; break;
} default:
/* value of the object is still in the same event state */ return; /* shouldn't happen */
CurrentAI->Remaining_Time_Delay = CurrentAI->Time_Delay; } /* switch (FromState) */
break; }
default:
return; /* shouldn't happen */
} /* switch (FromState) */
ToState = CurrentAI->Event_State; ToState = CurrentAI->Event_State;
if (FromState != ToState) { if (FromState != ToState ||
(ToState == EVENT_STATE_FAULT &&
Reliability != CurrentAI->Last_ToFault_Event_Reliability)) {
/* Event_State has changed. /* Event_State has changed.
Need to fill only the basic parameters of this type of event. Need to fill only the basic parameters of this type of event.
Other parameters will be filled in common function. */ Other parameters will be filled in common function. */
switch (ToState) { switch (ToState) {
case EVENT_STATE_HIGH_LIMIT: case EVENT_STATE_HIGH_LIMIT:
ExceededLimit = CurrentAI->High_Limit; ExceededLimit = CurrentAI->High_Limit;
characterstring_init_ansi(&msgText, "Goes to high limit"); msgText = Analog_Input_Event_Message(
CurrentAI, TRANSITION_TO_OFFNORMAL,
"Goes to high limit");
break; break;
case EVENT_STATE_LOW_LIMIT: case EVENT_STATE_LOW_LIMIT:
ExceededLimit = CurrentAI->Low_Limit; ExceededLimit = CurrentAI->Low_Limit;
characterstring_init_ansi(&msgText, "Goes to low limit"); msgText = Analog_Input_Event_Message(
CurrentAI, TRANSITION_TO_OFFNORMAL,
"Goes to low limit");
break; break;
case EVENT_STATE_NORMAL: case EVENT_STATE_NORMAL:
if (FromState == EVENT_STATE_HIGH_LIMIT) { if (FromState == EVENT_STATE_HIGH_LIMIT) {
ExceededLimit = CurrentAI->High_Limit; ExceededLimit = CurrentAI->High_Limit;
characterstring_init_ansi( msgText = Analog_Input_Event_Message(
&msgText, "Back to normal state from high limit"); CurrentAI, TRANSITION_TO_NORMAL,
} else { "Back to normal state from high limit");
} else if (FromState == EVENT_STATE_LOW_LIMIT) {
ExceededLimit = CurrentAI->Low_Limit; ExceededLimit = CurrentAI->Low_Limit;
characterstring_init_ansi( msgText = Analog_Input_Event_Message(
&msgText, "Back to normal state from low limit"); CurrentAI, TRANSITION_TO_NORMAL,
"Back to normal state from low limit");
} else {
ExceededLimit = 0;
msgText = Analog_Input_Event_Message(
CurrentAI, TRANSITION_TO_NORMAL,
"Back to normal state from fault");
} }
break; break;
case EVENT_STATE_FAULT:
ExceededLimit = 0;
msgText = Analog_Input_Event_Message(
CurrentAI, TRANSITION_TO_FAULT,
bactext_reliability_name(Reliability));
CurrentAI->Last_ToFault_Event_Reliability = Reliability;
break;
default: default:
ExceededLimit = 0; ExceededLimit = 0;
break; break;
@@ -1419,23 +1584,35 @@ void Analog_Input_Intrinsic_Reporting(uint32_t object_instance)
datetime_local( datetime_local(
&event_data.timeStamp.value.dateTime.date, &event_data.timeStamp.value.dateTime.date,
&event_data.timeStamp.value.dateTime.time, NULL, NULL); &event_data.timeStamp.value.dateTime.time, NULL, NULL);
/* fill Event_Time_Stamps */ /* set eventType and fill Event_Time_Stamps and
* Event_Message_Texts*/
switch (ToState) { switch (ToState) {
case EVENT_STATE_HIGH_LIMIT: case EVENT_STATE_HIGH_LIMIT:
case EVENT_STATE_LOW_LIMIT: case EVENT_STATE_LOW_LIMIT:
event_data.eventType = EVENT_OUT_OF_RANGE;
datetime_copy( datetime_copy(
&CurrentAI->Event_Time_Stamps[TRANSITION_TO_OFFNORMAL], &CurrentAI->Event_Time_Stamps[TRANSITION_TO_OFFNORMAL],
&event_data.timeStamp.value.dateTime); &event_data.timeStamp.value.dateTime);
CurrentAI->Event_Message_Texts[TRANSITION_TO_OFFNORMAL] =
msgText;
break; break;
case EVENT_STATE_FAULT: case EVENT_STATE_FAULT:
event_data.eventType = EVENT_CHANGE_OF_RELIABILITY;
datetime_copy( datetime_copy(
&CurrentAI->Event_Time_Stamps[TRANSITION_TO_FAULT], &CurrentAI->Event_Time_Stamps[TRANSITION_TO_FAULT],
&event_data.timeStamp.value.dateTime); &event_data.timeStamp.value.dateTime);
CurrentAI->Event_Message_Texts[TRANSITION_TO_FAULT] =
msgText;
break; break;
case EVENT_STATE_NORMAL: case EVENT_STATE_NORMAL:
event_data.eventType = FromState == EVENT_STATE_FAULT
? EVENT_CHANGE_OF_RELIABILITY
: EVENT_OUT_OF_RANGE;
datetime_copy( datetime_copy(
&CurrentAI->Event_Time_Stamps[TRANSITION_TO_NORMAL], &CurrentAI->Event_Time_Stamps[TRANSITION_TO_NORMAL],
&event_data.timeStamp.value.dateTime); &event_data.timeStamp.value.dateTime);
CurrentAI->Event_Message_Texts[TRANSITION_TO_NORMAL] =
msgText;
break; break;
default: default:
break; break;
@@ -1445,16 +1622,21 @@ void Analog_Input_Intrinsic_Reporting(uint32_t object_instance)
switch (ToState) { switch (ToState) {
case EVENT_STATE_HIGH_LIMIT: case EVENT_STATE_HIGH_LIMIT:
case EVENT_STATE_LOW_LIMIT: case EVENT_STATE_LOW_LIMIT:
event_data.eventType = EVENT_OUT_OF_RANGE;
datetime_copy( datetime_copy(
&event_data.timeStamp.value.dateTime, &event_data.timeStamp.value.dateTime,
&CurrentAI->Event_Time_Stamps[TRANSITION_TO_OFFNORMAL]); &CurrentAI->Event_Time_Stamps[TRANSITION_TO_OFFNORMAL]);
break; break;
case EVENT_STATE_FAULT: case EVENT_STATE_FAULT:
event_data.eventType = EVENT_CHANGE_OF_RELIABILITY;
datetime_copy( datetime_copy(
&event_data.timeStamp.value.dateTime, &event_data.timeStamp.value.dateTime,
&CurrentAI->Event_Time_Stamps[TRANSITION_TO_FAULT]); &CurrentAI->Event_Time_Stamps[TRANSITION_TO_FAULT]);
break; break;
case EVENT_STATE_NORMAL: case EVENT_STATE_NORMAL:
event_data.eventType = FromState == EVENT_STATE_FAULT
? EVENT_CHANGE_OF_RELIABILITY
: EVENT_OUT_OF_RANGE;
datetime_copy( datetime_copy(
&event_data.timeStamp.value.dateTime, &event_data.timeStamp.value.dateTime,
&CurrentAI->Event_Time_Stamps[TRANSITION_TO_NORMAL]); &CurrentAI->Event_Time_Stamps[TRANSITION_TO_NORMAL]);
@@ -1465,10 +1647,9 @@ void Analog_Input_Intrinsic_Reporting(uint32_t object_instance)
} }
/* Notification Class */ /* Notification Class */
event_data.notificationClass = CurrentAI->Notification_Class; event_data.notificationClass = CurrentAI->Notification_Class;
/* Event Type */
event_data.eventType = EVENT_OUT_OF_RANGE;
/* Message Text */ /* Message Text */
event_data.messageText = &msgText; characterstring_init_ansi(&msgCharString, msgText);
event_data.messageText = &msgCharString;
/* Notify Type */ /* Notify Type */
/* filled before */ /* filled before */
/* From State */ /* From State */
@@ -1479,31 +1660,59 @@ void Analog_Input_Intrinsic_Reporting(uint32_t object_instance)
event_data.toState = CurrentAI->Event_State; event_data.toState = CurrentAI->Event_State;
/* Event Values */ /* Event Values */
if (event_data.notifyType != NOTIFY_ACK_NOTIFICATION) { if (event_data.notifyType != NOTIFY_ACK_NOTIFICATION) {
/* Value that exceeded a limit. */ if (event_data.eventType == EVENT_OUT_OF_RANGE) {
event_data.notificationParams.outOfRange.exceedingValue = /* Value that exceeded a limit. */
PresentVal; event_data.notificationParams.outOfRange.exceedingValue =
/* Status_Flags of the referenced object. */ PresentVal;
bitstring_init( /* Status_Flags of the referenced object. */
&event_data.notificationParams.outOfRange.statusFlags); bitstring_init(
bitstring_set_bit( &event_data.notificationParams.outOfRange.statusFlags);
&event_data.notificationParams.outOfRange.statusFlags, bitstring_set_bit(
STATUS_FLAG_IN_ALARM, &event_data.notificationParams.outOfRange.statusFlags,
CurrentAI->Event_State != EVENT_STATE_NORMAL); STATUS_FLAG_IN_ALARM,
bitstring_set_bit( CurrentAI->Event_State != EVENT_STATE_NORMAL);
&event_data.notificationParams.outOfRange.statusFlags, bitstring_set_bit(
STATUS_FLAG_FAULT, false); &event_data.notificationParams.outOfRange.statusFlags,
bitstring_set_bit( STATUS_FLAG_FAULT, false);
&event_data.notificationParams.outOfRange.statusFlags, bitstring_set_bit(
STATUS_FLAG_OVERRIDDEN, false); &event_data.notificationParams.outOfRange.statusFlags,
bitstring_set_bit( STATUS_FLAG_OVERRIDDEN, false);
&event_data.notificationParams.outOfRange.statusFlags, bitstring_set_bit(
STATUS_FLAG_OUT_OF_SERVICE, CurrentAI->Out_Of_Service); &event_data.notificationParams.outOfRange.statusFlags,
/* Deadband used for limit checking. */ STATUS_FLAG_OUT_OF_SERVICE, CurrentAI->Out_Of_Service);
event_data.notificationParams.outOfRange.deadband = /* Deadband used for limit checking. */
CurrentAI->Deadband; event_data.notificationParams.outOfRange.deadband =
/* Limit that was exceeded. */ CurrentAI->Deadband;
event_data.notificationParams.outOfRange.exceededLimit = /* Limit that was exceeded. */
ExceededLimit; event_data.notificationParams.outOfRange.exceededLimit =
ExceededLimit;
} else {
event_data.notificationParams.changeOfReliability.reliability =
Reliability;
propertyValues.propertyIdentifier = PROP_PRESENT_VALUE;
propertyValues.propertyArrayIndex = BACNET_ARRAY_ALL;
propertyValues.value.tag = BACNET_APPLICATION_TAG_REAL;
propertyValues.value.type.Real = PresentVal;
event_data.notificationParams.changeOfReliability
.propertyValues = &propertyValues;
bitstring_init(&event_data.notificationParams
.changeOfReliability.statusFlags);
bitstring_set_bit(
&event_data.notificationParams.outOfRange.statusFlags,
STATUS_FLAG_IN_ALARM, false);
bitstring_set_bit(
&event_data.notificationParams.outOfRange.statusFlags,
STATUS_FLAG_FAULT,
CurrentAI->Event_State != EVENT_STATE_NORMAL);
bitstring_set_bit(
&event_data.notificationParams.outOfRange.statusFlags,
STATUS_FLAG_OVERRIDDEN, false);
bitstring_set_bit(
&event_data.notificationParams.outOfRange.statusFlags,
STATUS_FLAG_OUT_OF_SERVICE, CurrentAI->Out_Of_Service);
}
} }
/* add data from notification class */ /* add data from notification class */
debug_printf( debug_printf(
@@ -1832,9 +2041,6 @@ uint32_t Analog_Input_Create(uint32_t object_instance)
{ {
struct analog_input_descr *pObject = NULL; struct analog_input_descr *pObject = NULL;
int index = 0; int index = 0;
#if defined(INTRINSIC_REPORTING)
unsigned j;
#endif
if (!Object_List) { if (!Object_List) {
Object_List = Keylist_Create(); Object_List = Keylist_Create();
@@ -1868,12 +2074,7 @@ uint32_t Analog_Input_Create(uint32_t object_instance)
pObject->Time_Delay = 0; pObject->Time_Delay = 0;
/* notification class not connected */ /* notification class not connected */
pObject->Notification_Class = BACNET_MAX_INSTANCE; pObject->Notification_Class = BACNET_MAX_INSTANCE;
/* initialize Event time stamps using wildcards Analog_Input_Reset_Event_Properties(pObject);
and set Acked_transitions */
for (j = 0; j < MAX_BACNET_EVENT_TRANSITION; j++) {
datetime_wildcard_set(&pObject->Event_Time_Stamps[j]);
pObject->Acked_Transitions[j].bIsAcked = true;
}
#endif #endif
/* add to list */ /* add to list */
index = Keylist_Data_Add(Object_List, object_instance, pObject); index = Keylist_Data_Add(Object_List, object_instance, pObject);
+9 -2
View File
@@ -47,10 +47,13 @@ typedef struct analog_input_descr {
unsigned Notify_Type : 1; unsigned Notify_Type : 1;
ACKED_INFO Acked_Transitions[MAX_BACNET_EVENT_TRANSITION]; ACKED_INFO Acked_Transitions[MAX_BACNET_EVENT_TRANSITION];
BACNET_DATE_TIME Event_Time_Stamps[MAX_BACNET_EVENT_TRANSITION]; BACNET_DATE_TIME Event_Time_Stamps[MAX_BACNET_EVENT_TRANSITION];
const char *Event_Message_Texts[MAX_BACNET_EVENT_TRANSITION];
const char *Event_Message_Texts_Custom[MAX_BACNET_EVENT_TRANSITION];
/* time to generate event notification */ /* time to generate event notification */
uint32_t Remaining_Time_Delay; uint32_t Remaining_Time_Delay;
/* AckNotification information */ /* AckNotification information */
ACK_NOTIFICATION Ack_notify_data; ACK_NOTIFICATION Ack_notify_data;
BACNET_RELIABILITY Last_ToFault_Event_Reliability;
#endif #endif
} ANALOG_INPUT_DESCR; } ANALOG_INPUT_DESCR;
@@ -115,9 +118,13 @@ BACNET_STACK_EXPORT
void Analog_Input_Out_Of_Service_Set(uint32_t object_instance, bool oos_flag); void Analog_Input_Out_Of_Service_Set(uint32_t object_instance, bool oos_flag);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
unsigned Analog_Input_Event_State(uint32_t object_instance); const char *Analog_Input_Event_Message_Text(
uint32_t object_instance, enum BACnetEventTransitionBits transition);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool Analog_Input_Event_State_Set(uint32_t object_instance, unsigned state); bool Analog_Input_Event_Message_Text_Custom_Set(
uint32_t object_instance,
enum BACnetEventTransitionBits transition,
const char *custom_text);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool Analog_Input_Change_Of_Value(uint32_t instance); bool Analog_Input_Change_Of_Value(uint32_t instance);
+4
View File
@@ -62,8 +62,12 @@ typedef enum {
#endif #endif
#ifndef BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED #ifndef BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED
#if defined(INTRINSIC_REPORTING)
#define BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED 1
#else
#define BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED 0 #define BACNET_EVENT_CHANGE_OF_RELIABILITY_ENABLED 0
#endif #endif
#endif
#ifndef BACNET_EVENT_CHANGE_OF_DISCRETE_VALUE_ENABLED #ifndef BACNET_EVENT_CHANGE_OF_DISCRETE_VALUE_ENABLED
#define BACNET_EVENT_CHANGE_OF_DISCRETE_VALUE_ENABLED 0 #define BACNET_EVENT_CHANGE_OF_DISCRETE_VALUE_ENABLED 0