text:
#include <stdbool.h>
#include <stdint.h>
#include <string.h>     /* for memmove */
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "bacapp.h"
#include "config.h"     /* the custom stuff */
#include "apdu.h"
#include "wp.h" /* write property handling */
#include "version.h"
#include "device.h"     /* me */
#include "handlers.h"
#include "datalink.h"
#include "address.h"
#include "bacdevobjpropref.h"
#include "trendlog.h"
#if defined(BACFILE)
#include "bacfile.h"    /* object list dependency */
#endif

/* number of demo objects */
#ifndef MAX_TREND_LOGS
#define MAX_TREND_LOGS 8
#endif

TL_DATA_REC Logs[MAX_TREND_LOGS][TL_MAX_ENTRIES];
static TL_LOG_INFO LogInfo[MAX_TREND_LOGS];

/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Trend_Log_Properties_Required[] = {
    PROP_OBJECT_IDENTIFIER,
    PROP_OBJECT_NAME,
    PROP_OBJECT_TYPE,
    PROP_ENABLE,
    PROP_STOP_WHEN_FULL,
    PROP_BUFFER_SIZE,
    PROP_LOG_BUFFER,
    PROP_RECORD_COUNT,
    PROP_TOTAL_RECORD_COUNT,
    PROP_EVENT_STATE,
    PROP_LOGGING_TYPE,
    PROP_STATUS_FLAGS,
    -1
};

static const int Trend_Log_Properties_Optional[] = {
    PROP_DESCRIPTION,
    PROP_START_TIME,
    PROP_STOP_TIME,
    PROP_LOG_DEVICE_OBJECT_PROPERTY,
    PROP_LOG_INTERVAL,

/* Required if COV logging supported
    PROP_COV_RESUBSCRIPTION_INTERVAL,
    PROP_CLIENT_COV_INCREMENT, */

/* Required if intrinsic reporting supported
    PROP_NOTIFICATION_THRESHOLD,
    PROP_RECORDS_SINCE_NOTIFICATION,
    PROP_LAST_NOTIFY_RECORD,
    PROP_NOTIFICATION_CLASS,
    PROP_EVENT_ENABLE,
    PROP_ACKED_TRANSITIONS,
    PROP_NOTIFY_TYPE,
    PROP_EVENT_TIME_STAMPS, */

    PROP_ALIGN_INTERVALS,
    PROP_INTERVAL_OFFSET,
    PROP_TRIGGER,
    -1
};

static const int Trend_Log_Properties_Proprietary[] = {
    -1
};

void Trend_Log_Property_Lists(
    const int **pRequired,
    const int **pOptional,
    const int **pProprietary)
{
    if (pRequired)
        *pRequired = Trend_Log_Properties_Required;
    if (pOptional)
        *pOptional = Trend_Log_Properties_Optional;
    if (pProprietary)
        *pProprietary = Trend_Log_Properties_Proprietary;

    return;
}

/* we simply have 0-n object instances.  Yours might be */
/* more complex, and then you need validate that the */
/* given instance exists */
bool Trend_Log_Valid_Instance(
    uint32_t object_instance)
{
    if (object_instance < MAX_TREND_LOGS) {
        return true;
    }

    return false;
}

/* we simply have 0-n object instances.  Yours might be */
/* more complex, and then count how many you have */
unsigned Trend_Log_Count(
    void)
{
    return MAX_TREND_LOGS;
}

/* we simply have 0-n object instances.  Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Trend_Log_Index_To_Instance(
    unsigned index)
{
    return index;
}

/* we simply have 0-n object instances.  Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Trend_Log_Instance_To_Index(
    uint32_t object_instance)
{
    unsigned index = MAX_TREND_LOGS;

    if (object_instance < MAX_TREND_LOGS) {
        index = object_instance;
    }

    return index;
}

/*
 * Things to do when starting up the stack for Trend Logs.
 * Should be called whenever we reset the device or power it up
 */
void Trend_Log_Init(
    void)
{
    static bool initialized = false;
    int iLog;
    int iEntry;
    struct tm TempTime;
    time_t tClock;

    if (!initialized) {
        initialized = true;

        /* initialize all the values */

        for (iLog = 0; iLog < MAX_TREND_LOGS; iLog++) {
            /*
             * Do we need to do anything here?
             * Trend logs are usually assumed to survive over resets
             * and are frequently implemented using Battery Backed RAM
             * If they are implemented using Flash or SD cards or some
             * such mechanism there may be some RAM based setup needed
             * for log management purposes.
             * We probably need to look at inserting LOG_INTERRUPTED
             * entries into any active logs if the power down or reset
             * may have caused us to miss readings.
             */

            /* We will just fill the logs with some entries for testing
             * purposes.
             */
            TempTime.tm_year = 109;
            TempTime.tm_mon = iLog + 1; /* Different month for each log */
            TempTime.tm_mday = 1;
            TempTime.tm_hour = 0;
            TempTime.tm_min = 0;
            TempTime.tm_sec = 0;
            tClock = mktime(&TempTime);

            for (iEntry = 0; iEntry < TL_MAX_ENTRIES; iEntry++) {
                Logs[iLog][iEntry].tTimeStamp = tClock;
                Logs[iLog][iEntry].ucRecType = TL_TYPE_REAL;
                Logs[iLog][iEntry].Datum.fReal =
                    (float) (iEntry + (iLog * TL_MAX_ENTRIES));
                /* Put status flags with every second log */
                if ((iLog & 1) == 0)
                    Logs[iLog][iEntry].ucStatus = 128;
                else
                    Logs[iLog][iEntry].ucStatus = 0;
                tClock += 900;  /* advance 15 minutes */
            }

            LogInfo[iLog].tLastDataTime = tClock - 900;
            LogInfo[iLog].bAlignIntervals = true;
            LogInfo[iLog].bEnable = true;
            LogInfo[iLog].bStopWhenFull = false;
            LogInfo[iLog].bTrigger = false;
            LogInfo[iLog].LoggingType = LOGGING_TYPE_POLLED;
            LogInfo[iLog].Source.arrayIndex = 0;
            LogInfo[iLog].ucTimeFlags = 0;
            LogInfo[iLog].ulIntervalOffset = 0;
            LogInfo[iLog].iIndex = 0;
            LogInfo[iLog].ulLogInterval = 900;
            LogInfo[iLog].ulRecordCount = TL_MAX_ENTRIES;
            LogInfo[iLog].ulTotalRecordCount = 10000;

            LogInfo[iLog].Source.deviceIndentifier.instance =
                Device_Object_Instance_Number();
            LogInfo[iLog].Source.deviceIndentifier.type = OBJECT_DEVICE;
            LogInfo[iLog].Source.objectIdentifier.instance = iLog;
            LogInfo[iLog].Source.objectIdentifier.type = OBJECT_ANALOG_INPUT;
            LogInfo[iLog].Source.arrayIndex = BACNET_ARRAY_ALL;
            LogInfo[iLog].Source.propertyIdentifier = PROP_PRESENT_VALUE;

            datetime_set_values(&LogInfo[iLog].StartTime, 2009, 1, 1, 0, 0, 0,
                0);
            LogInfo[iLog].tStartTime =
                TL_BAC_Time_To_Local(&LogInfo[iLog].StartTime);
            datetime_set_values(&LogInfo[iLog].StopTime, 2020, 12, 22, 23, 59,
                59, 99);
            LogInfo[iLog].tStopTime =
                TL_BAC_Time_To_Local(&LogInfo[iLog].StopTime);
        }
    }

    return;
}

/*
 * Note: we use the instance number here and build the name based
 * on the assumption that there is a 1 to 1 correspondance. If there
 * is not we need to convert to index before proceeding.
 */
bool Trend_Log_Object_Name(
    uint32_t object_instance,
    BACNET_CHARACTER_STRING * object_name)
{
    static char text_string[32] = "";   /* okay for single thread */
    bool status = false;

    if (object_instance < MAX_TREND_LOGS) {
        sprintf(text_string, "Trend Log %u", object_instance);
        status = characterstring_init_ansi(object_name, text_string);
    }

    return status;
}

/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error or
   BACNET_STATUS_ABORT for abort message */
