First version of Trend Log which will actually log real data.
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
#include "bacdef.h"
|
#include "bacdef.h"
|
||||||
#include "bacdcode.h"
|
#include "bacdcode.h"
|
||||||
#include "bacerror.h"
|
#include "bacerror.h"
|
||||||
|
#include "bacdevobjpropref.h"
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "npdu.h"
|
#include "npdu.h"
|
||||||
#include "abort.h"
|
#include "abort.h"
|
||||||
@@ -59,7 +60,7 @@ void handler_read_property_object_set(
|
|||||||
int Encode_Property_APDU(
|
int Encode_Property_APDU(
|
||||||
uint8_t * apdu,
|
uint8_t * apdu,
|
||||||
BACNET_OBJECT_TYPE object_type,
|
BACNET_OBJECT_TYPE object_type,
|
||||||
uint32_t object_instance,
|
uint32_t object_instance,
|
||||||
BACNET_PROPERTY_ID property,
|
BACNET_PROPERTY_ID property,
|
||||||
int32_t array_index,
|
int32_t array_index,
|
||||||
BACNET_ERROR_CLASS * error_class,
|
BACNET_ERROR_CLASS * error_class,
|
||||||
@@ -190,3 +191,29 @@ void handler_read_property(
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int local_read_property(
|
||||||
|
uint8_t * value,
|
||||||
|
uint8_t * status,
|
||||||
|
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *Source,
|
||||||
|
BACNET_ERROR_CLASS * error_class,
|
||||||
|
BACNET_ERROR_CODE * error_code)
|
||||||
|
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
/* Try to fetch the required property */
|
||||||
|
len = Encode_Property_APDU(value, Source->objectIdentifier.type,
|
||||||
|
Source->objectIdentifier.instance, Source->propertyIdentifier,
|
||||||
|
Source->arrayIndex, error_class, error_code);
|
||||||
|
|
||||||
|
if((len >= 0) && (status != NULL)){
|
||||||
|
/* Fetch the status flags if required */
|
||||||
|
Encode_Property_APDU(status, Source->objectIdentifier.type,
|
||||||
|
Source->objectIdentifier.instance, PROP_STATUS_FLAGS,
|
||||||
|
0, error_class, error_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(len);
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,10 +32,8 @@
|
|||||||
#include "bacdcode.h"
|
#include "bacdcode.h"
|
||||||
#include "bacenum.h"
|
#include "bacenum.h"
|
||||||
#include "config.h" /* the custom stuff */
|
#include "config.h" /* the custom stuff */
|
||||||
|
#include "ai.h"
|
||||||
|
|
||||||
#ifndef MAX_ANALOG_INPUTS
|
|
||||||
#define MAX_ANALOG_INPUTS 7
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static float Present_Value[MAX_ANALOG_INPUTS];
|
static float Present_Value[MAX_ANALOG_INPUTS];
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
*
|
*
|
||||||
* Copyright (C) Peter Mc Shane
|
* Copyright (C) 2009 Peter Mc Shane
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
@@ -113,7 +113,7 @@ typedef struct tl_log_info {
|
|||||||
uint32_t ulIntervalOffset; /* Offset from start of period for taking reading in seconds */
|
uint32_t ulIntervalOffset; /* Offset from start of period for taking reading in seconds */
|
||||||
bool bTrigger; /* Set to 1 to cause a reading to be taken */
|
bool bTrigger; /* Set to 1 to cause a reading to be taken */
|
||||||
int iIndex; /* Current insertion point */
|
int iIndex; /* Current insertion point */
|
||||||
bool bClocked; /* True if ulTotalRecordCount has wrapped around */
|
time_t tLastDataTime;
|
||||||
} TL_LOG_INFO;
|
} TL_LOG_INFO;
|
||||||
|
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ void Trend_Log_Init(
|
|||||||
int iLog;
|
int iLog;
|
||||||
int iEntry;
|
int iEntry;
|
||||||
struct tm TempTime;
|
struct tm TempTime;
|
||||||
time_t Clock;
|
time_t tClock;
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initialized = true;
|
initialized = true;
|
||||||
@@ -285,10 +285,10 @@ void Trend_Log_Init(
|
|||||||
TempTime.tm_hour = 0;
|
TempTime.tm_hour = 0;
|
||||||
TempTime.tm_min = 0;
|
TempTime.tm_min = 0;
|
||||||
TempTime.tm_sec = 0;
|
TempTime.tm_sec = 0;
|
||||||
Clock = mktime(&TempTime);
|
tClock = mktime(&TempTime);
|
||||||
|
|
||||||
for(iEntry = 0; iEntry < TL_MAX_ENTRIES; iEntry++) {
|
for(iEntry = 0; iEntry < TL_MAX_ENTRIES; iEntry++) {
|
||||||
Logs[iLog][iEntry].tTimeStamp = Clock;
|
Logs[iLog][iEntry].tTimeStamp = tClock;
|
||||||
Logs[iLog][iEntry].ucRecType = TL_TYPE_REAL;
|
Logs[iLog][iEntry].ucRecType = TL_TYPE_REAL;
|
||||||
Logs[iLog][iEntry].Datum.fReal = (float)(iEntry + (iLog * TL_MAX_ENTRIES));
|
Logs[iLog][iEntry].Datum.fReal = (float)(iEntry + (iLog * TL_MAX_ENTRIES));
|
||||||
/* Put status flags with every second log */
|
/* Put status flags with every second log */
|
||||||
@@ -296,9 +296,10 @@ void Trend_Log_Init(
|
|||||||
Logs[iLog][iEntry].ucStatus = 128;
|
Logs[iLog][iEntry].ucStatus = 128;
|
||||||
else
|
else
|
||||||
Logs[iLog][iEntry].ucStatus = 0;
|
Logs[iLog][iEntry].ucStatus = 0;
|
||||||
Clock += 900; /* advance 15 minutes */
|
tClock += 900; /* advance 15 minutes */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogInfo[iLog].tLastDataTime = tClock - 900;
|
||||||
LogInfo[iLog].bAlignIntervals = true;
|
LogInfo[iLog].bAlignIntervals = true;
|
||||||
LogInfo[iLog].bEnable = true;
|
LogInfo[iLog].bEnable = true;
|
||||||
LogInfo[iLog].bStopWhenFull = false;
|
LogInfo[iLog].bStopWhenFull = false;
|
||||||
@@ -311,12 +312,12 @@ void Trend_Log_Init(
|
|||||||
LogInfo[iLog].ulLogInterval = 900;
|
LogInfo[iLog].ulLogInterval = 900;
|
||||||
LogInfo[iLog].ulRecordCount = 1000;
|
LogInfo[iLog].ulRecordCount = 1000;
|
||||||
LogInfo[iLog].ulTotalRecordCount = 10000;
|
LogInfo[iLog].ulTotalRecordCount = 10000;
|
||||||
LogInfo[iLog].bClocked = false;
|
|
||||||
|
|
||||||
LogInfo[iLog].Source.deviceIndentifier.instance = Device_Object_Instance_Number();
|
LogInfo[iLog].Source.deviceIndentifier.instance = Device_Object_Instance_Number();
|
||||||
LogInfo[iLog].Source.deviceIndentifier.type = OBJECT_DEVICE;
|
LogInfo[iLog].Source.deviceIndentifier.type = OBJECT_DEVICE;
|
||||||
LogInfo[iLog].Source.objectIdentifier.instance = iLog;
|
LogInfo[iLog].Source.objectIdentifier.instance = iLog;
|
||||||
LogInfo[iLog].Source.objectIdentifier.type = OBJECT_ANALOG_INPUT;
|
LogInfo[iLog].Source.objectIdentifier.type = OBJECT_ANALOG_INPUT;
|
||||||
|
LogInfo[iLog].Source.arrayIndex = BACNET_ARRAY_ALL;
|
||||||
LogInfo[iLog].Source.propertyIdentifier = PROP_PRESENT_VALUE;
|
LogInfo[iLog].Source.propertyIdentifier = PROP_PRESENT_VALUE;
|
||||||
|
|
||||||
datetime_set_values(&LogInfo[iLog].StartTime, 2009, 1, 1, 0, 0, 0, 0);
|
datetime_set_values(&LogInfo[iLog].StartTime, 2009, 1, 1, 0, 0, 0, 0);
|
||||||
@@ -740,6 +741,7 @@ bool Trend_Log_Write_Property(
|
|||||||
|
|
||||||
case PROP_LOG_DEVICE_OBJECT_PROPERTY:
|
case PROP_LOG_DEVICE_OBJECT_PROPERTY:
|
||||||
memset(&TempSource, 0, sizeof(TempSource)); /* Start with clean sheet */
|
memset(&TempSource, 0, sizeof(TempSource)); /* Start with clean sheet */
|
||||||
|
TempSource.arrayIndex = BACNET_ARRAY_ALL; /* Need this so if no array index set we read properties in full */
|
||||||
|
|
||||||
/* First up is the object ID */
|
/* First up is the object ID */
|
||||||
len = bacapp_decode_context_data(wp_data->application_data, wp_data->application_data_len, &value, PROP_LOG_DEVICE_OBJECT_PROPERTY);
|
len = bacapp_decode_context_data(wp_data->application_data, wp_data->application_data_len, &value, PROP_LOG_DEVICE_OBJECT_PROPERTY);
|
||||||
@@ -863,12 +865,19 @@ bool Trend_Log_Write_Property(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PROP_TRIGGER:
|
case PROP_TRIGGER:
|
||||||
/* To Do - implement trigger logic as per
|
|
||||||
* 12.25.30
|
|
||||||
*/
|
|
||||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||||
CurrentLog->bTrigger = value.type.Boolean;
|
/* We will not allow triggered operation if polling with aligning
|
||||||
status = true;
|
* to the clock as that will produce non aligned readings which
|
||||||
|
* goes against the reason for selscting this mode
|
||||||
|
*/
|
||||||
|
if((CurrentLog->LoggingType == LOGGING_TYPE_POLLED) &&
|
||||||
|
(CurrentLog->bAlignIntervals == true)) {
|
||||||
|
*error_class = ERROR_CLASS_PROPERTY;
|
||||||
|
*error_code = ERROR_CODE_NOT_CONFIGURED_FOR_TRIGGERED_LOGGING;
|
||||||
|
} else {
|
||||||
|
CurrentLog->bTrigger = value.type.Boolean;
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
*error_class = ERROR_CLASS_PROPERTY;
|
*error_class = ERROR_CLASS_PROPERTY;
|
||||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||||
@@ -953,8 +962,6 @@ void TL_Insert_Status_Rec(int iLog, BACNET_LOG_STATUS eStatus, bool bState)
|
|||||||
CurrentLog->iIndex = 0;
|
CurrentLog->iIndex = 0;
|
||||||
|
|
||||||
CurrentLog->ulTotalRecordCount++;
|
CurrentLog->ulTotalRecordCount++;
|
||||||
if(CurrentLog->ulTotalRecordCount == 0)
|
|
||||||
CurrentLog->bClocked = true;
|
|
||||||
|
|
||||||
if(CurrentLog->ulRecordCount < TL_MAX_ENTRIES)
|
if(CurrentLog->ulRecordCount < TL_MAX_ENTRIES)
|
||||||
CurrentLog->ulRecordCount++;
|
CurrentLog->ulRecordCount++;
|
||||||
@@ -968,7 +975,7 @@ void TL_Insert_Status_Rec(int iLog, BACNET_LOG_STATUS eStatus, bool bState)
|
|||||||
bool TL_Is_Enabled(int iLog)
|
bool TL_Is_Enabled(int iLog)
|
||||||
{
|
{
|
||||||
TL_LOG_INFO *CurrentLog;
|
TL_LOG_INFO *CurrentLog;
|
||||||
time_t Now;
|
time_t tNow;
|
||||||
bool bStatus;
|
bool bStatus;
|
||||||
|
|
||||||
bStatus = true;
|
bStatus = true;
|
||||||
@@ -984,24 +991,24 @@ bool TL_Is_Enabled(int iLog)
|
|||||||
bStatus = false;
|
bStatus = false;
|
||||||
} else if(CurrentLog->ucTimeFlags != (TL_T_START_WILD | TL_T_STOP_WILD)) {
|
} else if(CurrentLog->ucTimeFlags != (TL_T_START_WILD | TL_T_STOP_WILD)) {
|
||||||
/* enabled and either 1 wild card or none */
|
/* enabled and either 1 wild card or none */
|
||||||
Now = time(NULL);
|
tNow = time(NULL);
|
||||||
#if 0
|
#if 0
|
||||||
printf("\nFlags - %u, Current - %u, Start - %u, Stop - %u\n", (unsigned int)CurrentLog->ucTimeFlags,(unsigned int)Now, (unsigned int)CurrentLog->tStartTime, (unsigned int)CurrentLog->tStopTime);
|
printf("\nFlags - %u, Current - %u, Start - %u, Stop - %u\n", (unsigned int)CurrentLog->ucTimeFlags,(unsigned int)Now, (unsigned int)CurrentLog->tStartTime, (unsigned int)CurrentLog->tStopTime);
|
||||||
#endif
|
#endif
|
||||||
if((CurrentLog->ucTimeFlags & TL_T_START_WILD) != 0) {
|
if((CurrentLog->ucTimeFlags & TL_T_START_WILD) != 0) {
|
||||||
/* wild card start time */
|
/* wild card start time */
|
||||||
if(Now > CurrentLog->tStopTime)
|
if(tNow > CurrentLog->tStopTime)
|
||||||
bStatus = false;
|
bStatus = false;
|
||||||
} else if((CurrentLog->ucTimeFlags & TL_T_STOP_WILD) != 0) {
|
} else if((CurrentLog->ucTimeFlags & TL_T_STOP_WILD) != 0) {
|
||||||
/* wild card stop time */
|
/* wild card stop time */
|
||||||
if(Now < CurrentLog->tStartTime)
|
if(tNow < CurrentLog->tStartTime)
|
||||||
bStatus = false;
|
bStatus = false;
|
||||||
} else {
|
} else {
|
||||||
#if 0
|
#if 0
|
||||||
printf("\nCurrent - %u, Start - %u, Stop - %u\n", (unsigned int)Now, (unsigned int)CurrentLog->tStartTime, (unsigned int)CurrentLog->tStopTime);
|
printf("\nCurrent - %u, Start - %u, Stop - %u\n", (unsigned int)Now, (unsigned int)CurrentLog->tStartTime, (unsigned int)CurrentLog->tStopTime);
|
||||||
#endif
|
#endif
|
||||||
/* No wildcards so use both times */
|
/* No wildcards so use both times */
|
||||||
if((Now < CurrentLog->tStartTime) || (Now > CurrentLog->tStopTime))
|
if((tNow < CurrentLog->tStartTime) || (tNow > CurrentLog->tStopTime))
|
||||||
bStatus = false;
|
bStatus = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1571,10 +1578,179 @@ int TL_encode_entry(uint8_t *apdu, int iLog, int iEntry)
|
|||||||
if((pSource->ucStatus & 128) == 128) {
|
if((pSource->ucStatus & 128) == 128) {
|
||||||
bitstring_init(&TempBits);
|
bitstring_init(&TempBits);
|
||||||
bitstring_set_bits_used(&TempBits, 1, 4);
|
bitstring_set_bits_used(&TempBits, 1, 4);
|
||||||
/* only insert the 1st 4 bits - in BACnet order */
|
/* only insert the 1st 4 bits */
|
||||||
bitstring_set_octet(&TempBits, 0, (pSource->Datum.ucLogStatus & 0xF0));
|
bitstring_set_octet(&TempBits, 0, (pSource->Datum.ucLogStatus & 0x0F));
|
||||||
iLen += encode_context_bitstring(&apdu[iLen], 2, &TempBits);
|
iLen += encode_context_bitstring(&apdu[iLen], 2, &TempBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(iLen);
|
return(iLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Attempt to fetch the logged property and store it in the Trend Log *
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void TL_fetch_property(int iLog)
|
||||||
|
|
||||||
|
{
|
||||||
|
uint8_t ValueBuf[MAX_APDU]; /* This is a big buffer in case someone selects the device object list for example */
|
||||||
|
uint8_t StatusBuf[3]; /* Should be tag, bits unused in last octet and 1 byte of data */
|
||||||
|
BACNET_ERROR_CLASS error_class;
|
||||||
|
BACNET_ERROR_CODE error_code;
|
||||||
|
int iLen;
|
||||||
|
int iCount;
|
||||||
|
TL_LOG_INFO *CurrentLog;
|
||||||
|
TL_DATA_REC TempRec;
|
||||||
|
uint8_t tag_number = 0;
|
||||||
|
uint32_t len_value_type = 0;
|
||||||
|
BACNET_BIT_STRING TempBits;
|
||||||
|
|
||||||
|
CurrentLog = &LogInfo[iLog];
|
||||||
|
|
||||||
|
/* Record the current time in the log entry and also in the info block
|
||||||
|
* for the log so we can figure out when the next reading is due */
|
||||||
|
TempRec.tTimeStamp = time(NULL);
|
||||||
|
CurrentLog->tLastDataTime = TempRec.tTimeStamp;
|
||||||
|
TempRec.ucStatus = 0;
|
||||||
|
|
||||||
|
iLen = local_read_property(ValueBuf, StatusBuf, &LogInfo[iLog].Source, &error_class, &error_code);
|
||||||
|
if(iLen < 0) {
|
||||||
|
/* Insert error code into log */
|
||||||
|
TempRec.Datum.Error.usClass = error_class;
|
||||||
|
TempRec.Datum.Error.usCode = error_code;
|
||||||
|
TempRec.ucRecType = TL_TYPE_ERROR;
|
||||||
|
} else {
|
||||||
|
/* Decode data returned and see if we can fit it into the log */
|
||||||
|
iLen = decode_tag_number_and_value(ValueBuf, &tag_number, &len_value_type);
|
||||||
|
switch(tag_number) {
|
||||||
|
case BACNET_APPLICATION_TAG_NULL:
|
||||||
|
TempRec.ucRecType = TL_TYPE_NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BACNET_APPLICATION_TAG_BOOLEAN:
|
||||||
|
TempRec.ucRecType = TL_TYPE_BOOL;
|
||||||
|
TempRec.Datum.ucBoolean = decode_boolean(len_value_type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
|
||||||
|
TempRec.ucRecType = TL_TYPE_UNSIGN;
|
||||||
|
decode_unsigned(&ValueBuf[iLen], len_value_type, &TempRec.Datum.ulUValue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BACNET_APPLICATION_TAG_SIGNED_INT:
|
||||||
|
TempRec.ucRecType = TL_TYPE_SIGN;
|
||||||
|
decode_signed(&ValueBuf[iLen], len_value_type, &TempRec.Datum.lSValue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BACNET_APPLICATION_TAG_REAL:
|
||||||
|
TempRec.ucRecType = TL_TYPE_REAL;
|
||||||
|
decode_real_safe(&ValueBuf[iLen], len_value_type, &TempRec.Datum.fReal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BACNET_APPLICATION_TAG_BIT_STRING:
|
||||||
|
TempRec.ucRecType = TL_TYPE_BITS;
|
||||||
|
decode_bitstring(&ValueBuf[iLen], len_value_type, &TempBits);
|
||||||
|
/* We truncate any bitstrings at 32 bits to conserve space */
|
||||||
|
if(bitstring_bits_used(&TempBits) < 32) {
|
||||||
|
/* Store the bytes used and the bits free in the last byte */
|
||||||
|
TempRec.Datum.Bits.ucLen = bitstring_bytes_used(&TempBits) << 4;
|
||||||
|
TempRec.Datum.Bits.ucLen |= (8 - (bitstring_bits_used(&TempBits) % 8)) & 7;
|
||||||
|
/* Fetch the octets with the bits directly */
|
||||||
|
for(iCount = 0; iCount < bitstring_bytes_used(&TempBits); iCount++)
|
||||||
|
TempRec.Datum.Bits.ucStore[iCount] = bitstring_octet(&TempBits, iCount);
|
||||||
|
} else {
|
||||||
|
/* We will only use the first 4 octets to save space */
|
||||||
|
TempRec.Datum.Bits.ucLen = 4 << 4;
|
||||||
|
for(iCount = 0; iCount < 4; iCount++)
|
||||||
|
TempRec.Datum.Bits.ucStore[iCount] = bitstring_octet(&TempBits, iCount);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BACNET_APPLICATION_TAG_ENUMERATED:
|
||||||
|
TempRec.ucRecType = TL_TYPE_ENUM;
|
||||||
|
decode_enumerated(&ValueBuf[iLen], len_value_type, &TempRec.Datum.ulEnum);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Fake an error response for any types we cannot handle */
|
||||||
|
TempRec.Datum.Error.usClass = ERROR_CLASS_PROPERTY;
|
||||||
|
TempRec.Datum.Error.usCode = ERROR_CODE_DATATYPE_NOT_SUPPORTED;
|
||||||
|
TempRec.ucRecType = TL_TYPE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Finally insert the status flags into the record */
|
||||||
|
iLen += decode_tag_number_and_value(StatusBuf, &tag_number, &len_value_type);
|
||||||
|
decode_bitstring(&ValueBuf[iLen], len_value_type, &TempBits);
|
||||||
|
TempRec.ucStatus = 128 | bitstring_octet(&TempBits,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logs[iLog][CurrentLog->iIndex++] = TempRec;
|
||||||
|
if(CurrentLog->iIndex >= TL_MAX_ENTRIES)
|
||||||
|
CurrentLog->iIndex = 0;
|
||||||
|
|
||||||
|
CurrentLog->ulTotalRecordCount++;
|
||||||
|
|
||||||
|
if(CurrentLog->ulRecordCount < TL_MAX_ENTRIES)
|
||||||
|
CurrentLog->ulRecordCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Check each log to see if any data needs to be recorded. *
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void trend_log_timer(
|
||||||
|
uint16_t uSeconds)
|
||||||
|
{
|
||||||
|
TL_LOG_INFO *CurrentLog;
|
||||||
|
int iCount;
|
||||||
|
time_t tNow;
|
||||||
|
|
||||||
|
tNow = time(NULL);
|
||||||
|
for(iCount = 0; iCount < MAX_TREND_LOGS; iCount++) {
|
||||||
|
CurrentLog = &LogInfo[iCount];
|
||||||
|
if(CurrentLog->LoggingType == LOGGING_TYPE_POLLED) {
|
||||||
|
/* For polled logs we first need to see if they are clock
|
||||||
|
* aligned or not.
|
||||||
|
*/
|
||||||
|
if(CurrentLog->bAlignIntervals == true) {
|
||||||
|
/* Aligned logging so use the combination of the interval
|
||||||
|
* and the offset to decide when to log. Also log a reading if
|
||||||
|
* more than interval time has elapsed since last reading to ensure
|
||||||
|
* we don't miss a reading if we aren't called at the precise second
|
||||||
|
* when the match occurrs.
|
||||||
|
*/
|
||||||
|
// if(((tNow % CurrentLog->ulLogInterval) >= (CurrentLog->ulIntervalOffset % CurrentLog->ulLogInterval)) &&
|
||||||
|
// ((tNow - CurrentLog->tLastDataTime) >= CurrentLog->ulLogInterval)) {
|
||||||
|
if((tNow % CurrentLog->ulLogInterval) == (CurrentLog->ulIntervalOffset % CurrentLog->ulLogInterval)) {
|
||||||
|
/* Record value if time synchronised trigger condition is met
|
||||||
|
* and at least one period has elapsed.
|
||||||
|
*/
|
||||||
|
TL_fetch_property(iCount);
|
||||||
|
} else if((tNow - CurrentLog->tLastDataTime) > CurrentLog->ulLogInterval) {
|
||||||
|
/* Also record value if we have waited more than a period
|
||||||
|
* since the last reading. This ensures we take a reading as
|
||||||
|
* soon as possible after a power down if we have been off for
|
||||||
|
* more than a single period.
|
||||||
|
*/
|
||||||
|
TL_fetch_property(iCount);
|
||||||
|
}
|
||||||
|
} else if(((tNow - CurrentLog->tLastDataTime) >= CurrentLog->ulLogInterval) ||
|
||||||
|
(CurrentLog->bTrigger == true)) {
|
||||||
|
/* If not aligned take a reading when we have either waited long
|
||||||
|
* enough or a trigger is set.
|
||||||
|
*/
|
||||||
|
TL_fetch_property(iCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentLog->bTrigger = false; /* Clear this every time */
|
||||||
|
} else if(CurrentLog->LoggingType == LOGGING_TYPE_TRIGGERED) {
|
||||||
|
/* Triggered logs take a reading when the trigger is set and
|
||||||
|
* then reset the trigger to wait for the next event
|
||||||
|
*/
|
||||||
|
if(CurrentLog->bTrigger == true) {
|
||||||
|
TL_fetch_property(iCount);
|
||||||
|
CurrentLog->bTrigger = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -296,7 +296,8 @@ int main(
|
|||||||
int iCount = 0;
|
int iCount = 0;
|
||||||
int iType = 0;
|
int iType = 0;
|
||||||
int iKey;
|
int iKey;
|
||||||
static int iLimit[3] = { 7, 11, 7 };
|
int iSecondsRun = 0;
|
||||||
|
|
||||||
|
|
||||||
if (((argc != 2) && (argc != 3)) || ((argc >= 2) &&
|
if (((argc != 2) && (argc != 3)) || ((argc >= 2) &&
|
||||||
(strcmp(argv[1], "--help") == 0))) {
|
(strcmp(argv[1], "--help") == 0))) {
|
||||||
@@ -352,8 +353,6 @@ int main(
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
/* increment timer - exit if timed out */
|
/* increment timer - exit if timed out */
|
||||||
current_seconds = time(NULL);
|
current_seconds = time(NULL);
|
||||||
if (current_seconds != last_seconds) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns 0 bytes on timeout */
|
/* returns 0 bytes on timeout */
|
||||||
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
|
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
|
||||||
@@ -365,10 +364,16 @@ int main(
|
|||||||
/* at least one second has passed */
|
/* at least one second has passed */
|
||||||
if (current_seconds != last_seconds) {
|
if (current_seconds != last_seconds) {
|
||||||
putchar('.'); /* Just to show that time is passing... */
|
putchar('.'); /* Just to show that time is passing... */
|
||||||
last_seconds = current_seconds;
|
tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000));
|
||||||
tsm_timer_milliseconds(((current_seconds -
|
|
||||||
last_seconds) * 1000));
|
|
||||||
address_cache_timer(current_seconds - last_seconds);
|
address_cache_timer(current_seconds - last_seconds);
|
||||||
|
trend_log_timer(current_seconds - last_seconds);
|
||||||
|
last_seconds = current_seconds;
|
||||||
|
/* Change the analog input PVs for testing purposes */
|
||||||
|
for(iCount = 0; iCount < MAX_ANALOG_INPUTS; iCount++) {
|
||||||
|
Analog_Input_Present_Value_Set(iCount, iSecondsRun * (iCount + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
iSecondsRun++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_kbhit()) {
|
if (_kbhit()) {
|
||||||
@@ -403,9 +408,10 @@ int main(
|
|||||||
}
|
}
|
||||||
/* at least one second has passed */
|
/* at least one second has passed */
|
||||||
if (current_seconds != last_seconds) {
|
if (current_seconds != last_seconds) {
|
||||||
tsm_timer_milliseconds(((current_seconds -
|
tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000));
|
||||||
last_seconds) * 1000));
|
|
||||||
address_cache_timer(current_seconds - last_seconds);
|
address_cache_timer(current_seconds - last_seconds);
|
||||||
|
trend_log_timer(current_seconds - last_seconds);
|
||||||
|
last_seconds = current_seconds;
|
||||||
}
|
}
|
||||||
if (Error_Detected)
|
if (Error_Detected)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -32,6 +32,11 @@
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifndef MAX_ANALOG_INPUTS
|
||||||
|
#define MAX_ANALOG_INPUTS 7
|
||||||
|
#endif
|
||||||
|
|
||||||
void Analog_Input_Property_Lists(
|
void Analog_Input_Property_Lists(
|
||||||
const int **pRequired,
|
const int **pRequired,
|
||||||
const int **pOptional,
|
const int **pOptional,
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ extern "C" {
|
|||||||
BACNET_ADDRESS * src,
|
BACNET_ADDRESS * src,
|
||||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||||
|
|
||||||
|
int local_read_property(
|
||||||
|
uint8_t * value,
|
||||||
|
uint8_t * status,
|
||||||
|
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *Source,
|
||||||
|
BACNET_ERROR_CLASS * error_class,
|
||||||
|
BACNET_ERROR_CODE * error_code);
|
||||||
|
|
||||||
void handler_rr_object_set(
|
void handler_rr_object_set(
|
||||||
BACNET_OBJECT_TYPE object_type,
|
BACNET_OBJECT_TYPE object_type,
|
||||||
rr_info_function pFunction1);
|
rr_info_function pFunction1);
|
||||||
|
|||||||
@@ -119,6 +119,9 @@ extern "C" {
|
|||||||
BACNET_ERROR_CLASS *error_class,
|
BACNET_ERROR_CLASS *error_class,
|
||||||
BACNET_ERROR_CODE *error_code);
|
BACNET_ERROR_CODE *error_code);
|
||||||
|
|
||||||
|
void trend_log_timer(
|
||||||
|
uint16_t uSeconds);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
Reference in New Issue
Block a user