Acknowledge Alarm for Analog-Input and Analog-Value objects.
Moved initialization of handlers to GetEventInformations to specific init object.
This commit is contained in:
@@ -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
|
||||
@@ -27,10 +28,13 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "bactext.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
@@ -39,6 +43,17 @@
|
||||
|
||||
/** @file h_alarm_ack.c Handles Alarm Acknowledgment. */
|
||||
|
||||
static alarm_ack_function Alarm_Ack[MAX_BACNET_OBJECT_TYPE];
|
||||
|
||||
void handler_alarm_ack_set(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
alarm_ack_function pFunction)
|
||||
{
|
||||
if (object_type < MAX_BACNET_OBJECT_TYPE) {
|
||||
Alarm_Ack[object_type] = pFunction;
|
||||
}
|
||||
}
|
||||
|
||||
/** Handler for an Alarm/Event Acknowledgement.
|
||||
* @ingroup ALMACK
|
||||
* This handler will be invoked by apdu_handler() if it has been enabled
|
||||
@@ -48,12 +63,12 @@
|
||||
* - the message is segmented
|
||||
* - if decoding fails
|
||||
* - Otherwise, sends a simple ACK
|
||||
*
|
||||
*
|
||||
* @param service_request [in] The contents of the service request.
|
||||
* @param service_len [in] The length of the service_request.
|
||||
* @param src [in] BACNET_ADDRESS of the source of the message
|
||||
* @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information
|
||||
* decoded from the APDU header of this message.
|
||||
* @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information
|
||||
* decoded from the APDU header of this message.
|
||||
*/
|
||||
void handler_alarm_ack(
|
||||
uint8_t * service_request,
|
||||
@@ -61,12 +76,14 @@ void handler_alarm_ack(
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_ALARM_ACK_DATA data;
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
int bytes_sent = 0;
|
||||
int ack_result = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ALARM_ACK_DATA data;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
@@ -103,25 +120,60 @@ void handler_alarm_ack(
|
||||
goto AA_ABORT;
|
||||
}
|
||||
|
||||
/*
|
||||
** Process Life Safety Operation Here
|
||||
*/
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Alarm Ack Operation: Received acknowledge for object id %lu from %s for process id %lu for object %lu\n",
|
||||
"Alarm Ack Operation: Received acknowledge for object id (%d, %lu) from %s for process id %lu \n",
|
||||
data.eventObjectIdentifier.type,
|
||||
(unsigned long) data.eventObjectIdentifier.instance,
|
||||
data.ackSource.value, (unsigned long) data.ackProcessIdentifier,
|
||||
(unsigned long) data.eventObjectIdentifier.instance);
|
||||
data.ackSource.value, (unsigned long) data.ackProcessIdentifier);
|
||||
#endif
|
||||
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM);
|
||||
|
||||
if (Alarm_Ack[data.eventObjectIdentifier.type]) {
|
||||
|
||||
ack_result = Alarm_Ack[data.eventObjectIdentifier.type](&data, &error_code);
|
||||
|
||||
switch (ack_result)
|
||||
{
|
||||
case 1:
|
||||
len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Alarm Acknowledge: " "Sending Simple Ack!\n");
|
||||
fprintf(stderr, "Alarm Acknowledge: " "Sending Simple Ack!\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
AA_ABORT:
|
||||
case -1:
|
||||
len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM,
|
||||
ERROR_CLASS_OBJECT, error_code);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Alarm Acknowledge: error %s!\n",
|
||||
bactext_error_code_name(error_code));
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Alarm Acknowledge: abort other!\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM,
|
||||
ERROR_CLASS_OBJECT, ERROR_CODE_NO_ALARM_CONFIGURED);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Alarm Acknowledge: error %s!\n",
|
||||
bactext_error_code_name(ERROR_CODE_NO_ALARM_CONFIGURED));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
AA_ABORT:
|
||||
pdu_len += len;
|
||||
bytes_sent =
|
||||
datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0],
|
||||
|
||||
@@ -122,6 +122,13 @@ void Analog_Input_Init(
|
||||
datetime_wildcard_set(&AI_Descr[i].Event_Time_Stamps[j]);
|
||||
AI_Descr[i].Acked_Transitions[j].bIsAcked = true;
|
||||
}
|
||||
|
||||
/* Set handler for GetEventInformation function */
|
||||
handler_get_event_information_set(OBJECT_ANALOG_INPUT,
|
||||
Analog_Input_Event_Information);
|
||||
/* Set handler for AcknowledgeAlarm function */
|
||||
handler_alarm_ack_set(OBJECT_ANALOG_INPUT,
|
||||
Analog_Input_Alarm_Ack);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -873,10 +880,10 @@ void Analog_Input_Intrinsic_Reporting(uint32_t object_instance)
|
||||
}
|
||||
|
||||
|
||||
#if defined(INTRINSIC_REPORTING)
|
||||
int Analog_Input_Event_Information(unsigned index,
|
||||
BACNET_GET_EVENT_INFORMATION_DATA * getevent_data)
|
||||
{
|
||||
#if defined(INTRINSIC_REPORTING)
|
||||
bool IsNotAckedTransitions;
|
||||
bool IsActiveEvent;
|
||||
int i;
|
||||
@@ -934,10 +941,104 @@ int Analog_Input_Event_Information(unsigned index,
|
||||
}
|
||||
else
|
||||
return 0; /* no active event at this index */
|
||||
#endif /* defined(INTRINSIC_REPORTING) */
|
||||
}
|
||||
|
||||
|
||||
int Analog_Input_Alarm_Ack(BACNET_ALARM_ACK_DATA * alarmack_data,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
ANALOG_INPUT_DESCR *CurrentAI;
|
||||
unsigned int object_index;
|
||||
|
||||
|
||||
object_index = Analog_Input_Instance_To_Index(
|
||||
alarmack_data->eventObjectIdentifier.instance);
|
||||
|
||||
if (object_index < MAX_ANALOG_INPUTS)
|
||||
CurrentAI = &AI_Descr[object_index];
|
||||
else {
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (alarmack_data->eventStateAcked)
|
||||
{
|
||||
case EVENT_STATE_OFFNORMAL:
|
||||
case EVENT_STATE_HIGH_LIMIT:
|
||||
case EVENT_STATE_LOW_LIMIT:
|
||||
if(CurrentAI->Acked_Transitions[TRANSITION_TO_OFFNORMAL].bIsAcked == false) {
|
||||
if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
if(datetime_compare(&CurrentAI->Acked_Transitions[TRANSITION_TO_OFFNORMAL].Time_Stamp,
|
||||
&alarmack_data->eventTimeStamp.value.dateTime) > 0)
|
||||
{
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: Send ack notification */
|
||||
CurrentAI->Acked_Transitions[TRANSITION_TO_OFFNORMAL].bIsAcked = true;
|
||||
}
|
||||
else {
|
||||
*error_code = ERROR_CODE_INVALID_EVENT_STATE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_STATE_FAULT:
|
||||
if(CurrentAI->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked == false) {
|
||||
if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
if(datetime_compare(&CurrentAI->Acked_Transitions[TRANSITION_TO_NORMAL].Time_Stamp,
|
||||
&alarmack_data->eventTimeStamp.value.dateTime) > 0)
|
||||
{
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: Send ack notification */
|
||||
CurrentAI->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked = true;
|
||||
}
|
||||
else {
|
||||
*error_code = ERROR_CODE_INVALID_EVENT_STATE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_STATE_NORMAL:
|
||||
if(CurrentAI->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked == false) {
|
||||
if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
if(datetime_compare(&CurrentAI->Acked_Transitions[TRANSITION_TO_FAULT].Time_Stamp,
|
||||
&alarmack_data->eventTimeStamp.value.dateTime) > 0)
|
||||
{
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: Send ack notification */
|
||||
CurrentAI->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked = true;
|
||||
}
|
||||
else {
|
||||
*error_code = ERROR_CODE_INVALID_EVENT_STATE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* defined(INTRINSIC_REPORTING) */
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
|
||||
@@ -113,6 +113,9 @@ extern "C" {
|
||||
int Analog_Input_Event_Information(unsigned index,
|
||||
BACNET_GET_EVENT_INFORMATION_DATA * getevent_data);
|
||||
|
||||
int Analog_Input_Alarm_Ack(BACNET_ALARM_ACK_DATA * alarmack_data,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
void Analog_Input_Init(
|
||||
void);
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "bacapp.h"
|
||||
#include "bactext.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "alarm_ack.h"
|
||||
#include "getevent.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
@@ -131,6 +132,13 @@ void Analog_Value_Init(
|
||||
datetime_wildcard_set(&AV_Descr[i].Event_Time_Stamps[j]);
|
||||
AV_Descr[i].Acked_Transitions[j].bIsAcked = true;
|
||||
}
|
||||
|
||||
/* Set handler for GetEventInformation function */
|
||||
handler_get_event_information_set(OBJECT_ANALOG_VALUE,
|
||||
Analog_Value_Event_Information);
|
||||
/* Set handler for AcknowledgeAlarm function */
|
||||
handler_alarm_ack_set(OBJECT_ANALOG_VALUE,
|
||||
Analog_Value_Alarm_Ack);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -983,10 +991,10 @@ void Analog_Value_Intrinsic_Reporting(uint32_t object_instance)
|
||||
}
|
||||
|
||||
|
||||
#if defined(INTRINSIC_REPORTING)
|
||||
int Analog_Value_Event_Information(unsigned index,
|
||||
BACNET_GET_EVENT_INFORMATION_DATA * getevent_data)
|
||||
{
|
||||
#if defined(INTRINSIC_REPORTING)
|
||||
bool IsNotAckedTransitions;
|
||||
bool IsActiveEvent;
|
||||
int i;
|
||||
@@ -1044,9 +1052,102 @@ int Analog_Value_Event_Information(unsigned index,
|
||||
}
|
||||
else
|
||||
return 0; /* no active event at this index */
|
||||
#endif /* defined(INTRINSIC_REPORTING) */
|
||||
}
|
||||
|
||||
int Analog_Value_Alarm_Ack(BACNET_ALARM_ACK_DATA * alarmack_data,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
ANALOG_VALUE_DESCR *CurrentAV;
|
||||
unsigned int object_index;
|
||||
|
||||
|
||||
object_index = Analog_Value_Instance_To_Index(
|
||||
alarmack_data->eventObjectIdentifier.instance);
|
||||
|
||||
if (object_index < MAX_ANALOG_VALUES)
|
||||
CurrentAV = &AV_Descr[object_index];
|
||||
else {
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (alarmack_data->eventStateAcked)
|
||||
{
|
||||
case EVENT_STATE_OFFNORMAL:
|
||||
case EVENT_STATE_HIGH_LIMIT:
|
||||
case EVENT_STATE_LOW_LIMIT:
|
||||
if(CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL].bIsAcked == false) {
|
||||
if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
if(datetime_compare(&CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL].Time_Stamp,
|
||||
&alarmack_data->eventTimeStamp.value.dateTime) > 0)
|
||||
{
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: Send ack notification */
|
||||
CurrentAV->Acked_Transitions[TRANSITION_TO_OFFNORMAL].bIsAcked = true;
|
||||
}
|
||||
else {
|
||||
*error_code = ERROR_CODE_INVALID_EVENT_STATE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_STATE_FAULT:
|
||||
if(CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked == false) {
|
||||
if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
if(datetime_compare(&CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL].Time_Stamp,
|
||||
&alarmack_data->eventTimeStamp.value.dateTime) > 0)
|
||||
{
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: Send ack notification */
|
||||
CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked = true;
|
||||
}
|
||||
else {
|
||||
*error_code = ERROR_CODE_INVALID_EVENT_STATE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_STATE_NORMAL:
|
||||
if(CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT].bIsAcked == false) {
|
||||
if(alarmack_data->eventTimeStamp.tag != TIME_STAMP_DATETIME){
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
if(datetime_compare(&CurrentAV->Acked_Transitions[TRANSITION_TO_FAULT].Time_Stamp,
|
||||
&alarmack_data->eventTimeStamp.value.dateTime) > 0)
|
||||
{
|
||||
*error_code = ERROR_CODE_INVALID_TIME_STAMP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: Send ack notification */
|
||||
CurrentAV->Acked_Transitions[TRANSITION_TO_NORMAL].bIsAcked = true;
|
||||
}
|
||||
else {
|
||||
*error_code = ERROR_CODE_INVALID_EVENT_STATE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif /* defined(INTRINSIC_REPORTING) */
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
@@ -100,6 +100,9 @@ extern "C" {
|
||||
int Analog_Value_Event_Information(unsigned index,
|
||||
BACNET_GET_EVENT_INFORMATION_DATA * getevent_data);
|
||||
|
||||
int Analog_Value_Alarm_Ack(BACNET_ALARM_ACK_DATA * alarmack_data,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
void Analog_Value_Init(
|
||||
void);
|
||||
|
||||
|
||||
@@ -127,15 +127,10 @@ static void Init_Service_Handlers(
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||
handler_device_communication_control);
|
||||
#if defined(INTRINSIC_REPORTING)
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM,
|
||||
handler_alarm_ack);
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_GET_EVENT_INFORMATION,
|
||||
handler_get_event_information);
|
||||
/* Set handlers for GetEventInformation
|
||||
for all objects that support intrinsic reporting. */
|
||||
handler_get_event_information_set(OBJECT_ANALOG_INPUT,
|
||||
Analog_Input_Event_Information);
|
||||
handler_get_event_information_set(OBJECT_ANALOG_VALUE,
|
||||
Analog_Value_Event_Information);
|
||||
|
||||
#endif /* defined(INTRINSIC_REPORTING) */
|
||||
}
|
||||
|
||||
@@ -169,7 +164,7 @@ int main(
|
||||
0
|
||||
}; /* address where message came from */
|
||||
uint16_t pdu_len = 0;
|
||||
unsigned timeout = 1000; /* milliseconds */
|
||||
unsigned timeout = 100; /* milliseconds */
|
||||
time_t last_seconds = 0;
|
||||
time_t current_seconds = 0;
|
||||
uint32_t elapsed_seconds = 0;
|
||||
|
||||
@@ -50,6 +50,14 @@ typedef struct {
|
||||
BACNET_TIMESTAMP ackTimeStamp;
|
||||
} BACNET_ALARM_ACK_DATA;
|
||||
|
||||
/* return +1 if alarm was acknowledged
|
||||
return -1 if any error occurred
|
||||
return -2 abort */
|
||||
typedef int (
|
||||
*alarm_ack_function) (
|
||||
BACNET_ALARM_ACK_DATA * alarmack_data,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "wp.h"
|
||||
#include "readrange.h"
|
||||
#include "getevent.h"
|
||||
#include "alarm_ack.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -250,6 +251,10 @@ extern "C" {
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
void handler_alarm_ack_set(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
alarm_ack_function pFunction);
|
||||
|
||||
void handler_conf_private_trans(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
|
||||
@@ -75,6 +75,7 @@ HANDLER_SRC = \
|
||||
$(BACNET_HANDLER)/h_rr.c \
|
||||
$(BACNET_HANDLER)/h_wp.c \
|
||||
$(BACNET_HANDLER)/h_wpm.c \
|
||||
$(BACNET_HANDLER)/h_alarm_ack.c \
|
||||
$(BACNET_HANDLER)/h_arf.c \
|
||||
$(BACNET_HANDLER)/h_arf_a.c \
|
||||
$(BACNET_HANDLER)/h_awf.c \
|
||||
|
||||
Reference in New Issue
Block a user