int Trend_Log_Read_Property(
    BACNET_READ_PROPERTY_DATA * rpdata)
{
    int apdu_len = 0;   /* return value */
    int len = 0;        /* apdu len intermediate value */
    BACNET_BIT_STRING bit_string;
    BACNET_CHARACTER_STRING char_string;
    TL_LOG_INFO *CurrentLog;
    uint8_t *apdu = NULL;

    if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
        (rpdata->application_data_len == 0)) {
        return 0;
    }
    apdu = rpdata->application_data;
    CurrentLog = &LogInfo[Trend_Log_Instance_To_Index(rpdata->object_instance)];        /* Pin down which log to look at */
    switch (rpdata->object_property) {
        case PROP_OBJECT_IDENTIFIER:
            apdu_len =
                encode_application_object_id(&apdu[0], OBJECT_TRENDLOG,
                rpdata->object_instance);
            break;

        case PROP_DESCRIPTION:
        case PROP_OBJECT_NAME:
            Trend_Log_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_TRENDLOG);
            break;

        case PROP_ENABLE:
            apdu_len =
                encode_application_boolean(&apdu[0], CurrentLog->bEnable);
            break;

        case PROP_STOP_WHEN_FULL:
            apdu_len =
                encode_application_boolean(&apdu[0],
                CurrentLog->bStopWhenFull);
            break;

        case PROP_BUFFER_SIZE:
            apdu_len = encode_application_unsigned(&apdu[0], TL_MAX_ENTRIES);
            break;

        case PROP_LOG_BUFFER:
            /* You can only read the buffer via the ReadRange service */
            rpdata->error_class = ERROR_CLASS_PROPERTY;
            rpdata->error_code = ERROR_CODE_READ_ACCESS_DENIED;
            apdu_len = BACNET_STATUS_ERROR;
            break;

        case PROP_RECORD_COUNT:
            apdu_len +=
                encode_application_unsigned(&apdu[0],
                CurrentLog->ulRecordCount);
            break;

        case PROP_TOTAL_RECORD_COUNT:
            apdu_len +=
                encode_application_unsigned(&apdu[0],
                CurrentLog->ulTotalRecordCount);
            break;

        case PROP_EVENT_STATE:
            /* note: see the details in the standard on how to use this */
            apdu_len =
                encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
            break;

        case PROP_LOGGING_TYPE:
            apdu_len =
                encode_application_enumerated(&apdu[0],
                CurrentLog->LoggingType);
            break;

        case PROP_STATUS_FLAGS:
            /* note: see the details in the standard on how to use these */
            bitstring_init(&bit_string);
            bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
            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);
            apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
            break;

        case PROP_START_TIME:
            len =
                encode_application_date(&apdu[0], &CurrentLog->StartTime.date);
            apdu_len = len;
            len =
                encode_application_time(&apdu[apdu_len],
                &CurrentLog->StartTime.time);
            apdu_len += len;
            break;

        case PROP_STOP_TIME:
            len =
                encode_application_date(&apdu[0], &CurrentLog->StopTime.date);
            apdu_len = len;
            len =
                encode_application_time(&apdu[apdu_len],
                &CurrentLog->StopTime.time);
            apdu_len += len;
            break;

        case PROP_LOG_DEVICE_OBJECT_PROPERTY:
            /*
             * BACnetDeviceObjectPropertyReference ::= SEQUENCE {
             *     objectIdentifier   [0] BACnetObjectIdentifier,
             *     propertyIdentifier [1] BACnetPropertyIdentifier,
             *     propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
             *                                               -- if omitted with an array then
             *                                               -- the entire array is referenced
             *     deviceIdentifier   [3] BACnetObjectIdentifier OPTIONAL
             * }
             */
            apdu_len +=
                bacapp_encode_device_obj_property_ref(&apdu[0],
                &CurrentLog->Source);
            break;

        case PROP_LOG_INTERVAL:
            /* We only log to 1 sec accuracy so must multiply by 100 before passing it on */
            apdu_len +=
                encode_application_unsigned(&apdu[0],
                CurrentLog->ulLogInterval * 100);
            break;

        case PROP_ALIGN_INTERVALS:
            apdu_len =
                encode_application_boolean(&apdu[0],
                CurrentLog->bAlignIntervals);
            break;

        case PROP_INTERVAL_OFFSET:
            /* We only log to 1 sec accuracy so must multiply by 100 before passing it on */
            apdu_len +=
                encode_application_unsigned(&apdu[0],
                CurrentLog->ulIntervalOffset * 100);
            break;

        case PROP_TRIGGER:
            apdu_len =
                encode_application_boolean(&apdu[0], CurrentLog->bTrigger);
            break;

        default:
            rpdata->error_class = ERROR_CLASS_PROPERTY;
            rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
            apdu_len = BACNET_STATUS_ERROR;
            break;
    }
    /*  only array properties can have array options */
    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;
        apdu_len = BACNET_STATUS_ERROR;
    }

    return apdu_len;
}

/* returns true if successful */
bool Trend_Log_Write_Property(
    BACNET_WRITE_PROPERTY_DATA * wp_data)
{
    bool status = false;        /* return value */
    int len = 0;
    int iOffset = 0;
    BACNET_APPLICATION_DATA_VALUE value;
    TL_LOG_INFO *CurrentLog;
    BACNET_DATE TempDate;       /* build here in case of error in time half of datetime */
    BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE TempSource;
    bool bEffectiveEnable;
    int log_index;

    /* Pin down which log to look at */
    log_index = Trend_Log_Instance_To_Index(wp_data->object_instance);
    CurrentLog = &LogInfo[log_index];

    /* 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;
    }
    if ((wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
        (wp_data->array_index != BACNET_ARRAY_ALL)) {
        /*  only array properties can have array options */
        wp_data->error_class = ERROR_CLASS_PROPERTY;
        wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
        return false;
    }
    switch (wp_data->object_property) {
        case PROP_ENABLE:
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
                &wp_data->error_class, &wp_data->error_code);
            if (status) {
                /* Section 12.25.5 can't enable a full log with stop when full set */
                if ((CurrentLog->bEnable == false) &&
                    (CurrentLog->bStopWhenFull == true) &&
                    (CurrentLog->ulRecordCount == TL_MAX_ENTRIES) &&
                    (value.type.Boolean == true)) {
                    status = false;
                    wp_data->error_class = ERROR_CLASS_OBJECT;
                    wp_data->error_code = ERROR_CODE_LOG_BUFFER_FULL;
                    break;
                }

                /* Only trigger this validation on a potential change of state */
                if (CurrentLog->bEnable != value.type.Boolean) {
                    bEffectiveEnable = TL_Is_Enabled(log_index);
                    CurrentLog->bEnable = value.type.Boolean;
                    /* To do: what actions do we need to take on writing ? */
                    if (value.type.Boolean == false) {
                        if (bEffectiveEnable == true) {
                            /* Only insert record if we really were
                               enabled i.e. times and enable flags */
                            TL_Insert_Status_Rec(log_index,
                                LOG_STATUS_LOG_DISABLED, true);
                        }
                    } else {
                        if (TL_Is_Enabled(log_index)) {
                            /* Have really gone from disabled to enabled as
                             * enable flag and times were correct
                             */
                            TL_Insert_Status_Rec(log_index,
                                LOG_STATUS_LOG_DISABLED, false);
                        }
                    }
                }
            }
            break;

        case PROP_STOP_WHEN_FULL:
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
                &wp_data->error_class, &wp_data->error_code);
            if (status) {
                /* Only trigger this on a change of state */
                if (CurrentLog->bStopWhenFull != value.type.Boolean) {
                    CurrentLog->bStopWhenFull = value.type.Boolean;

                    if ((value.type.Boolean == true) &&
                        (CurrentLog->ulRecordCount == TL_MAX_ENTRIES) &&
                        (CurrentLog->bEnable == true)) {

                        /* When full log is switched from normal to stop when full
                         * disable the log and record the fact - see 135-2008 12.25.12
                         */
                        CurrentLog->bEnable = false;
                        TL_Insert_Status_Rec(log_index,
                            LOG_STATUS_LOG_DISABLED, true);
                    }
                }
            }
            break;

        case PROP_BUFFER_SIZE:
            /* Fixed size buffer so deny write. If buffer size was writable
             * we would probably erase the current log, resize, re-initalise
             * and carry on - however write is not allowed if enable is true.
             */
            wp_data->error_class = ERROR_CLASS_PROPERTY;
            wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
            break;

        case PROP_RECORD_COUNT:
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
                &wp_data->error_class, &wp_data->error_code);
            if (status) {
                if (value.type.Unsigned_Int == 0) {
                    /* Time to clear down the log */
                    CurrentLog->ulRecordCount = 0;
                    CurrentLog->iIndex = 0;
                    TL_Insert_Status_Rec(log_index, LOG_STATUS_BUFFER_PURGED,
                        true);
                }
            }
            break;

        case PROP_LOGGING_TYPE:
            /* logic
             * triggered and polled options.
             */
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
                &wp_data->error_class, &wp_data->error_code);
            if (status) {
                if (value.type.Enumerated != LOGGING_TYPE_COV) {
                    CurrentLog->LoggingType = value.type.Enumerated;
                    if (value.type.Enumerated == LOGGING_TYPE_POLLED) {
                        /* As per 12.25.27 pick a suitable default if interval is 0 */
                        if (CurrentLog->ulLogInterval == 0) {
                            CurrentLog->ulLogInterval = 900;
                        }
                    }
                    if (value.type.Enumerated == LOGGING_TYPE_TRIGGERED) {
                        /* As per 12.25.27 0 the interval if triggered logging selected */
                        CurrentLog->ulLogInterval = 0;
                    }
                } else {
                    /* We don't currently support COV */
                    status = false;
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code =
                        ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
                }
            }
            break;

        case PROP_START_TIME:
            /* Copy the date part to safe place */
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_DATE,
                &wp_data->error_class, &wp_data->error_code);
            if (!status) {
                break;
            }
            TempDate = value.type.Date;
            /* Then decode the time part */
            len =
                bacapp_decode_application_data(wp_data->application_data + len,
                wp_data->application_data_len - len, &value);

            if (len) {
                status =
                    WPValidateArgType(&value, BACNET_APPLICATION_TAG_TIME,
                    &wp_data->error_class, &wp_data->error_code);
                if (!status) {
                    break;
                }
                /* First record the current enable state of the log */
                bEffectiveEnable = TL_Is_Enabled(log_index);
                CurrentLog->StartTime.date = TempDate;  /* Safe to copy the date now */
                CurrentLog->StartTime.time = value.type.Time;

                if (datetime_wildcard_present(&CurrentLog->StartTime)) {
                    /* Mark start time as wild carded */
                    CurrentLog->ucTimeFlags |= TL_T_START_WILD;
                    CurrentLog->tStartTime = 0;
                } else {
                    /* Clear wild card flag and set time in local format */
                    CurrentLog->ucTimeFlags &= ~TL_T_START_WILD;
                    CurrentLog->tStartTime =
                        TL_BAC_Time_To_Local(&CurrentLog->StartTime);
                }

                if (bEffectiveEnable != TL_Is_Enabled(log_index)) {
                    /* Enable status has changed because of time update */
                    if (bEffectiveEnable == true) {
                        /* Say we went from enabled to disabled */
                        TL_Insert_Status_Rec(log_index,
                            LOG_STATUS_LOG_DISABLED, true);
                    } else {
                        /* Say we went from disabled to enabled */
                        TL_Insert_Status_Rec(log_index,
                            LOG_STATUS_LOG_DISABLED, false);
                    }
                }
            }
            break;

        case PROP_STOP_TIME:
            /* Copy the date part to safe place */
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_DATE,
                &wp_data->error_class, &wp_data->error_code);
            if (!status) {
                break;
            }
            TempDate = value.type.Date;
            /* Then decode the time part */
            len =
                bacapp_decode_application_data(wp_data->application_data + len,
                wp_data->application_data_len - len, &value);

            if (len) {
                status =
                    WPValidateArgType(&value, BACNET_APPLICATION_TAG_TIME,
                    &wp_data->error_class, &wp_data->error_code);
                if (!status) {
                    break;
                }
                /* First record the current enable state of the log */
                bEffectiveEnable = TL_Is_Enabled(log_index);
                CurrentLog->StopTime.date = TempDate;   /* Safe to copy the date now */
                CurrentLog->StopTime.time = value.type.Time;

                if (datetime_wildcard_present(&CurrentLog->StopTime)) {
                    /* Mark stop time as wild carded */
                    CurrentLog->ucTimeFlags |= TL_T_STOP_WILD;
                    CurrentLog->tStopTime = 0xFFFFFFFF; /* Fixme: how do we set this to max for time_t ? */
                } else {
                    /* Clear wild card flag and set time in local format */
                    CurrentLog->ucTimeFlags &= ~TL_T_STOP_WILD;
                    CurrentLog->tStopTime =
                        TL_BAC_Time_To_Local(&CurrentLog->StopTime);
                }

                if (bEffectiveEnable != TL_Is_Enabled(log_index)) {
                    /* Enable status has changed because of time update */
                    if (bEffectiveEnable == true) {
                        /* Say we went from enabled to disabled */
                        TL_Insert_Status_Rec(log_index,
                            LOG_STATUS_LOG_DISABLED, true);
                    } else {
                        /* Say we went from disabled to enabled */
                        TL_Insert_Status_Rec(log_index,
                            LOG_STATUS_LOG_DISABLED, false);
                    }
                }
            }
            break;

        case PROP_LOG_DEVICE_OBJECT_PROPERTY:
            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 */
            len =
                bacapp_decode_context_data(wp_data->application_data,
                wp_data->application_data_len, &value,
                PROP_LOG_DEVICE_OBJECT_PROPERTY);
            if ((len == 0) || (value.context_tag != 0) ||
                ((wp_data->application_data_len - len) == 0)) {
                /* Bad decode, wrong tag or following required parameter missing */
                wp_data->error_class = ERROR_CLASS_PROPERTY;
                wp_data->error_code = ERROR_CODE_OTHER;
                break;
            }

            TempSource.objectIdentifier = value.type.Object_Id;
            wp_data->application_data_len -= len;
            iOffset = len;
            /* Second up is the property id */
            len =
                bacapp_decode_context_data(&wp_data->application_data[iOffset],
                wp_data->application_data_len, &value,
                PROP_LOG_DEVICE_OBJECT_PROPERTY);
            if ((len == 0) || (value.context_tag != 1)) {
                /* Bad decode or wrong tag */
                wp_data->error_class = ERROR_CLASS_PROPERTY;
                wp_data->error_code = ERROR_CODE_OTHER;
                break;
            }

            TempSource.propertyIdentifier = value.type.Enumerated;
            wp_data->application_data_len -= len;

            /* If there is still more to come */
            if (wp_data->application_data_len != 0) {
                iOffset += len;
                len =
                    bacapp_decode_context_data(&wp_data->application_data
                    [iOffset], wp_data->application_data_len, &value,
                    PROP_LOG_DEVICE_OBJECT_PROPERTY);
                if ((len == 0) || ((value.context_tag != 2) &&
                        (value.context_tag != 3))) {
                    /* Bad decode or wrong tag */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code = ERROR_CODE_OTHER;
                    break;
                }

                if (value.context_tag == 2) {
                    /* Got an index so deal with it */
                    TempSource.arrayIndex = value.type.Unsigned_Int;
                    wp_data->application_data_len -= len;
                    /* Still some remaining so fetch potential device ID */
                    if (wp_data->application_data_len != 0) {
                        iOffset += len;
                        len =
                            bacapp_decode_context_data
                            (&wp_data->application_data[iOffset],
                            wp_data->application_data_len, &value,
                            PROP_LOG_DEVICE_OBJECT_PROPERTY);
                        if ((len == 0) || (value.context_tag != 3)) {
                            /* Bad decode or wrong tag */
                            wp_data->error_class = ERROR_CLASS_PROPERTY;
                            wp_data->error_code = ERROR_CODE_OTHER;
                            break;
                        }
                    }
                }

                if (value.context_tag == 3) {
                    /* Got a device ID so deal with it */
                    TempSource.deviceIndentifier = value.type.Object_Id;
                    if ((TempSource.deviceIndentifier.instance !=
                            Device_Object_Instance_Number()) ||
                        (TempSource.deviceIndentifier.type != OBJECT_DEVICE)) {
                        /* Not our ID so can't handle it at the moment */
                        wp_data->error_class = ERROR_CLASS_PROPERTY;
                        wp_data->error_code =
                            ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
                        break;
                    }
                }
            }
            /* Make sure device ID is set to ours in case not supplied */
            TempSource.deviceIndentifier.type = OBJECT_DEVICE;
            TempSource.deviceIndentifier.instance =
                Device_Object_Instance_Number();
            /* Quick comparison if structures are packed ... */
            if (memcmp(&TempSource, &CurrentLog->Source,
                    sizeof(BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE)) != 0) {
                /* Clear buffer if property being logged is changed */
                CurrentLog->ulRecordCount = 0;
                CurrentLog->iIndex = 0;
                TL_Insert_Status_Rec(log_index, LOG_STATUS_BUFFER_PURGED,
                    true);
            }
            CurrentLog->Source = TempSource;
            status = true;
            break;

        case PROP_LOG_INTERVAL:
            if (CurrentLog->LoggingType == LOGGING_TYPE_TRIGGERED) {
                /* Read only if triggered log so flag error and bail out */
                wp_data->error_class = ERROR_CLASS_PROPERTY;
                wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
                break;
            }
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
                &wp_data->error_class, &wp_data->error_code);
            if (status) {
                if ((CurrentLog->LoggingType == LOGGING_TYPE_POLLED) &&
                    (value.type.Unsigned_Int == 0)) {
                    /* We don't support COV at the moment so don't allow switching
                     * to it by clearing interval whilst in polling mode */
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code =
                        ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
                    status = false;
                } else {
                    /* We only log to 1 sec accuracy so must divide by 100 before passing it on */
                    CurrentLog->ulLogInterval = value.type.Unsigned_Int / 100;
                }
            }
            break;

        case PROP_ALIGN_INTERVALS:
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
                &wp_data->error_class, &wp_data->error_code);
            if (status) {
                CurrentLog->bAlignIntervals = value.type.Boolean;
            }
            break;

        case PROP_INTERVAL_OFFSET:
            /* We only log to 1 sec accuracy so must divide by 100 before passing it on */
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
                &wp_data->error_class, &wp_data->error_code);
            if (status) {
                CurrentLog->ulIntervalOffset = value.type.Unsigned_Int / 100;
            }
            break;

        case PROP_TRIGGER:
            status =
                WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
                &wp_data->error_class, &wp_data->error_code);
            if (status) {
                /* We will not allow triggered operation if polling with aligning
                 * 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)) {
                    wp_data->error_class = ERROR_CLASS_PROPERTY;
                    wp_data->error_code =
                        ERROR_CODE_NOT_CONFIGURED_FOR_TRIGGERED_LOGGING;
                    status = false;
                } else {
                    CurrentLog->bTrigger = value.type.Boolean;
                }
            }
            break;

        default:
            wp_data->error_class = ERROR_CLASS_PROPERTY;
            wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
            break;
    }

    return status;
}

bool TrendLogGetRRInfo(
    BACNET_READ_RANGE_DATA * pRequest,  /* Info on the request */
    RR_PROP_INFO * pInfo)
{       /* Where to put the information */
    int log_index;

    log_index = Trend_Log_Instance_To_Index(pRequest->object_instance);
    if (log_index >= MAX_TREND_LOGS) {
        pRequest->error_class = ERROR_CLASS_OBJECT;
        pRequest->error_code = ERROR_CODE_UNKNOWN_OBJECT;
    } else if (pRequest->object_property == PROP_LOG_BUFFER) {
        pInfo->RequestTypes = RR_BY_POSITION | RR_BY_TIME | RR_BY_SEQUENCE;
        pInfo->Handler = rr_trend_log_encode;
        return (true);
    } else {
        pRequest->error_class = ERROR_CLASS_SERVICES;
        pRequest->error_code = ERROR_CODE_PROPERTY_IS_NOT_A_LIST;
    }

    return (false);
}

/*****************************************************************************
 * Insert a status record into a trend log - does not check for enable/log   *
 * full, time slots and so on as these type of entries have to go in         *
 * irrespective of such things which means that valid readings may get       *
 * pushed out of the log to make room.                                       *
 *****************************************************************************/

void TL_Insert_Status_Rec(
    int iLog,
    BACNET_LOG_STATUS eStatus,
    bool bState)
{
    TL_LOG_INFO *CurrentLog;
    TL_DATA_REC TempRec;

    CurrentLog = &LogInfo[iLog];

    TempRec.tTimeStamp = time(NULL);
    TempRec.ucRecType = TL_TYPE_STATUS;
    TempRec.ucStatus = 0;
    TempRec.Datum.ucLogStatus = 0;
    /* Note we set the bits in correct order so that we can place them directly
     * into the bitstring structure later on when we have to encode them */
    switch (eStatus) {
        case LOG_STATUS_LOG_DISABLED:
            if (bState)
                TempRec.Datum.ucLogStatus = 1 << LOG_STATUS_LOG_DISABLED;
            break;
        case LOG_STATUS_BUFFER_PURGED:
            if (bState)
                TempRec.Datum.ucLogStatus = 1 << LOG_STATUS_BUFFER_PURGED;
            break;
        case LOG_STATUS_LOG_INTERRUPTED:
            TempRec.Datum.ucLogStatus = 1 << LOG_STATUS_LOG_INTERRUPTED;
            break;
        default:
            break;
    }

    Logs[iLog][CurrentLog->iIndex++] = TempRec;
    if (CurrentLog->iIndex >= TL_MAX_ENTRIES)
        CurrentLog->iIndex = 0;

    CurrentLog->ulTotalRecordCount++;

    if (CurrentLog->ulRecordCount < TL_MAX_ENTRIES)
        CurrentLog->ulRecordCount++;
}

/*****************************************************************************
 * Use the combination of the enable flag and the enable times to determine  *
 * if the log is really enabled now. See 135-2008 sections 12.25.5 - 12.25.7 *
 *****************************************************************************/

bool TL_Is_Enabled(
    int iLog)
{
    TL_LOG_INFO *CurrentLog;
    time_t tNow;
    bool bStatus;

    bStatus = true;
    CurrentLog = &LogInfo[iLog];
#if 0
    printf("\nFlags - %u, Start - %u, Stop - %u\n",
        (unsigned int) CurrentLog->ucTimeFlags,
        (unsigned int) CurrentLog->tStartTime,
        (unsigned int) CurrentLog->tStopTime);
#endif
    if (CurrentLog->bEnable == false) {
        /* Not enabled so time is irrelevant */
        bStatus = false;
    } else if ((CurrentLog->ucTimeFlags == 0) &&
        (CurrentLog->tStopTime < CurrentLog->tStartTime)) {
        /* Start time was after stop time as per 12.25.6 and 12.25.7 */
        bStatus = false;
    } else if (CurrentLog->ucTimeFlags != (TL_T_START_WILD | TL_T_STOP_WILD)) {
        /* enabled and either 1 wild card or none */
        tNow = time(NULL);
#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);
#endif
        if ((CurrentLog->ucTimeFlags & TL_T_START_WILD) != 0) {
            /* wild card start time */
            if (tNow > CurrentLog->tStopTime)
                bStatus = false;
        } else if ((CurrentLog->ucTimeFlags & TL_T_STOP_WILD) != 0) {
            /* wild card stop time */
            if (tNow < CurrentLog->tStartTime)
                bStatus = false;
        } else {
#if 0
            printf("\nCurrent - %u, Start - %u, Stop - %u\n",
                (unsigned int) Now, (unsigned int) CurrentLog->tStartTime,
                (unsigned int) CurrentLog->tStopTime);
#endif
            /* No wildcards so use both times */
            if ((tNow < CurrentLog->tStartTime) ||
                (tNow > CurrentLog->tStopTime))
                bStatus = false;
        }
    }

    return (bStatus);
}

/*****************************************************************************
 * Convert a BACnet time into a local time in seconds since the local epoch  *
 *****************************************************************************/

time_t TL_BAC_Time_To_Local(
    BACNET_DATE_TIME * SourceTime)
{
    struct tm LocalTime;
    int iTemp;

    LocalTime.tm_year = SourceTime->date.year - 1900;   /* We store BACnet year in full format */
    /* Some clients send a date of all 0s to indicate start of epoch
     * even though this is not a valid date. Pick this up here and
     * correct the day and month for the local time functions.
     */
    iTemp =
        SourceTime->date.year + SourceTime->date.month + SourceTime->date.day;
    if (iTemp == 1900) {
        LocalTime.tm_mon = 0;
        LocalTime.tm_mday = 1;
    } else {
        LocalTime.tm_mon = SourceTime->date.month - 1;
        LocalTime.tm_mday = SourceTime->date.day;
    }

    LocalTime.tm_hour = SourceTime->time.hour;
    LocalTime.tm_min = SourceTime->time.min;
    LocalTime.tm_sec = SourceTime->time.sec;

    return (mktime(&LocalTime));
}

/*****************************************************************************
 * Convert a local time in seconds since the local epoch into a BACnet time  *
 *****************************************************************************/

void TL_Local_Time_To_BAC(
    BACNET_DATE_TIME * DestTime,
    time_t SourceTime)
{
    struct tm *TempTime;

    TempTime = localtime(&SourceTime);

    DestTime->date.year = (uint16_t) (TempTime->tm_year + 1900);
    DestTime->date.month = (uint8_t) (TempTime->tm_mon + 1);
    DestTime->date.day = (uint8_t) TempTime->tm_mday;
    /* BACnet is 1 to 7 = Monday to Sunday
     * Windows is days from Sunday 0 - 6 so we
     * have to adjust */
    if (TempTime->tm_wday == 0)
        DestTime->date.wday = 7;
    else
        DestTime->date.wday = (uint8_t) TempTime->tm_wday;
    DestTime->time.hour = (uint8_t) TempTime->tm_hour;
    DestTime->time.min = (uint8_t) TempTime->tm_min;
    DestTime->time.sec = (uint8_t) TempTime->tm_sec;
    DestTime->time.hundredths = 0;
}

/****************************************************************************
 * Build a list of Trend Log entries from the Log Buffer property as        *
 * required for the ReadsRange functionality.                               *
 *                                                                          *
 * We have to support By Position, By Sequence and By Time requests.        *
 *                                                                          *
 * We do assume the list cannot change whilst we are accessing it so would  *
 * not be multithread safe if there are other tasks that write to the log.  *
 *                                                                          *
 * We take the simple approach here to filling the buffer by taking a max   *
 * size for a single entry and then stopping if there is less than that     *
 * left in the buffer. You could build each entry in a seperate buffer and  *
 * determine the exact length before copying but this is time consuming,    *
 * requires more memory and would probably only let you sqeeeze one more    *
 * entry in on occasion. The value is calculated as 10 bytes for the time   *
 * stamp + 6 bytes for our largest data item (bit string capped at 32 bits) *
 * + 3 bytes for the status flags + 4 for the context tags to give 23.      *
 ****************************************************************************/

#define TL_MAX_ENC 23   /* Maximum size of encoded log entry, see above */

int rr_trend_log_encode(
    uint8_t * apdu,
    BACNET_READ_RANGE_DATA * pRequest)
{
    /* Initialise result flags to all false */
    bitstring_init(&pRequest->ResultFlags);
    bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_FIRST_ITEM, false);
    bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_LAST_ITEM, false);
    bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS, false);
    pRequest->ItemCount = 0;    /* Start out with nothing */

    /* Bail out now if nowt - should never happen for a Trend Log but ... */
    if (LogInfo[Trend_Log_Instance_To_Index(pRequest->
                object_instance)].ulRecordCount == 0)
        return (0);

    if ((pRequest->RequestType == RR_BY_POSITION) ||
        (pRequest->RequestType == RR_READ_ALL))
        return (TL_encode_by_position(apdu, pRequest));
    else if (pRequest->RequestType == RR_BY_SEQUENCE)
        return (TL_encode_by_sequence(apdu, pRequest));

    return (TL_encode_by_time(apdu, pRequest));
}

/****************************************************************************
 * Handle encoding for the By Position and All options.                     *
 * Does All option by converting to a By Position request starting at index *
 * 1 and of maximum log size length.                                        *
 ****************************************************************************/

int TL_encode_by_position(
    uint8_t * apdu,
    BACNET_READ_RANGE_DATA * pRequest)
{
    int log_index = 0;
    int iLen = 0;
    int32_t iTemp = 0;
    TL_LOG_INFO *CurrentLog = NULL;

    uint32_t uiIndex = 0;       /* Current entry number */
    uint32_t uiFirst = 0;       /* Entry number we started encoding from */
    uint32_t uiLast = 0;        /* Entry number we finished encoding on */
    uint32_t uiTarget = 0;      /* Last entry we are required to encode */
    uint32_t uiRemaining = 0;   /* Amount of unused space in packet */

    /* See how much space we have */
    uiRemaining = MAX_APDU - pRequest->Overhead;
    log_index = Trend_Log_Instance_To_Index(pRequest->object_instance);
    CurrentLog = &LogInfo[log_index];
    if (pRequest->RequestType == RR_READ_ALL) {
        /*
         * Read all the list or as much as will fit in the buffer by selecting
         * a range that covers the whole list and falling through to the next
         * section of code
         */
        pRequest->Count = CurrentLog->ulRecordCount;    /* Full list */
        pRequest->Range.RefIndex = 1;   /* Starting at the beginning */
    }

    if (pRequest->Count < 0) {  /* negative count means work from index backwards */
        /*
         * Convert from end index/negative count to
         * start index/positive count and then process as
         * normal. This assumes that the order to return items
         * is always first to last, if this is not true we will
         * have to handle this differently.
         *
         * Note: We need to be careful about how we convert these
         * values due to the mix of signed and unsigned types - don't
         * try to optimise the code unless you understand all the
         * implications of the data type conversions!
         */

        iTemp = pRequest->Range.RefIndex;       /* pull out and convert to signed */
        iTemp += pRequest->Count + 1;   /* Adjust backwards, remember count is -ve */
        if (iTemp < 1) {        /* if count is too much, return from 1 to start index */
            pRequest->Count = pRequest->Range.RefIndex;
            pRequest->Range.RefIndex = 1;
        } else {        /* Otherwise adjust the start index and make count +ve */
            pRequest->Range.RefIndex = iTemp;
            pRequest->Count = -pRequest->Count;
        }
    }

    /* From here on in we only have a starting point and a positive count */

    if (pRequest->Range.RefIndex > CurrentLog->ulRecordCount)   /* Nothing to return as we are past the end of the list */
        return (0);

    uiTarget = pRequest->Range.RefIndex + pRequest->Count - 1;  /* Index of last required entry */
    if (uiTarget > CurrentLog->ulRecordCount)   /* Capped at end of list if necessary */
        uiTarget = CurrentLog->ulRecordCount;

    uiIndex = pRequest->Range.RefIndex;
    uiFirst = uiIndex;  /* Record where we started from */
    while (uiIndex <= uiTarget) {
        if (uiRemaining < TL_MAX_ENC) {
            /*
             * Can't fit any more in! We just set the result flag to say there
             * was more and drop out of the loop early
             */
            bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS,
                true);
            break;
        }

        iTemp = TL_encode_entry(&apdu[iLen], log_index, uiIndex);

        uiRemaining -= iTemp;   /* Reduce the remaining space */
        iLen += iTemp;  /* and increase the length consumed */
        uiLast = uiIndex;       /* Record the last entry encoded */
        uiIndex++;      /* and get ready for next one */
        pRequest->ItemCount++;  /* Chalk up another one for the response count */
    }

    /* Set remaining result flags if necessary */
    if (uiFirst == 1)
        bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_FIRST_ITEM,
            true);

    if (uiLast == CurrentLog->ulRecordCount)
        bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_LAST_ITEM, true);

    return (iLen);
}

/****************************************************************************
 * Handle encoding for the By Sequence option.                              *
 * The fact that the buffer always has at least a single entry is used      *
 * implicetly in the following as we don't have to handle the case of an    *
 * empty buffer.                                                            *
 ****************************************************************************/

int TL_encode_by_sequence(
    uint8_t * apdu,
    BACNET_READ_RANGE_DATA * pRequest)
{
    int log_index = 0;
    int iLen = 0;
    int32_t iTemp = 0;
    TL_LOG_INFO *CurrentLog = NULL;

    uint32_t uiIndex = 0;       /* Current entry number */
    uint32_t uiFirst = 0;       /* Entry number we started encoding from */
    uint32_t uiLast = 0;        /* Entry number we finished encoding on */
    uint32_t uiSequence = 0;    /* Tracking sequenc number when encoding */
    uint32_t uiRemaining = 0;   /* Amount of unused space in packet */
    uint32_t uiFirstSeq = 0;    /* Sequence number for 1st record in log */

    uint32_t uiBegin = 0;       /* Starting Sequence number for request */
    uint32_t uiEnd = 0; /* Ending Sequence number for request */
    bool bWrapReq = false;      /* Has request sequence range spanned the max for uint32_t? */
    bool bWrapLog = false;      /* Has log sequence range spanned the max for uint32_t? */

    /* See how much space we have */
    uiRemaining = MAX_APDU - pRequest->Overhead;
    log_index = Trend_Log_Instance_To_Index(pRequest->object_instance);
    CurrentLog = &LogInfo[log_index];
    /* Figure out the sequence number for the first record, last is ulTotalRecordCount */
    uiFirstSeq =
        CurrentLog->ulTotalRecordCount - (CurrentLog->ulRecordCount - 1);

    /* Calculate start and end sequence numbers from request */
    if (pRequest->Count < 0) {
        uiBegin = pRequest->Range.RefSeqNum + pRequest->Count + 1;
        uiEnd = pRequest->Range.RefSeqNum;
    } else {
        uiBegin = pRequest->Range.RefSeqNum;
        uiEnd = pRequest->Range.RefSeqNum + pRequest->Count - 1;
    }
    /* See if we have any wrap around situations */
    if (uiBegin > uiEnd)
        bWrapReq = true;
    if (uiFirstSeq > CurrentLog->ulTotalRecordCount)
        bWrapLog = true;

    if ((bWrapReq == false) && (bWrapLog == false)) {   /* Simple case no wraps */
        /* If no overlap between request range and buffer contents bail out */
        if ((uiEnd < uiFirstSeq) || (uiBegin > CurrentLog->ulTotalRecordCount))
            return (0);

        /* Truncate range if necessary so it is guaranteed to lie
         * between the first and last sequence numbers in the buffer
         * inclusive.
         */
        if (uiBegin < uiFirstSeq)
            uiBegin = uiFirstSeq;

        if (uiEnd > CurrentLog->ulTotalRecordCount)
            uiEnd = CurrentLog->ulTotalRecordCount;
    } else {    /* There are wrap arounds to contend with */
        /* First check for non overlap condition as it is common to all */
        if ((uiBegin > CurrentLog->ulTotalRecordCount) && (uiEnd < uiFirstSeq))
            return (0);

        if (bWrapLog == false) {        /* Only request range wraps */
            if (uiEnd < uiFirstSeq) {
                uiEnd = CurrentLog->ulTotalRecordCount;
                if (uiBegin < uiFirstSeq)
                    uiBegin = uiFirstSeq;
            } else {
                uiBegin = uiFirstSeq;
                if (uiEnd > CurrentLog->ulTotalRecordCount)
                    uiEnd = CurrentLog->ulTotalRecordCount;
            }
        } else if (bWrapReq == false) { /* Only log wraps */
            if (uiBegin > CurrentLog->ulTotalRecordCount) {
                if (uiBegin > uiFirstSeq)
                    uiBegin = uiFirstSeq;
            } else {
                if (uiEnd > CurrentLog->ulTotalRecordCount)
                    uiEnd = CurrentLog->ulTotalRecordCount;
            }
        } else {        /* Both wrap */
            if (uiBegin < uiFirstSeq)
                uiBegin = uiFirstSeq;

            if (uiEnd > CurrentLog->ulTotalRecordCount)
                uiEnd = CurrentLog->ulTotalRecordCount;
        }
    }

    /* We now have a range that lies completely within the log buffer
     * and we need to figure out where that starts in the buffer.
     */
    uiIndex = uiBegin - uiFirstSeq + 1;
    uiSequence = uiBegin;
    uiFirst = uiIndex;  /* Record where we started from */
    while (uiSequence != uiEnd + 1) {
        if (uiRemaining < TL_MAX_ENC) {
            /*
             * Can't fit any more in! We just set the result flag to say there
             * was more and drop out of the loop early
             */
            bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS,
                true);
            break;
        }

        iTemp = TL_encode_entry(&apdu[iLen], log_index, uiIndex);

        uiRemaining -= iTemp;   /* Reduce the remaining space */
        iLen += iTemp;  /* and increase the length consumed */
        uiLast = uiIndex;       /* Record the last entry encoded */
        uiIndex++;      /* and get ready for next one */
        uiSequence++;
        pRequest->ItemCount++;  /* Chalk up another one for the response count */
    }

    /* Set remaining result flags if necessary */
    if (uiFirst == 1)
        bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_FIRST_ITEM,
            true);

    if (uiLast == CurrentLog->ulRecordCount)
        bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_LAST_ITEM, true);

    pRequest->FirstSequence = uiBegin;

    return (iLen);
}

/****************************************************************************
 * Handle encoding for the By Time option.                                  *
 * The fact that the buffer always has at least a single entry is used      *
 * implicetly in the following as we don't have to handle the case of an    *
 * empty buffer.                                                            *
 ****************************************************************************/

int TL_encode_by_time(
    uint8_t * apdu,
    BACNET_READ_RANGE_DATA * pRequest)
{
    int log_index = 0;
    int iLen = 0;
    int32_t iTemp = 0;
    int iCount = 0;
    TL_LOG_INFO *CurrentLog = NULL;

    uint32_t uiIndex = 0;       /* Current entry number */
    uint32_t uiFirst = 0;       /* Entry number we started encoding from */
    uint32_t uiLast = 0;        /* Entry number we finished encoding on */
    uint32_t uiRemaining = 0;   /* Amount of unused space in packet */
    uint32_t uiFirstSeq = 0;    /* Sequence number for 1st record in log */
    time_t tRefTime = 0;        /* The time from the request in local format */

    /* See how much space we have */
    uiRemaining = MAX_APDU - pRequest->Overhead;
    log_index = Trend_Log_Instance_To_Index(pRequest->object_instance);
    CurrentLog = &LogInfo[log_index];

    tRefTime = TL_BAC_Time_To_Local(&pRequest->Range.RefTime);
    /* Find correct position for oldest entry in log */
    if (CurrentLog->ulRecordCount < TL_MAX_ENTRIES)
        uiIndex = 0;
    else
        uiIndex = CurrentLog->iIndex;

    if (pRequest->Count < 0) {
        /* Start at end of log and look for record which has
         * timestamp greater than or equal to the reference.
         */
        iCount = CurrentLog->ulRecordCount - 1;
        /* Start out with the sequence number for the last record */
        uiFirstSeq = CurrentLog->ulTotalRecordCount;
        for (;;) {
            if (Logs[pRequest->object_instance][(uiIndex +
                        iCount) % TL_MAX_ENTRIES].tTimeStamp < tRefTime)
                break;

            uiFirstSeq--;
            iCount--;
            if (iCount < 0)
                return (0);
        }

        /* We have an and point for our request,
         * now work backwards to find where we should start from
         */

        pRequest->Count = -pRequest->Count;     /* Conveert to +ve count */
        /* If count would bring us back beyond the limits
         * Of the buffer then pin it to the start of the buffer
         * otherwise adjust starting point and sequence number
         * appropriately.
         */
        iTemp = pRequest->Count - 1;
        if (iTemp > iCount) {
            uiFirstSeq -= iCount;
            pRequest->Count = iCount + 1;
            iCount = 0;
        } else {
            uiFirstSeq -= iTemp;
            iCount -= iTemp;
        }
    } else {
        /* Start at beginning of log and look for 1st record which has
         * timestamp greater than the reference time.
         */
        iCount = 0;
        /* Figure out the sequence number for the first record, last is ulTotalRecordCount */
        uiFirstSeq =
            CurrentLog->ulTotalRecordCount - (CurrentLog->ulRecordCount - 1);
        for (;;) {
            if (Logs[pRequest->object_instance][(uiIndex +
                        iCount) % TL_MAX_ENTRIES].tTimeStamp > tRefTime)
                break;

            uiFirstSeq++;
            iCount++;
            if ((uint32_t) iCount == CurrentLog->ulRecordCount)
                return (0);
        }
    }

    /* We now have a starting point for the operation and a +ve count */

    uiIndex = iCount + 1;       /* Convert to BACnet 1 based reference */
    uiFirst = uiIndex;  /* Record where we started from */
    iCount = pRequest->Count;
    while (iCount != 0) {
        if (uiRemaining < TL_MAX_ENC) {
            /*
             * Can't fit any more in! We just set the result flag to say there
             * was more and drop out of the loop early
             */
            bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_MORE_ITEMS,
                true);
            break;
        }

        iTemp = TL_encode_entry(&apdu[iLen], log_index, uiIndex);

        uiRemaining -= iTemp;   /* Reduce the remaining space */
        iLen += iTemp;  /* and increase the length consumed */
        uiLast = uiIndex;       /* Record the last entry encoded */
        uiIndex++;      /* and get ready for next one */
        pRequest->ItemCount++;  /* Chalk up another one for the response count */
        iCount--;       /* And finally cross another one off the requested count */

        if (uiIndex > CurrentLog->ulRecordCount)        /* Finish up if we hit the end of the log */
            break;
    }

    /* Set remaining result flags if necessary */
    if (uiFirst == 1)
        bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_FIRST_ITEM,
            true);

    if (uiLast == CurrentLog->ulRecordCount)
        bitstring_set_bit(&pRequest->ResultFlags, RESULT_FLAG_LAST_ITEM, true);

    pRequest->FirstSequence = uiFirstSeq;

    return (iLen);
}

int TL_encode_entry(
    uint8_t * apdu,
    int iLog,
    int iEntry)
{
    int iLen = 0;
    TL_DATA_REC *pSource = NULL;
    BACNET_BIT_STRING TempBits;
    uint8_t ucCount = 0;
    BACNET_DATE_TIME TempTime;

    /* Convert from BACnet 1 based to 0 based array index and then
     * handle wrap around of the circular buffer */

    if (LogInfo[iLog].ulRecordCount < TL_MAX_ENTRIES)
        pSource = &Logs[iLog][(iEntry - 1) % TL_MAX_ENTRIES];
    else
        pSource =
            &Logs[iLog][(LogInfo[iLog].iIndex + iEntry - 1) % TL_MAX_ENTRIES];

    iLen = 0;
    /* First stick the time stamp in with tag [0] */
    TL_Local_Time_To_BAC(&TempTime, pSource->tTimeStamp);
    iLen += bacapp_encode_context_datetime(apdu, 0, &TempTime);

    /* Next comes the actual entry with tag [1] */
    iLen += encode_opening_tag(&apdu[iLen], 1);
    /* The data entry is tagged individually [0] - [10] to indicate which type */
    switch (pSource->ucRecType) {
        case TL_TYPE_STATUS:
            /* Build bit string directly from the stored octet */
            bitstring_init(&TempBits);
            bitstring_set_bits_used(&TempBits, 1, 5);
            bitstring_set_octet(&TempBits, 0, pSource->Datum.ucLogStatus);
            iLen +=
                encode_context_bitstring(&apdu[iLen], pSource->ucRecType,
                &TempBits);
            break;

        case TL_TYPE_BOOL:
            iLen +=
                encode_context_boolean(&apdu[iLen], pSource->ucRecType,
                pSource->Datum.ucBoolean);
            break;

        case TL_TYPE_REAL:
            iLen +=
                encode_context_real(&apdu[iLen], pSource->ucRecType,
                pSource->Datum.fReal);
            break;

        case TL_TYPE_ENUM:
            iLen +=
                encode_context_enumerated(&apdu[iLen], pSource->ucRecType,
                pSource->Datum.ulEnum);
            break;

        case TL_TYPE_UNSIGN:
            iLen +=
                encode_context_unsigned(&apdu[iLen], pSource->ucRecType,
                pSource->Datum.ulUValue);
            break;

        case TL_TYPE_SIGN:
            iLen +=
                encode_context_signed(&apdu[iLen], pSource->ucRecType,
                pSource->Datum.lSValue);
            break;

        case TL_TYPE_BITS:
            /* Rebuild bitstring directly from stored octets - which we
             * have limited to 32 bits maximum as allowed by the standard
             */
            bitstring_init(&TempBits);
            bitstring_set_bits_used(&TempBits,
                (pSource->Datum.Bits.ucLen >> 4) & 0x0F,
                pSource->Datum.Bits.ucLen & 0x0F);
            for (ucCount = pSource->Datum.Bits.ucLen >> 4; ucCount > 0;
                ucCount--)
                bitstring_set_octet(&TempBits, ucCount - 1,
                    pSource->Datum.Bits.ucStore[ucCount - 1]);

            iLen +=
                encode_context_bitstring(&apdu[iLen], pSource->ucRecType,
                &TempBits);
            break;

        case TL_TYPE_NULL:
            iLen += encode_context_null(&apdu[iLen], pSource->ucRecType);
            break;

        case TL_TYPE_ERROR:
            iLen += encode_opening_tag(&apdu[iLen], TL_TYPE_ERROR);
            iLen +=
                encode_application_enumerated(&apdu[iLen],
                pSource->Datum.Error.usClass);
            iLen +=
                encode_application_enumerated(&apdu[iLen],
                pSource->Datum.Error.usCode);
            iLen += encode_closing_tag(&apdu[iLen], TL_TYPE_ERROR);
            break;

        case TL_TYPE_DELTA:
            iLen +=
                encode_context_real(&apdu[iLen], pSource->ucRecType,
                pSource->Datum.fTime);
            break;

        case TL_TYPE_ANY:
            /* Should never happen as we don't support this at the moment */
            break;
    }

    iLen += encode_closing_tag(&apdu[iLen], 1);
    /* Check if status bit string is required and insert with tag [2] */
    if ((pSource->ucStatus & 128) == 128) {
        bitstring_init(&TempBits);
        bitstring_set_bits_used(&TempBits, 1, 4);
        /* only insert the 1st 4 bits */
        bitstring_set_octet(&TempBits, 0, (pSource->ucStatus & 0x0F));
        iLen += encode_context_bitstring(&apdu[iLen], 2, &TempBits);
    }

    return (iLen);
}

static 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;
    BACNET_READ_PROPERTY_DATA rpdata;

    if (value != NULL) {
        /* configure our storage */
        rpdata.application_data = value;
        rpdata.application_data_len = MAX_APDU;
        rpdata.object_type = Source->objectIdentifier.type;
        rpdata.object_instance = Source->objectIdentifier.instance;
        rpdata.object_property = Source->propertyIdentifier;
        rpdata.array_index = Source->arrayIndex;
        /* Try to fetch the required property */
        len = Device_Read_Property(&rpdata);
        if (len < 0) {
            *error_class = rpdata.error_class;
            *error_code = rpdata.error_code;
        }
    }

    if ((len >= 0) && (status != NULL)) {
        /* Fetch the status flags if required */
        rpdata.application_data = status;
        rpdata.application_data_len = MAX_APDU;
        rpdata.object_property = PROP_STATUS_FLAGS;
        rpdata.array_index = BACNET_ARRAY_ALL;
        len = Device_Read_Property(&rpdata);
        if (len < 0) {
            *error_class = rpdata.error_class;
            *error_code = rpdata.error_code;
        }
    }

    return (len);
}

/****************************************************************************
 * 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;
    uint8_t ucCount;
    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 (ucCount = 0;
                        ucCount < bitstring_bytes_used(&TempBits); ucCount++)
                        TempRec.Datum.Bits.ucStore[ucCount] =
                            bitstring_octet(&TempBits, ucCount);
                } else {
                    /* We will only use the first 4 octets to save space */
                    TempRec.Datum.Bits.ucLen = 4 << 4;
                    for (ucCount = 0; ucCount < 4; ucCount++)
                        TempRec.Datum.Bits.ucStore[ucCount] =
                            bitstring_octet(&TempBits, ucCount);
                }
                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(&StatusBuf[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 = NULL;
    int iCount = 0;
    time_t tNow = 0;

    /* unused parameter */
    uSeconds = uSeconds;
    /* use OS to get the current time */
    tNow = time(NULL);
    for (iCount = 0; iCount < MAX_TREND_LOGS; iCount++) {
        CurrentLog = &LogInfo[iCount];
        if (TL_Is_Enabled(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;
                }
            }
        }
    }
}

redpajama_set_name: RedPajamaGithub


STAR WARS 1978 A NEW HOPE CHEWBACCA FIGURE ACTION FIGURE -- 12 BACK-A NO OFFER ORIGINAL CARDED FIGURE -- WITH SKU ON THE FOOTER CARDBOARD -- HAS BEEN GRADED BY AFA AND RECIEVED A GRADE OF AFA 80, SUB GRADES OF C80, F85, B85 -- HARD TO FIND AND AWESOME EXAMPLE OF THE FIGURE. PLEASE REFER TO PICTURES AS TO WHAT YOU WILL BE PURCHASING. THIS FIGURE IS SEALED ON THE CARD BACK AND HAS NOT BEEN REMOVED AT ALL. BUBBLE IS ORIGINALLY SEALED AND NOTHING HAS BEEN TAINTED TO THE SEAL OR ITEM.
- NO RE-CARDED JUNK HERE. COOL FIGURE TO ADD TO YOUR COLLECTION.
PRICES OF VINTAGE ACTION FIGURES HAVE BEEN ON THE RISE --- STILL IN PROTECTIVE BAGGIE FROM AFA SO THE CASE HAS REMAINED UNSCRATCHED. Figure was made by Kenner toys and is officially licensed by Lucasfilm Ltd.
All figures range from mint to excellent condition! What you see in the scan is what you get. If you are interested in more Star Wars OR G. Joe Collectibles please take a look at my other auctions. SORRY FOR THE RATE INCREASES, IT IS DUE TO THE US POSTAL SERVICE.
The item "KENNER VINTAGE MOC 1978 STAR WARS NEW HOPE 12-BACK A CHEWBACCA SKU FOOTER AFA 80" is in sale since Sunday, August 20, 2017. This item is in the category "Toys & Hobbies\Action Figures\TV, Movie & Video Games".
The seller is "jharley7" and is located in Solana Beach, California. This item can be shipped worldwide.


The striking Q7 OB is great in size and elegance. This floor plan was designed to hold friends and family by maximizing interior space with a side-mount table, recessed storage, in-floor storage, and storage below seats. Inside the captain's helm console is like a closet. It has room dedicated for a cooler, shelves for gear, cockpit table storage, and a removable trash container. The main seating area features a standard refreshment center with a solid surface counter-top, a built-in blender for smoothies, and can be equipped to offer Shore Power with a refrigerator/freezer.
Captains will love being at the helm. The throttle arm rest, cell phone holder, Simrad® touch screen controls, and captain-only recessed storage will make the driver feel at home and in control of this yacht certified vessel. With up to 350 horsepower, you will be hooked after driving the Q7 OB. Sporty handling combined with safety and class makes this the quintessential family bow rider.


text:
Cheshunt hotels
About Cheshunt
Cheap Hotels in Cheshunt
YHA London Lee Valley Hotel
This YHA Hostel is located in the 10,000-acre Lee Valley Park, 3 miles from Waltham Abbey. Next door to an activity centre, it offers accommodation in lakeside cabins. In this beautiful countryside location, guests can try sailing, kayaking or canoeing on the lake. Caving and rock climbing are also available and there are fantastic walking and cycling routes surrounding this YHA hostel. Guests can relax at the bar or in the comfortable TV lounge. Wi-Fi access is available in public areas. The majority of rooms contain bunk beds London's Liverpool Street can be reached in just 25 minutes from Cheshunt Railway Station, which is just a 5-minute walk away. Junction 5 of the M25 is 5 minutes' drive away.
Cheshunt Marriott Hotel
Halfhide Lane, Turnford
Near Lee Valley Park
YHA London Lee Valley - Hostel Hotel
Windmill Lane, Cheshunt
Near Lee Valley White Water Centre
Hotels in Cheshunt
A few miles from central London, yet surrounded by green spaces, Cheshunt is close to both the excitement of the capital as well as enjoying the peacefulness of the countryside.
The town sits on the edge of the Lee Valley Country Park, a 10, 000-acre green space spilling into three counties. Book one of our Cheshunt hotels and admire everything from heritage sites to herons.
Lee Valley Park
Whether you're into extreme sports or exploring history, there are endless things to do in the Lee Valley Park, from horse riding and walking to fishing or ice-skating. Go canoeing, kayaking or white water rafting at the White Water Centre, or cycling at the Lee Valley Velopark, part of the Queen Elizabeth Olympic Park. Myddelton House Gardens and Waltham Abbey Gardens are both definitely worth exploring. At the latter you'll find the Lee Valley Park Farms, home to rare breeds of pig, llamas, meerkats and more.
More than 200 species of bird have been recorded in the park, as well as 35 species of mammal and more than 500 types of plant. Look out for bitterns, otters, water voles, red kites, muntjac deer, green woodpeckers, foxes, goosanders, goldcrests, emperor dragonflies, lesser-spotted woodpeckers, nightingales, grass snakes, kestrels, herons and a variety of butterflies.
You'll find ancient monuments, thousands of trees, formal gardens, a kids maze, a pet corner, a café and ponds in Cedars Park on the edge of the town. The park was once the site of Theobalds Palace, a Tudor palace which was one of James I's residences, and has been awarded a Green Flag every year since 2009.
A short drive out of the town is Cheshunt Park, which has wildflower meadows, woodland, a play area, basketball and football courts, an orchard and a pond. It's also a great place to look out for wildlife and birds - the Second World War pillbox here has been made into a home for hibernating bats. Next to the park is a golf centre with an 18-hole course, putting green and driving range where you can take lessons from a pro. On the other side is the Brookfield Shopping Park for those seeking a bit of retail therapy.
You can go swimming, play football, squash, badminton or table tennis or work out at the gym in the Laura Trott Leisure Centre in the middle of town. There's also a kids' gym and a learner pool for the little ones, plus a beauty salon, a sauna and steam room and exercise studios.
Admire the old brickwork and wooden beams over a meal or drink at the Coach and Horses, a former coaching inn also thought to have been used as a court. The menu includes thin crust pizzas, steaks, tapas and much more, and there's a cocktail menu too. A short drive out of town, in Goff's Oak, is the Chelsea Garden Café, whose landscaped garden won a silver medal at the Chelsea Flower Show. Lavas serves Mediterranean dishes to eat in or take away – you'll find French, Spanish, Italian, Turkish and Greek specialities on the menu. Or, head to De Ja Vu, Cheshunt Tandoori or Mahek for an Indian meal.
Frequently asked questions about Hotels in Cheshunt
What are the best hotels to stay in Cheshunt?
The best hotels to stay in Cheshunt are YHA London Lee Valley and Cheshunt Marriott Hotel.
What are the most convenient hotel rates in Cheshunt?
YHA London Lee Valley in Cheshunt offers one night in a double room at the price of £29.
What hotels are in the central Cheshunt neighborhood?
YHA London Lee Valley and Cheshunt Marriott Hotel are located in the central neighborhood of Cheshunt.
Cheshunt map
Weather in Cheshunt
Points of Interest in Hertfordshire
Stratford Station
Hotels in Broxbourne
Hotels in Chingford
Hotels in Cockfosters
Hotels in Buckhurst Hill
Hotels in Chigwell
Cities Around Hertfordshire
Hotels in St Albans
Hotels in Stevenage
Hotels in Abbots Langley
Hotels in Aldbury
Hotels in Chester Le Street

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: Get value from input within slot Vue Js I've tried to get data from my child component Dropdown.vue which inside this component contain slot for input value searching
.ui-dropdown__nav(ref="dropdown" :style="styles")
  .ui-dropdown__search-box(v-if="$slots['search-box']")
    slot(name="search-box")
  ul.ui-dropdown__menu
    li.ui-dropdown__item(
      v-for="(item, index) in options"
      :key="index"
      :class="{ 'ui-dropdown__item--current': label === item }"
    )
      button.ui-dropdown__choose(@click.prevent="$emit('change', item, index)")
        | {{ item }}

and this is my parent component
 ui-dropdown(
   :options="infoOptions"
   :label="selectedInfo ? selectedInfo : 'Select'"
   @change="selectInfo"
 )
   ui-input(
     small
     slot="search-box"
   )

how can I get value from input to pass for a child component. Thanks

redpajama_set_name: RedPajamaStackExchange


text:
Dactylospora är ett släkte av lavar. Dactylospora ingår i familjen Dactylosporaceae, ordningen Lecanorales, klassen Lecanoromycetes, divisionen sporsäcksvampar och riket svampar.

Källor

Sporsäcksvampar
Dactylospora

redpajama_set_name: RedPajamaWikipedia


Three bedroom semi-detached property situated in the heart of Braunstone Town, property comprises of: Hallway, one reception room, kitchen, utility room, three bedrooms and family bathroom. Driveway and a good size garden to the rear with shrubs and borders. Gas central heating throughout.
In need of general modernisation and updating.
Braunstone Town, well known for its popularity in terms of convenience for ease of access to the Leicester City centre with all it's excellent amenities therein as well as to the M1/M69 motorway network for travel North, South and West, adjoining Fosse Park shopping centre and Meridian Business and Entertainment Parks. Within the immediate vicinity are a fine range of local amenities to include a wide range of quality bars, and restaurants, shopping for day to day needs, schooling only walking distance away and regular bus services to the aforementioned centre of employment.


This is a placeholder page for Amanda Kimball, which means this person is not currently on this site. We do suggest using the tools below to find Amanda Kimball.
You are visiting the placeholder page for Amanda Kimball. This page is here because someone used our placeholder utility to look for Amanda Kimball. We created this page automatically in hopes Amanda Kimball would find it. If you are not Amanda Kimball, but are an alumni of Baraboo High School, register on this site for free now.


Aug 05, 20150183;32;China Iron Ore Circular Vibrating Screen Machine Equipment For Separate Stone With Eccentric Shaft . Order). Jiaozuo City Xinhai Mine Machinery Equipment Plant. Crushing Vibrating Screen. vibratory screens for iron ore mining offers 2640 crushing vibrating screen products. About 28% of these are vibrating screen, 1% are steel wire mesh.
Jul 21, 20180183;32;Vibrating screener All industrial manufacturers Videos. The new UltraFine high frequency vibrating wet screen is designed for separation from 0.075 to 1 mm, and is an ideal alternative to hydrocyclones by.
Professional Copper Ore Vibratory Screener With Ring Grooved Lock Bolt Brief Introduction Vibrating Screening Machine is suitable to screen all kinds of granular materials.
Animal feed (pellets and crumbles), dried sand, fertilizer, iron ore, wood pellets, quick and burnt lime, limestone, grain, gypsum, salt, and sugar are just a few of the materials and applications in which the MD Vibratory Screen is capable of screening efficiently and effectively.
vibratory screener Solutions In Motion. Apr 9, 2018 (or less) but still needs a vibratory screener. . This decking is also utilized in screeners for the iron ore, potash and phosphate industries.
Vibrating Screen For Iron Ore Iron Ore . vibratory ore screener machine . Mining ore circular vibrating screen machine,US $ 0 99,999 / Set, New, Circular. design of vibratory screens for iron ores Deze pagina vertalen.
ore dressing vibratory screener fertilizer offers 54 malaysia manganese ore products. About 31% of these are vibrating screen, 27% are mineral separator, and 20% are manganese ore. A wide variety of betel nut, organic fertilizer (bat guano), coal, iron ore, manganese high recovery Jigger machine for tin ore dressing in Malaysia Sn mine.
Add to Favorites. Iron ore linear vibrating sieve screen machine,sand small vibrating screener . Add to Favorites. quarry sand screener, vibration screen for silica sand price. Get Price Vibrating Screen, Vibrating Screen Suppliers and Manufacturers at . Ore Application Drum Vibrating Screen Round Sifter. Add to Compare .
Its also used by the oil and gas industries as a proppant to keep a hydraulic fracture from closing. A fine form of silica sand is also used as a filler for rubber, paints and plastics. When mining silica sand, the sand is put through an industrial screener that screens at a specific diameter.


text:
Horseman's News
Clinton Anderson Tips
Real Estate Section
Intensely Competitive Season Finalé Set Amidst Live Music & Fun Festivities For All.
October 14, 2019 Site Administrator Latest News Leave a comment
As the Oct. 15 entry closing date nears for the Galway Downs International Horse Trials, plans are ramping up to make it a season finalé to remember for contenders and fans alike.
Important qualifying scores are on the line in the CCI-L 4/3/2* divisions, with equally intense national level competition through Beginner Novice. The agenda includes the popular Training Three Day division, which preserves eventing's origins by staging all of the discipline's original endurance day phases: roads and track, steeplechase, more roads and track, and cross-country.
"Everyone who has the opportunity to do a Training Three Day should do it," urges Bec Braitling, a professional who won the division last year aboard Dassett Ricochet. It was an important stepping stone for that now 7-year-old horse. He went on to a winning year, including victory in the Woodside CCI2*-S earlier this month. Braitling promotes the division for riders, too. "I encourage all my riders to do it because there's so much to think about: there's a lot involved."
The competition takes place Oct. 31-Nov. 3 at the continually updated and improved Galway Downs Equestrian Center. The tournament action is woven throughout the 242-acre property's special event spaces. Shady trees, eco-friendly water features and lush grass expanses are appealing aesthetics that reflect function-oriented facility-wide upgrades that matter most to equestrians. The combined result is an equestrian sport stage that's drawing a rapidly growing base of exhibitors and fans. Its location in the heart of Southern California's Temecula Valley Wine Country enhances its destination event appeal.
Intense Fun for All
The intensity of the competition is matched only by the intensity of the fun. Two new tented "Oasis" areas on the cross-country course – near the tower and the water complex — will have snacks, soft drinks, local beers and Galway Spirits cocktails. Plus live music as the soundtrack to horse and riders galloping over ditches, banks and ponds. The international divisions run the course, created by Canadian international designer Jay Hambly, on Saturday, and the national Horse Trials divisions unfurl on Sunday. All divisions will conclude with an awards presentation in the Grand Prix Arena. Cash and other prizes presented then are courtesy of generous event sponsors: Devoucoux, Auburn Labs and Parker Equine Insurance.
The on-course Oasis hotspots are in addition to Wednesday's night welcome party and Saturday night's shindig in the Grand Prix Arena VIP tent, with good food, adult beverages, dancing and more live music. Throughout the weekend, live streamed cross-country action will display on big screens in the on-course and arena-adjacent VIP areas.
Organizer Robert Kellerhouse is thrilled to merge top notch equestrian competition with top local musical performances. The weekend's line-up includes the Americana music of Lee Koch and the Tim Walsh Band, plus Tony Suraci performing as the Highwayman with spot-on covers of hits by that group's members: Willie Nelson, Johnny Cash, Waylon Jennings and Kris Kristofferson. A Saturday afternoon concert on the Sycamore Tree Field anchors the weekend's musical festivities.
A ticket to the Wednesday and Saturday parties comes with each Galway Downs entry, and additional tickets, including VIP weekend packages, are available for friends, family and fans to join in on the fun. Ten-dollar parking includes free admission, plus the event program and access to arena side bleachers and the Oasis entertainment.
A bustling vendor area and food trucks with delicious offerings enhance the weekend's excitement.
Non-Stop Improvements
Temecula businessman Ken Smith has owned the beautiful 242-acre Galway Downs property for nine years now. He notes that it's undergone more improvements in the last 18 months than it has throughout the whole of his ownership.
Competitors are itching to get their steeds into brand new FEI-Stabling brought by Australian Olympic eventer Clayton Fredericks. Making its debut on the West Coast at the Galway Downs International, the Clearspan® covered stables have generously-sized, single row stalls separated by a 13' aisle. Air circulates freely and horses can see each other but not be in contact, for safe socialization. Plusses include a 50-amp power supply for each 20 stalls, LED lighting and HDPE walls that clean easily for biosecurity and are kick and chew resistant.
Footing improvements are an ongoing highlight, in part made possible by the venue's new role hosting international dressage with the West Coast Dressage Festival competition and the first-class hunter/jumper series from Nilforushan Equestrian Events.
Stadium jumping takes place in arenas footed with fresh geo-textile and sand footing. And cross-country is tended year-round by resident course builder and designer Bert Wood, with the help during the International of Canada's Jay Hambly.
Eventers count on Galway Downs to lead the way in cross-country creativity, challenge and safety, notes Hambly. The international course designer is fresh from serving on the design team for the 2020 Tokyo Olympics test event and looks forward to working with his longtime Galway partner, Bert Wood.
"There's lots to play with," Hambly notes of what's in store for contenders. "Bert has built a multitude of water obstacles, and lots of mounds and bumps, and there are trees everywhere! Galway has always set the standard on the West Coast."
Galway Downs' final international event of 2019 will conclude on a romantic note. When international contenders Helen Bouscaren and James Alliston finish competing on Sunday, they'll transform into bride and groom and head out to a pre-determined spot on cross-county to capture the sunset and their sentiments in front of friends from the eventing circuit.
Enter: www.evententries.com, or USEA's X-Entry at https://services.useventing.com/Services/Login.aspx
Tickets: https://www.events.org/cpage.aspx?e=122357
Ticket availability ranges from free daily general admission with $10 parking, to VIP Patrons Passes, which include reserved ringside tented seating, breakfast, lunch and beverages Thursday through Sunday.
Volunteer: www.eventingvolunteers.com.
More information: www.galwaydowns.net.
Previous Post:October Stakes Races to Watch
Next Post:Teresa Dietrich
Horseman's News • P.O. Box 893640 • Temecula, CA 92589
(800) 817-7259 • (951) 303-3900 • Fax (951) 303-3905


9/06/2018�� Thousands of years later, Ra-den was found chained beneath the Throne of Thunder by adventurers. Broken by millenia of imprisonment and torture, Ra came to the conclusion that Azeroth was twisted, beyond redemption, and that the only answer to corruption was destruction.... World of Warcraft Patch 5.2 brought with it the release of the Throne of Thunder raid which is the third tier of raiding in Mists of Pandaria.
Reseting phase dont work. When we need to reset Vita phase, we need to go in Anima phase, to pull boss a little to Anima orb and let the orb touch boss first and we will get Unleashed Anima debuff, after that move fast boss to Vita orb and orb need to reset Unleashed Anima debuff but that thing dont work, Unleashed Anima dont reset.
If you are not yet item lvl 480, there is lots of work to do, since to get into the LFR for the new starter Throne of Thunder content an item level of at least 480 is required. Preparing for Patch 5.2, and Throne of Thunder from now is the fastest way to the new tier 15 gear and mounts.


Nhà cung cấp: Amazon.com - giá Amazon: 60.99$ - shipping rates and return policy. GEM Products - giá Amazon: 91.18$ - ships from nj, united states. Watch Time LLC - giá Amazon: 95$ - ships from nj, united states. My Gift Stop - giá Amazon: 95.97$ - ships from ct, united states. All Glitters!!! - giá Amazon: 99.66$ - shipping rates and return policy. VirVentures - giá Amazon: 102.91$ - ships from tx, united states. Watchsavings - giá Amazon: 98.99$ - ships from ny, united states. RDBrands - giá Amazon: 113.75$ - ships from nj, united states. YourShopNow - giá Amazon: 182$ - ships from fl, united states.


It looks less like "Ta-da! Magic!" and more like "Ta-da! Medallions!" which is basically just being more specific but hey! Medallions!
Good to know my bugbear medallion can take care of my beloved boots!
So if clothing and accessories are physically made for midforms and are changed for a human by the medallion, what if the clothing is removed from the human form, and is out of the range of the medallion? Will it revert back to midform mode?
Yes. It works the same way with medallions and mythics. It can go maybe a few inches away from the medallion, but once out of range of the 'magic field' it will revert to its original form.
Have fun at AC! It's huuuuuuuuge!
Sounds like the medallions create a kind of template for the original nonhominid body to shape itself into when taking on a human appearance and a separate one for returning to original/modifying clothing; my brain keeps trying to flowchart the whole thing. I'm assuming that clothes sewn for nonhominid bodies would modify to human-wearables when a medallion gets used as well as vice-versa, right?
As far as clothes made for midforms work, that's exactly what Lorne says in this RQ.
Are there any Encantado in Skin Deep? Creatures from around the Amazon River.
It's the same basic mechanism a normally-operating TARDIS uses to select a form when it lands, automatically blending in with even a complex environment without actually bashing into anything.
It's possible a sphinx wrote the software.
I assume in full form, nobody needs glasses?
Didn't Merial have to start wearing glasses because her eyes as a Nixie are adjusted to seeing underwater?
On page 12 of Orientations chapter 2, her Turning is seen. She was at a pier beach, and not wearing glasses.


text:
About Public Affairs Committee
About Public Affairs Committee TOP
List of Member Companies
About Sumitomo
About Sumitomo TOP
Sumitomo in History
Sumitomo's starting point
Related Facilities
Sumitomo Quotes with Enduring Value
Current Major Activities
Current Major Activities TOP
Sumitomo's SUMITOMO QUARTERLY
Feature: Sumitomo Group's Initiatives
From the Sumitomo/Society Interface
Manga Reportage "Visits to Sumitomo Group"
Bedrock of Integrity
"A Brief Message from the
Heart" Letter Contest award
ceremoney
Intercollegiate NegotiationCompetition
Speech Contest of the Schools for
the Blind
Sumitomo Cultural Forum
Speech Contest of the Schools for the Blind
Special support for the Speech Contest of the Schools for the Blind
Sumitomo Group Public Affairs Committee supported The 75th Speech Contest of School for the Blind (hosted by Mainichi Newspaper Co., Ltd. Tenji Mainichi) which was held on Oct. 20th , 2006 at "Hotel Awina Osaka" in Tennoji, Osaka. This speech contest has marked its 75th anniversary observing the tradition since its establishment in 1928. The 9 representatives of blind students between 15-73 years old, who had won the elimination contest, made a speech passionately about future dream, purpose of life and ordinary feeling with their own words, aiming for championship flag of Minister of Education and Science and Tenji Mainichi Cup.
The sharpened sense of blind students brought us what we had never noticed.
We received impression and power from their words sending the message of "Power to live." The gist of this contest "Sending the message of our mind with our own words" is leading to our group message of Sumitomo Group Public Affairs Committee "Passing important values from people to people."
The 1st-prize winner was Tokuko Takemoto, 73 years old from Okayama Prefectural Okayama Blind School. With the title "Live today without regret," she made a speech breezily about fulfilling school life and stronger motivation for learning.
"With the concrete episodes of interaction with classmates and walking training, she expressed great joy in realizing her dream for the first time in 60 years, which she gave up once, to go on to the blind school. Her august speech, 'Nothing is too late to learn with motivation,' deeply impressed about 300 audiences at the venue." (From the morning edition of The Mainichi Newspapers on Nov. 7th, 2006) Her speech was highly evaluated by the 7 judges including actress Kyoko Mitsubayashi,
"I've been greatly moved all the time since the beginning.
It was very difficult to judge and the result came out with our efforts.
All the speeches got to my heart. Specially, I was deeply impressed with Mrs. Sasaki who continued to speak about her gratitude for her husband even after she passed the time limit although she knew that her marks would be subtracted." (From the review of special judge, actress Kyoko Mitsubayashi)
The 2nd-prize winner was Makoto Nishikame, 49 years old from Osaka Municipal Blind School, its title was "Never ever give up your dream."
The 3rd-prize was Miki Imai, 16 years old from Gifu Prefectural Gifu Blind School. She made a speech enthusiastically with the title "Treasure hunt."
Sumitomo Group Public Affairs Committee presented the 1st-prize winner with Sumitomo Group Cup. Moreover, 3 winners from the 1st to 3rd prize were presented with overseas study tour as supplementary prize. All the 9 participants were presented with the memento of portable CD player as the performance award.
Click to read each speech.
The 1st prize "Live today without regret"
The 2nd prize "Never ever give up your dream"
The 3rd prize "Treasure hunt"
Sumitomo Group Public Affairs Committee


Indiana has the right location and resources for aerospace companies to innovate and grow. As the home of top research universities and global giants in the aerospace industry, Indiana is leading the charge toward breakthroughs in advanced materials and components that are opening up new possibilities for what we can build and where we can go in the 21st century.
With the Institute for Advanced Composite Manufacturing developing new materials at Purdue Research Park, GE Aviation building a $100 million jet engine manufacturing facility, the largest manufacturing facility for Rolls-Royce civil aero jet engines outside the U.K., and recent expansions from Raytheon and Alcoa just to name a few, Indiana aerospace companies are delivering the technologies and the jobs of tomorrow in a state that works.