bacnet/runtime/device.c
changeset 2189 49a6738b7c63
parent 2020 6dddf3070806
child 2261 37ef7a3c6b8b
equal deleted inserted replaced
2186:2ec02f0f9fa9 2189:49a6738b7c63
       
     1 /**************************************************************************
       
     2 *
       
     3 * Copyright (C) 2005,2006,2009 Steve Karg <skarg@users.sourceforge.net>
       
     4 * Copyright (C) 2017 Mario de Sousa <msousa@fe.up.pt>
       
     5 *
       
     6 * Permission is hereby granted, free of charge, to any person obtaining
       
     7 * a copy of this software and associated documentation files (the
       
     8 * "Software"), to deal in the Software without restriction, including
       
     9 * without limitation the rights to use, copy, modify, merge, publish,
       
    10 * distribute, sublicense, and/or sell copies of the Software, and to
       
    11 * permit persons to whom the Software is furnished to do so, subject to
       
    12 * the following conditions:
       
    13 *
       
    14 * The above copyright notice and this permission notice shall be included
       
    15 * in all copies or substantial portions of the Software.
       
    16 *
       
    17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
    20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
       
    21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
       
    22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       
    23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
    24 *
       
    25 *********************************************************************/
       
    26 
       
    27 /** Base "class" for handling all BACnet objects belonging
       
    28  *  to a BACnet device, as well as Device-specific properties. */
       
    29 
       
    30 #include <stdbool.h>
       
    31 #include <stdint.h>
       
    32 #include <string.h>     /* for memmove */
       
    33 #include <time.h>       /* for timezone, localtime */
       
    34 
       
    35 #include "config_bacnet_for_beremiz_%(locstr)s.h"     /* the custom configuration for beremiz plugin */
       
    36 #include "bacdef.h"
       
    37 #include "bacdcode.h"
       
    38 #include "bacenum.h"
       
    39 #include "bacapp.h"
       
    40 #include "apdu.h"
       
    41 #include "wp.h" /* WriteProperty handling */
       
    42 #include "rp.h" /* ReadProperty handling */
       
    43 #include "dcc.h"        /* DeviceCommunicationControl handling */
       
    44 #include "version.h"
       
    45 #include "device_%(locstr)s.h"     /* me */
       
    46 #include "handlers.h"
       
    47 #include "datalink.h"
       
    48 #include "address.h"
       
    49 /* os specfic includes */
       
    50 #include "timer.h"
       
    51 /* include the device object */
       
    52 #include "device_%(locstr)s.h"
       
    53 #include "ai_%(locstr)s.h"
       
    54 #include "ao_%(locstr)s.h"
       
    55 #include "av_%(locstr)s.h"
       
    56 #include "bi_%(locstr)s.h"
       
    57 #include "bo_%(locstr)s.h"
       
    58 #include "bv_%(locstr)s.h"
       
    59 #include "msi_%(locstr)s.h"
       
    60 #include "mso_%(locstr)s.h"
       
    61 #include "msv_%(locstr)s.h"
       
    62 
       
    63 
       
    64 #if defined(__BORLANDC__) || defined(_WIN32)
       
    65 /* Not included in time.h as specified by The Open Group */
       
    66 /* Difference from UTC and local standard time */
       
    67 long int timezone;
       
    68 #endif
       
    69 
       
    70 /* local forward (semi-private) and external prototypes */
       
    71 int Device_Read_Property_Local(
       
    72     BACNET_READ_PROPERTY_DATA * rpdata);
       
    73 bool Device_Write_Property_Local(
       
    74     BACNET_WRITE_PROPERTY_DATA * wp_data);
       
    75 extern int Routed_Device_Read_Property_Local(
       
    76     BACNET_READ_PROPERTY_DATA * rpdata);
       
    77 extern bool Routed_Device_Write_Property_Local(
       
    78     BACNET_WRITE_PROPERTY_DATA * wp_data);
       
    79 
       
    80 /* may be overridden by outside table */
       
    81 static object_functions_t *Object_Table;
       
    82 
       
    83 static object_functions_t My_Object_Table[] = {
       
    84     {OBJECT_DEVICE,
       
    85             NULL /* Init - don't init Device or it will recurse! */ ,
       
    86             Device_Count,
       
    87             Device_Index_To_Instance,
       
    88             Device_Valid_Object_Instance_Number,
       
    89             Device_Object_Name,
       
    90             Device_Read_Property_Local,
       
    91             Device_Write_Property_Local,
       
    92             Device_Property_Lists,
       
    93             DeviceGetRRInfo,
       
    94             NULL /* Iterator */ ,
       
    95             NULL /* Value_Lists */ ,
       
    96             NULL /* COV */ ,
       
    97             NULL /* COV Clear */ ,
       
    98             NULL /* Intrinsic Reporting */ },
       
    99     {OBJECT_ANALOG_INPUT,
       
   100             Analog_Input_Init,
       
   101             Analog_Input_Count,
       
   102             Analog_Input_Index_To_Instance,
       
   103             Analog_Input_Valid_Instance,
       
   104             Analog_Input_Object_Name,
       
   105             Analog_Input_Read_Property,
       
   106             Analog_Input_Write_Property,
       
   107             Analog_Input_Property_Lists,
       
   108             NULL /* ReadRangeInfo */ ,
       
   109             NULL /* Iterator */ ,
       
   110             NULL /* Value_Lists */ ,
       
   111             NULL /* COV */ ,
       
   112             NULL /* COV Clear */ ,
       
   113             NULL /* Intrinsic Reporting */ },
       
   114     {OBJECT_ANALOG_OUTPUT,
       
   115             Analog_Output_Init,
       
   116             Analog_Output_Count,
       
   117             Analog_Output_Index_To_Instance,
       
   118             Analog_Output_Valid_Instance,
       
   119             Analog_Output_Object_Name,
       
   120             Analog_Output_Read_Property,
       
   121             Analog_Output_Write_Property,
       
   122             Analog_Output_Property_Lists,
       
   123             NULL /* ReadRangeInfo */ ,
       
   124             NULL /* Iterator */ ,
       
   125             NULL /* Value_Lists */ ,
       
   126             NULL /* COV */ ,
       
   127             NULL /* COV Clear */ ,
       
   128             NULL /* Intrinsic Reporting */ },
       
   129     {OBJECT_ANALOG_VALUE,
       
   130             Analog_Value_Init,
       
   131             Analog_Value_Count,
       
   132             Analog_Value_Index_To_Instance,
       
   133             Analog_Value_Valid_Instance,
       
   134             Analog_Value_Object_Name,
       
   135             Analog_Value_Read_Property,
       
   136             Analog_Value_Write_Property,
       
   137             Analog_Value_Property_Lists,
       
   138             NULL /* ReadRangeInfo */ ,
       
   139             NULL /* Iterator */ ,
       
   140             NULL /* Value_Lists */ ,
       
   141             NULL /* COV */ ,
       
   142             NULL /* COV Clear */ ,
       
   143             NULL /* Intrinsic Reporting */ },
       
   144     {OBJECT_BINARY_INPUT,
       
   145             Binary_Input_Init,
       
   146             Binary_Input_Count,
       
   147             Binary_Input_Index_To_Instance,
       
   148             Binary_Input_Valid_Instance,
       
   149             Binary_Input_Object_Name,
       
   150             Binary_Input_Read_Property,
       
   151             Binary_Input_Write_Property,
       
   152             Binary_Input_Property_Lists,
       
   153             NULL /* ReadRangeInfo */ ,
       
   154             NULL /* Iterator */ ,
       
   155             NULL /* Value_Lists */ ,
       
   156             NULL /* COV */ ,
       
   157             NULL /* COV Clear */ ,
       
   158             NULL /* Intrinsic Reporting */ },
       
   159     {OBJECT_BINARY_OUTPUT,
       
   160             Binary_Output_Init,
       
   161             Binary_Output_Count,
       
   162             Binary_Output_Index_To_Instance,
       
   163             Binary_Output_Valid_Instance,
       
   164             Binary_Output_Object_Name,
       
   165             Binary_Output_Read_Property,
       
   166             Binary_Output_Write_Property,
       
   167             Binary_Output_Property_Lists,
       
   168             NULL /* ReadRangeInfo */ ,
       
   169             NULL /* Iterator */ ,
       
   170             NULL /* Value_Lists */ ,
       
   171             NULL /* COV */ ,
       
   172             NULL /* COV Clear */ ,
       
   173             NULL /* Intrinsic Reporting */ },
       
   174     {OBJECT_BINARY_VALUE,
       
   175             Binary_Value_Init,
       
   176             Binary_Value_Count,
       
   177             Binary_Value_Index_To_Instance,
       
   178             Binary_Value_Valid_Instance,
       
   179             Binary_Value_Object_Name,
       
   180             Binary_Value_Read_Property,
       
   181             Binary_Value_Write_Property,
       
   182             Binary_Value_Property_Lists,
       
   183             NULL /* ReadRangeInfo */ ,
       
   184             NULL /* Iterator */ ,
       
   185             NULL /* Value_Lists */ ,
       
   186             NULL /* COV */ ,
       
   187             NULL /* COV Clear */ ,
       
   188             NULL /* Intrinsic Reporting */ },
       
   189     {OBJECT_MULTI_STATE_INPUT,
       
   190             Multistate_Input_Init,
       
   191             Multistate_Input_Count,
       
   192             Multistate_Input_Index_To_Instance,
       
   193             Multistate_Input_Valid_Instance,
       
   194             Multistate_Input_Object_Name,
       
   195             Multistate_Input_Read_Property,
       
   196             Multistate_Input_Write_Property,
       
   197             Multistate_Input_Property_Lists,
       
   198             NULL /* ReadRangeInfo */ ,
       
   199             NULL /* Iterator */ ,
       
   200             NULL /* Value_Lists */ ,
       
   201             NULL /* COV */ ,
       
   202             NULL /* COV Clear */ ,
       
   203             NULL /* Intrinsic Reporting */ },
       
   204     {OBJECT_MULTI_STATE_OUTPUT,
       
   205             Multistate_Output_Init,
       
   206             Multistate_Output_Count,
       
   207             Multistate_Output_Index_To_Instance,
       
   208             Multistate_Output_Valid_Instance,
       
   209             Multistate_Output_Object_Name,
       
   210             Multistate_Output_Read_Property,
       
   211             Multistate_Output_Write_Property,
       
   212             Multistate_Output_Property_Lists,
       
   213             NULL /* ReadRangeInfo */ ,
       
   214             NULL /* Iterator */ ,
       
   215             NULL /* Value_Lists */ ,
       
   216             NULL /* COV */ ,
       
   217             NULL /* COV Clear */ ,
       
   218             NULL /* Intrinsic Reporting */ },
       
   219     {OBJECT_MULTI_STATE_VALUE,
       
   220             Multistate_Value_Init,
       
   221             Multistate_Value_Count,
       
   222             Multistate_Value_Index_To_Instance,
       
   223             Multistate_Value_Valid_Instance,
       
   224             Multistate_Value_Object_Name,
       
   225             Multistate_Value_Read_Property,
       
   226             Multistate_Value_Write_Property,
       
   227             Multistate_Value_Property_Lists,
       
   228             NULL /* ReadRangeInfo */ ,
       
   229             NULL /* Iterator */ ,
       
   230             NULL /* Value_Lists */ ,
       
   231             NULL /* COV */ ,
       
   232             NULL /* COV Clear */ ,
       
   233             NULL /* Intrinsic Reporting */ },
       
   234     {MAX_BACNET_OBJECT_TYPE,
       
   235             NULL /* Init */ ,
       
   236             NULL /* Count */ ,
       
   237             NULL /* Index_To_Instance */ ,
       
   238             NULL /* Valid_Instance */ ,
       
   239             NULL /* Object_Name */ ,
       
   240             NULL /* Read_Property */ ,
       
   241             NULL /* Write_Property */ ,
       
   242             NULL /* Property_Lists */ ,
       
   243             NULL /* ReadRangeInfo */ ,
       
   244             NULL /* Iterator */ ,
       
   245             NULL /* Value_Lists */ ,
       
   246             NULL /* COV */ ,
       
   247             NULL /* COV Clear */ ,
       
   248         NULL /* Intrinsic Reporting */ }
       
   249 };
       
   250 
       
   251 /** Glue function to let the Device object, when called by a handler,
       
   252  * lookup which Object type needs to be invoked.
       
   253  * param: Object_Type [in] The type of BACnet Object the handler wants to access.
       
   254  * return: Pointer to the group of object helper functions that implement this
       
   255  *         type of Object.
       
   256  */
       
   257 static struct object_functions *Device_Objects_Find_Functions(
       
   258     BACNET_OBJECT_TYPE Object_Type)
       
   259 {
       
   260     struct object_functions *pObject = NULL;
       
   261 
       
   262     pObject = Object_Table;
       
   263     while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
       
   264         /* handle each object type */
       
   265         if (pObject->Object_Type == Object_Type) {
       
   266             return (pObject);
       
   267         }
       
   268         pObject++;
       
   269     }
       
   270 
       
   271     return (NULL);
       
   272 }
       
   273 
       
   274 /** Try to find a rr_info_function helper function for the requested object type.
       
   275  *
       
   276  * param: object_type [in] The type of BACnet Object the handler wants to access.
       
   277  * return: Pointer to the object helper function that implements the
       
   278  *         ReadRangeInfo function, Object_RR_Info, for this type of Object on
       
   279  *         success, else a NULL pointer if the type of Object isn't supported
       
   280  *         or doesn't have a ReadRangeInfo function.
       
   281  */
       
   282 rr_info_function Device_Objects_RR_Info(
       
   283     BACNET_OBJECT_TYPE object_type)
       
   284 {
       
   285     struct object_functions *pObject = NULL;
       
   286 
       
   287     pObject = Device_Objects_Find_Functions(object_type);
       
   288     return (pObject != NULL ? pObject->Object_RR_Info : NULL);
       
   289 }
       
   290 
       
   291 /** For a given object type, returns the special property list.
       
   292  * This function is used for ReadPropertyMultiple calls which want
       
   293  * just Required, just Optional, or All properties.
       
   294  *
       
   295  * param: object_type [in] The desired BACNET_OBJECT_TYPE whose properties
       
   296  *            are to be listed.
       
   297  * param: pPropertyList [out] Reference to the structure which will, on return,
       
   298  *            list, separately, the Required, Optional, and Proprietary object
       
   299  *            properties with their counts.
       
   300  */
       
   301 void Device_Objects_Property_List(
       
   302     BACNET_OBJECT_TYPE object_type,
       
   303     struct special_property_list_t *pPropertyList)
       
   304 {
       
   305     struct object_functions *pObject = NULL;
       
   306 
       
   307     pPropertyList->Required.pList = NULL;
       
   308     pPropertyList->Optional.pList = NULL;
       
   309     pPropertyList->Proprietary.pList = NULL;
       
   310 
       
   311     /* If we can find an entry for the required object type
       
   312      * and there is an Object_List_RPM fn ptr then call it
       
   313      * to populate the pointers to the individual list counters.
       
   314      */
       
   315 
       
   316     pObject = Device_Objects_Find_Functions(object_type);
       
   317     if ((pObject != NULL) && (pObject->Object_RPM_List != NULL)) {
       
   318         pObject->Object_RPM_List(&pPropertyList->Required.pList,
       
   319             &pPropertyList->Optional.pList, &pPropertyList->Proprietary.pList);
       
   320     }
       
   321 
       
   322     /* Fetch the counts if available otherwise zero them */
       
   323     pPropertyList->Required.count =
       
   324         pPropertyList->Required.pList ==
       
   325         NULL ? 0 : property_list_count(pPropertyList->Required.pList);
       
   326 
       
   327     pPropertyList->Optional.count =
       
   328         pPropertyList->Optional.pList ==
       
   329         NULL ? 0 : property_list_count(pPropertyList->Optional.pList);
       
   330 
       
   331     pPropertyList->Proprietary.count =
       
   332         pPropertyList->Proprietary.pList ==
       
   333         NULL ? 0 : property_list_count(pPropertyList->Proprietary.pList);
       
   334 
       
   335     return;
       
   336 }
       
   337 
       
   338 /** Commands a Device re-initialization, to a given state.
       
   339  * The request's password must match for the operation to succeed.
       
   340  * This implementation provides a framework, but doesn't
       
   341  * actually *DO* anything.
       
   342  * @note You could use a mix of states and passwords to multiple outcomes.
       
   343  * @note You probably want to restart *after* the simple ack has been sent
       
   344  *       from the return handler, so just set a local flag here.
       
   345  *
       
   346  * param: rd_data [in,out] The information from the RD request.
       
   347  *                         On failure, the error class and code will be set.
       
   348  * return: True if succeeds (password is correct), else False.
       
   349  */
       
   350 bool Device_Reinitialize(
       
   351     BACNET_REINITIALIZE_DEVICE_DATA * rd_data)
       
   352 {
       
   353     bool status = false;
       
   354 
       
   355     if (characterstring_ansi_same(&rd_data->password, "Jesus")) {
       
   356         switch (rd_data->state) {
       
   357             case BACNET_REINIT_COLDSTART:
       
   358             case BACNET_REINIT_WARMSTART:
       
   359                 dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
       
   360                 break;
       
   361             case BACNET_REINIT_STARTBACKUP:
       
   362                 break;
       
   363             case BACNET_REINIT_ENDBACKUP:
       
   364                 break;
       
   365             case BACNET_REINIT_STARTRESTORE:
       
   366                 break;
       
   367             case BACNET_REINIT_ENDRESTORE:
       
   368                 break;
       
   369             case BACNET_REINIT_ABORTRESTORE:
       
   370                 break;
       
   371             default:
       
   372                 break;
       
   373         }
       
   374         /* Note: you could use a mix of state
       
   375            and password to multiple things */
       
   376         /* note: you probably want to restart *after* the
       
   377            simple ack has been sent from the return handler
       
   378            so just set a flag from here */
       
   379         status = true;
       
   380     } else {
       
   381         rd_data->error_class = ERROR_CLASS_SECURITY;
       
   382         rd_data->error_code = ERROR_CODE_PASSWORD_FAILURE;
       
   383     }
       
   384 
       
   385     return status;
       
   386 }
       
   387 
       
   388 /* These three arrays are used by the ReadPropertyMultiple handler,
       
   389  * as well as to initialize the XXX_Property_List used by the 
       
   390  * Property List (PROP_PROPERTY_LIST) property.
       
   391  */
       
   392 static const int Device_Properties_Required[] = {
       
   393  /* (1) Currently Supported                  */
       
   394  /* (2) Required by standard ASHRAE 135-2016 */
       
   395                                            /*(1)(2)      */
       
   396     PROP_OBJECT_IDENTIFIER,                /* W  R ( 75) */
       
   397     PROP_OBJECT_NAME,                      /* W  R ( 77) */
       
   398     PROP_OBJECT_TYPE,                      /* R  R ( 79) */
       
   399     PROP_SYSTEM_STATUS,                    /* R  R (112) */
       
   400     PROP_VENDOR_NAME,                      /* R  R (121) */
       
   401     PROP_VENDOR_IDENTIFIER,                /* W  R (120) */
       
   402     PROP_MODEL_NAME,                       /* W  R ( 70) */
       
   403     PROP_FIRMWARE_REVISION,                /* R  R ( 44) */
       
   404     PROP_APPLICATION_SOFTWARE_VERSION,     /* R  R ( 12) */
       
   405     PROP_PROTOCOL_VERSION,                 /* R  R ( 98) */
       
   406     PROP_PROTOCOL_REVISION,                /* R  R (139) */
       
   407     PROP_PROTOCOL_SERVICES_SUPPORTED,      /* R  R ( 97) */
       
   408     PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED,  /* R  R ( 96) */
       
   409     PROP_OBJECT_LIST,                      /* R  R ( 76) */
       
   410     PROP_MAX_APDU_LENGTH_ACCEPTED,         /* R  R ( 62) */
       
   411     PROP_SEGMENTATION_SUPPORTED,           /* R  R (107) */
       
   412     PROP_APDU_TIMEOUT,                     /* W  R ( 11) */
       
   413     PROP_NUMBER_OF_APDU_RETRIES,           /* W  R ( 73) */
       
   414     PROP_DEVICE_ADDRESS_BINDING,           /* R  R ( 30) */
       
   415     PROP_DATABASE_REVISION,                /* R  R (155) */
       
   416 //  PROP_PROPERTY_LIST,                    /* R  R (371) */
       
   417     -1
       
   418 };
       
   419 
       
   420 static const int Device_Properties_Optional[] = {
       
   421     PROP_DESCRIPTION,                      /* W  O ( 28) */
       
   422     PROP_LOCAL_TIME,                       /* R  O ( 57) */
       
   423     PROP_UTC_OFFSET,                       /* R  O (119) */
       
   424     PROP_LOCAL_DATE,                       /* R  O ( 56) */
       
   425     PROP_DAYLIGHT_SAVINGS_STATUS,          /* R  O ( 24) */
       
   426     PROP_LOCATION,                         /* W  O ( 58) */
       
   427     -1
       
   428 };
       
   429 
       
   430 static const int Device_Properties_Proprietary[] = {
       
   431     -1
       
   432 };
       
   433 
       
   434 /* This array stores the PROPERTY_LIST which may be read by clients.
       
   435  * End of list is marked by following the last element with the value '-1'
       
   436  * 
       
   437  * It is initialized by Binary_Value_Init() based off the values
       
   438  * stored in Binary_Value_Properties_Required 
       
   439  *           Binary_Value_Properties_Optional
       
   440  *           Binary_Value_Properties_Proprietary
       
   441  */
       
   442 /* TODO: Allocate memory for this array with malloc() at startup */
       
   443 static int Device_Properties_List[64];
       
   444 
       
   445 
       
   446 void Device_Property_Lists(
       
   447     const int **pRequired,
       
   448     const int **pOptional,
       
   449     const int **pProprietary)
       
   450 {
       
   451     if (pRequired)
       
   452         *pRequired = Device_Properties_Required;
       
   453     if (pOptional)
       
   454         *pOptional = Device_Properties_Optional;
       
   455     if (pProprietary)
       
   456         *pProprietary = Device_Properties_Proprietary;
       
   457 
       
   458     return;
       
   459 }
       
   460 
       
   461 
       
   462 static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
       
   463 
       
   464 static BACNET_CHARACTER_STRING My_Object_Name;
       
   465 static uint32_t Object_Instance_Number                             = 260001;
       
   466 static uint16_t Vendor_Identifier                                  = BACNET_VENDOR_ID;
       
   467 static char    *Vendor_Name                                        = BACNET_VENDOR_NAME;
       
   468 static char    *Firmware_Revision                                  = BACNET_FIRMWARE_REVISION;
       
   469 static char     Model_Name                  [MAX_DEV_MOD_LEN  + 1] = BACNET_DEVICE_MODEL_NAME;
       
   470 static char     Application_Software_Version[MAX_DEV_VER_LEN  + 1] = BACNET_DEVICE_APPSOFT_VER;
       
   471 static char     Location                    [MAX_DEV_LOC_LEN  + 1] = BACNET_DEVICE_LOCATION;
       
   472 static char     Description                 [MAX_DEV_DESC_LEN + 1] = BACNET_DEVICE_DESCRIPTION;
       
   473 /* static uint8_t Protocol_Version = 1; - constant, not settable */
       
   474 /* static uint8_t Protocol_Revision = 4; - constant, not settable */
       
   475 /* Protocol_Services_Supported - dynamically generated */
       
   476 /* Protocol_Object_Types_Supported - in RP encoding */
       
   477 /* Object_List - dynamically generated */
       
   478 /* static BACNET_SEGMENTATION Segmentation_Supported = SEGMENTATION_NONE; */
       
   479 /* static uint8_t Max_Segments_Accepted = 0; */
       
   480 /* VT_Classes_Supported */
       
   481 /* Active_VT_Sessions */
       
   482 static BACNET_TIME Local_Time;  /* rely on OS, if there is one */
       
   483 static BACNET_DATE Local_Date;  /* rely on OS, if there is one */
       
   484 /* NOTE: BACnet UTC Offset is inverse of common practice.
       
   485    If your UTC offset is -5hours of GMT,
       
   486    then BACnet UTC offset is +5hours.
       
   487    BACnet UTC offset is expressed in minutes. */
       
   488 static int32_t UTC_Offset = 5 * 60;
       
   489 static bool Daylight_Savings_Status = false;    /* rely on OS */
       
   490 /* List_Of_Session_Keys */
       
   491 /* Time_Synchronization_Recipients */
       
   492 /* Max_Master - rely on MS/TP subsystem, if there is one */
       
   493 /* Max_Info_Frames - rely on MS/TP subsystem, if there is one */
       
   494 /* Device_Address_Binding - required, but relies on binding cache */
       
   495 static uint32_t Database_Revision = 0;
       
   496 /* Configuration_Files */
       
   497 /* Last_Restore_Time */
       
   498 /* Backup_Failure_Timeout */
       
   499 /* Active_COV_Subscriptions */
       
   500 /* Slave_Proxy_Enable */
       
   501 /* Manual_Slave_Address_Binding */
       
   502 /* Auto_Slave_Discovery */
       
   503 /* Slave_Address_Binding */
       
   504 /* Profile_Name */
       
   505 
       
   506 unsigned Device_Count(
       
   507     void)
       
   508 {
       
   509     return 1;
       
   510 }
       
   511 
       
   512 uint32_t Device_Index_To_Instance(
       
   513     unsigned index)
       
   514 {
       
   515     index = index;
       
   516     return Object_Instance_Number;
       
   517 }
       
   518 
       
   519 /* methods to manipulate the data */
       
   520 
       
   521 /** Return the Object Instance number for our (single) Device Object.
       
   522  * This is a key function, widely invoked by the handler code, since
       
   523  * it provides "our" (ie, local) address.
       
   524  * return: The Instance number used in the BACNET_OBJECT_ID for the Device.
       
   525  */
       
   526 uint32_t Device_Object_Instance_Number(
       
   527     void)
       
   528 {
       
   529     return Object_Instance_Number;
       
   530 }
       
   531 
       
   532 bool Device_Set_Object_Instance_Number(
       
   533     uint32_t object_id)
       
   534 {
       
   535     bool status = true; /* return value */
       
   536 
       
   537     if (object_id <= BACNET_MAX_INSTANCE) {
       
   538         /* Make the change and update the database revision */
       
   539         Object_Instance_Number = object_id;
       
   540         Device_Inc_Database_Revision();
       
   541     } else
       
   542         status = false;
       
   543 
       
   544     return status;
       
   545 }
       
   546 
       
   547 bool Device_Valid_Object_Instance_Number(
       
   548     uint32_t object_id)
       
   549 {
       
   550     return (Object_Instance_Number == object_id);
       
   551 }
       
   552 
       
   553 bool Device_Object_Name(
       
   554     uint32_t object_instance,
       
   555     BACNET_CHARACTER_STRING * object_name)
       
   556 {
       
   557     bool status = false;
       
   558 
       
   559     if (object_instance == Object_Instance_Number) {
       
   560         status = characterstring_copy(object_name, &My_Object_Name);
       
   561     }
       
   562 
       
   563     return status;
       
   564 }
       
   565 
       
   566 bool Device_Set_Object_Name(
       
   567     BACNET_CHARACTER_STRING * object_name)
       
   568 {
       
   569     bool status = false;        /*return value */
       
   570 
       
   571     if (!characterstring_same(&My_Object_Name, object_name)) {
       
   572         /* Make the change and update the database revision */
       
   573         status = characterstring_copy(&My_Object_Name, object_name);
       
   574         Device_Inc_Database_Revision();
       
   575     }
       
   576 
       
   577     return status;
       
   578 }
       
   579 
       
   580 BACNET_DEVICE_STATUS Device_System_Status(
       
   581     void)
       
   582 {
       
   583     return System_Status;
       
   584 }
       
   585 
       
   586 int Device_Set_System_Status(
       
   587     BACNET_DEVICE_STATUS status,
       
   588     bool local)
       
   589 {
       
   590     int result = 0;     /*return value - 0 = ok, -1 = bad value, -2 = not allowed */
       
   591 
       
   592     /* We limit the options available depending on whether the source is
       
   593      * internal or external. */
       
   594     if (local) {
       
   595         switch (status) {
       
   596             case STATUS_OPERATIONAL:
       
   597             case STATUS_OPERATIONAL_READ_ONLY:
       
   598             case STATUS_DOWNLOAD_REQUIRED:
       
   599             case STATUS_DOWNLOAD_IN_PROGRESS:
       
   600             case STATUS_NON_OPERATIONAL:
       
   601                 System_Status = status;
       
   602                 break;
       
   603 
       
   604                 /* Don't support backup at present so don't allow setting */
       
   605             case STATUS_BACKUP_IN_PROGRESS:
       
   606                 result = -2;
       
   607                 break;
       
   608 
       
   609             default:
       
   610                 result = -1;
       
   611                 break;
       
   612         }
       
   613     } else {
       
   614         switch (status) {
       
   615                 /* Allow these for the moment as a way to easily alter
       
   616                  * overall device operation. The lack of password protection
       
   617                  * or other authentication makes allowing writes to this
       
   618                  * property a risky facility to provide.
       
   619                  */
       
   620             case STATUS_OPERATIONAL:
       
   621             case STATUS_OPERATIONAL_READ_ONLY:
       
   622             case STATUS_NON_OPERATIONAL:
       
   623                 System_Status = status;
       
   624                 break;
       
   625 
       
   626                 /* Don't allow outsider set this - it should probably
       
   627                  * be set if the device config is incomplete or
       
   628                  * corrupted or perhaps after some sort of operator
       
   629                  * wipe operation.
       
   630                  */
       
   631             case STATUS_DOWNLOAD_REQUIRED:
       
   632                 /* Don't allow outsider set this - it should be set
       
   633                  * internally at the start of a multi packet download
       
   634                  * perhaps indirectly via PT or WF to a config file.
       
   635                  */
       
   636             case STATUS_DOWNLOAD_IN_PROGRESS:
       
   637                 /* Don't support backup at present so don't allow setting */
       
   638             case STATUS_BACKUP_IN_PROGRESS:
       
   639                 result = -2;
       
   640                 break;
       
   641 
       
   642             default:
       
   643                 result = -1;
       
   644                 break;
       
   645         }
       
   646     }
       
   647 
       
   648     return (result);
       
   649 }
       
   650 
       
   651 const char *Device_Vendor_Name(
       
   652     void)
       
   653 {
       
   654     return Vendor_Name;
       
   655 }
       
   656 
       
   657 /** Returns the Vendor ID for this Device.
       
   658  * See the assignments at http://www.bacnet.org/VendorID/BACnet%%20Vendor%%20IDs.htm
       
   659  * return: The Vendor ID of this Device.
       
   660  */
       
   661 uint16_t Device_Vendor_Identifier(
       
   662     void)
       
   663 {
       
   664     return Vendor_Identifier;
       
   665 }
       
   666 
       
   667 void Device_Set_Vendor_Identifier(
       
   668     uint16_t vendor_id)
       
   669 {
       
   670     Vendor_Identifier = vendor_id;
       
   671 }
       
   672 
       
   673 const char *Device_Model_Name(
       
   674     void)
       
   675 {
       
   676     return Model_Name;
       
   677 }
       
   678 
       
   679 bool Device_Set_Model_Name(
       
   680     const char *name,
       
   681     size_t length)
       
   682 {
       
   683     bool status = false;        /*return value */
       
   684 
       
   685     if (length < sizeof(Model_Name)) {
       
   686         memmove(Model_Name, name, length);
       
   687         Model_Name[length] = 0;
       
   688         status = true;
       
   689     }
       
   690 
       
   691     return status;
       
   692 }
       
   693 
       
   694 const char *Device_Firmware_Revision(
       
   695     void)
       
   696 {
       
   697      return Firmware_Revision;
       
   698 }
       
   699 
       
   700 const char *Device_Application_Software_Version(
       
   701     void)
       
   702 {
       
   703     return Application_Software_Version;
       
   704 }
       
   705 
       
   706 bool Device_Set_Application_Software_Version(
       
   707     const char *name,
       
   708     size_t length)
       
   709 {
       
   710     bool status = false;        /*return value */
       
   711 
       
   712     if (length < sizeof(Application_Software_Version)) {
       
   713         memmove(Application_Software_Version, name, length);
       
   714         Application_Software_Version[length] = 0;
       
   715         status = true;
       
   716     }
       
   717 
       
   718     return status;
       
   719 }
       
   720 
       
   721 const char *Device_Description(
       
   722     void)
       
   723 {
       
   724     return Description;
       
   725 }
       
   726 
       
   727 bool Device_Set_Description(
       
   728     const char *name,
       
   729     size_t length)
       
   730 {
       
   731     bool status = false;        /*return value */
       
   732 
       
   733     if (length < sizeof(Description)) {
       
   734         memmove(Description, name, length);
       
   735         Description[length] = 0;
       
   736         status = true;
       
   737     }
       
   738 
       
   739     return status;
       
   740 }
       
   741 
       
   742 const char *Device_Location(
       
   743     void)
       
   744 {
       
   745     return Location;
       
   746 }
       
   747 
       
   748 bool Device_Set_Location(
       
   749     const char *name,
       
   750     size_t length)
       
   751 {
       
   752     bool status = false;        /*return value */
       
   753 
       
   754     if (length < sizeof(Location)) {
       
   755         memmove(Location, name, length);
       
   756         Location[length] = 0;
       
   757         status = true;
       
   758     }
       
   759 
       
   760     return status;
       
   761 }
       
   762 
       
   763 uint8_t Device_Protocol_Version(
       
   764     void)
       
   765 {
       
   766     return BACNET_PROTOCOL_VERSION;
       
   767 }
       
   768 
       
   769 uint8_t Device_Protocol_Revision(
       
   770     void)
       
   771 {
       
   772     return BACNET_PROTOCOL_REVISION;
       
   773 }
       
   774 
       
   775 BACNET_SEGMENTATION Device_Segmentation_Supported(
       
   776     void)
       
   777 {
       
   778     return SEGMENTATION_NONE;
       
   779 }
       
   780 
       
   781 uint32_t Device_Database_Revision(
       
   782     void)
       
   783 {
       
   784     return Database_Revision;
       
   785 }
       
   786 
       
   787 void Device_Set_Database_Revision(
       
   788     uint32_t revision)
       
   789 {
       
   790     Database_Revision = revision;
       
   791 }
       
   792 
       
   793 /*
       
   794  * Shortcut for incrementing database revision as this is potentially
       
   795  * the most common operation if changing object names and ids is
       
   796  * implemented.
       
   797  */
       
   798 void Device_Inc_Database_Revision(
       
   799     void)
       
   800 {
       
   801     Database_Revision++;
       
   802 }
       
   803 
       
   804 /** Get the total count of objects supported by this Device Object.
       
   805  * @note Since many network clients depend on the object list
       
   806  *       for discovery, it must be consistent!
       
   807  * return: The count of objects, for all supported Object types.
       
   808  */
       
   809 unsigned Device_Object_List_Count(
       
   810     void)
       
   811 {
       
   812     unsigned count = 0; /* number of objects */
       
   813     struct object_functions *pObject = NULL;
       
   814 
       
   815     /* initialize the default return values */
       
   816     pObject = Object_Table;
       
   817     while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
       
   818         if (pObject->Object_Count) {
       
   819             count += pObject->Object_Count();
       
   820         }
       
   821         pObject++;
       
   822     }
       
   823 
       
   824     return count;
       
   825 }
       
   826 
       
   827 /** Lookup the Object at the given array index in the Device's Object List.
       
   828  * Even though we don't keep a single linear array of objects in the Device,
       
   829  * this method acts as though we do and works through a virtual, concatenated
       
   830  * array of all of our object type arrays.
       
   831  *
       
   832  * param: array_index [in] The desired array index (1 to N)
       
   833  * param: object_type [out] The object's type, if found.
       
   834  * param: instance [out] The object's instance number, if found.
       
   835  * return: True if found, else false.
       
   836  */
       
   837 bool Device_Object_List_Identifier(
       
   838     unsigned array_index,
       
   839     int *object_type,
       
   840     uint32_t * instance)
       
   841 {
       
   842     bool status = false;
       
   843     unsigned count = 0;
       
   844     unsigned object_index = 0;
       
   845     unsigned temp_index = 0;
       
   846     struct object_functions *pObject = NULL;
       
   847 
       
   848     /* array index zero is length - so invalid */
       
   849     if (array_index == 0) {
       
   850         return status;
       
   851     }
       
   852     object_index = array_index - 1;
       
   853     /* initialize the default return values */
       
   854     pObject = Object_Table;
       
   855     while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
       
   856         if (pObject->Object_Count) {
       
   857             object_index -= count;
       
   858             count = pObject->Object_Count();
       
   859             if (object_index < count) {
       
   860                 /* Use the iterator function if available otherwise
       
   861                  * look for the index to instance to get the ID */
       
   862                 if (pObject->Object_Iterator) {
       
   863                     /* First find the first object */
       
   864                     temp_index = pObject->Object_Iterator(~(unsigned) 0);
       
   865                     /* Then step through the objects to find the nth */
       
   866                     while (object_index != 0) {
       
   867                         temp_index = pObject->Object_Iterator(temp_index);
       
   868                         object_index--;
       
   869                     }
       
   870                     /* set the object_index up before falling through to next bit */
       
   871                     object_index = temp_index;
       
   872                 }
       
   873                 if (pObject->Object_Index_To_Instance) {
       
   874                     *object_type = pObject->Object_Type;
       
   875                     *instance =
       
   876                         pObject->Object_Index_To_Instance(object_index);
       
   877                     status = true;
       
   878                     break;
       
   879                 }
       
   880             }
       
   881         }
       
   882         pObject++;
       
   883     }
       
   884 
       
   885     return status;
       
   886 }
       
   887 
       
   888 /** Determine if we have an object with the given object_name.
       
   889  * If the object_type and object_instance pointers are not null,
       
   890  * and the lookup succeeds, they will be given the resulting values.
       
   891  * param: object_name [in] The desired Object Name to look for.
       
   892  * param: object_type [out] The BACNET_OBJECT_TYPE of the matching Object.
       
   893  * param: object_instance [out] The object instance number of the matching Object.
       
   894  * return: True on success or else False if not found.
       
   895  */
       
   896 bool Device_Valid_Object_Name(
       
   897     BACNET_CHARACTER_STRING * object_name1,
       
   898     int *object_type,
       
   899     uint32_t * object_instance)
       
   900 {
       
   901     bool found = false;
       
   902     int type = 0;
       
   903     uint32_t instance;
       
   904     unsigned max_objects = 0, i = 0;
       
   905     bool check_id = false;
       
   906     BACNET_CHARACTER_STRING object_name2;
       
   907     struct object_functions *pObject = NULL;
       
   908 
       
   909     max_objects = Device_Object_List_Count();
       
   910     for (i = 1; i <= max_objects; i++) {
       
   911         check_id = Device_Object_List_Identifier(i, &type, &instance);
       
   912         if (check_id) {
       
   913             pObject = Device_Objects_Find_Functions(type);
       
   914             if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
       
   915                 (pObject->Object_Name(instance, &object_name2) &&
       
   916                     characterstring_same(object_name1, &object_name2))) {
       
   917                 found = true;
       
   918                 if (object_type) {
       
   919                     *object_type = type;
       
   920                 }
       
   921                 if (object_instance) {
       
   922                     *object_instance = instance;
       
   923                 }
       
   924                 break;
       
   925             }
       
   926         }
       
   927     }
       
   928 
       
   929     return found;
       
   930 }
       
   931 
       
   932 /** Determine if we have an object of this type and instance number.
       
   933  * param: object_type [in] The desired BACNET_OBJECT_TYPE
       
   934  * param: object_instance [in] The object instance number to be looked up.
       
   935  * return: True if found, else False if no such Object in this device.
       
   936  */
       
   937 bool Device_Valid_Object_Id(
       
   938     int object_type,
       
   939     uint32_t object_instance)
       
   940 {
       
   941     bool status = false;        /* return value */
       
   942     struct object_functions *pObject = NULL;
       
   943 
       
   944     pObject = Device_Objects_Find_Functions(object_type);
       
   945     if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
       
   946         status = pObject->Object_Valid_Instance(object_instance);
       
   947     }
       
   948 
       
   949     return status;
       
   950 }
       
   951 
       
   952 /** Copy a child object's object_name value, given its ID.
       
   953  * param: object_type [in] The BACNET_OBJECT_TYPE of the child Object.
       
   954  * param: object_instance [in] The object instance number of the child Object.
       
   955  * param: object_name [out] The Object Name found for this child Object.
       
   956  * return: True on success or else False if not found.
       
   957  */
       
   958 bool Device_Object_Name_Copy(
       
   959     BACNET_OBJECT_TYPE object_type,
       
   960     uint32_t object_instance,
       
   961     BACNET_CHARACTER_STRING * object_name)
       
   962 {
       
   963     struct object_functions *pObject = NULL;
       
   964     bool found = false;
       
   965 
       
   966     pObject = Device_Objects_Find_Functions(object_type);
       
   967     if ((pObject != NULL) && (pObject->Object_Name != NULL)) {
       
   968         found = pObject->Object_Name(object_instance, object_name);
       
   969     }
       
   970 
       
   971     return found;
       
   972 }
       
   973 
       
   974 static void Device_Update_Current_Time(
       
   975     void)
       
   976 {
       
   977     struct tm *tblock = NULL;
       
   978 #if defined(_MSC_VER)
       
   979     time_t tTemp;
       
   980 #else
       
   981     struct timeval tv;
       
   982 #endif
       
   983 /*
       
   984 struct tm
       
   985 
       
   986 int    tm_sec   Seconds [0,60].
       
   987 int    tm_min   Minutes [0,59].
       
   988 int    tm_hour  Hour [0,23].
       
   989 int    tm_mday  Day of month [1,31].
       
   990 int    tm_mon   Month of year [0,11].
       
   991 int    tm_year  Years since 1900.
       
   992 int    tm_wday  Day of week [0,6] (Sunday =0).
       
   993 int    tm_yday  Day of year [0,365].
       
   994 int    tm_isdst Daylight Savings flag.
       
   995 */
       
   996 #if defined(_MSC_VER)
       
   997     time(&tTemp);
       
   998     tblock = localtime(&tTemp);
       
   999 #else
       
  1000     if (gettimeofday(&tv, NULL) == 0) {
       
  1001         tblock = localtime(&tv.tv_sec);
       
  1002     }
       
  1003 #endif
       
  1004 
       
  1005     if (tblock) {
       
  1006         datetime_set_date(&Local_Date, (uint16_t) tblock->tm_year + 1900,
       
  1007             (uint8_t) tblock->tm_mon + 1, (uint8_t) tblock->tm_mday);
       
  1008 #if !defined(_MSC_VER)
       
  1009         datetime_set_time(&Local_Time, (uint8_t) tblock->tm_hour,
       
  1010             (uint8_t) tblock->tm_min, (uint8_t) tblock->tm_sec,
       
  1011             (uint8_t) (tv.tv_usec / 10000));
       
  1012 #else
       
  1013         datetime_set_time(&Local_Time, (uint8_t) tblock->tm_hour,
       
  1014             (uint8_t) tblock->tm_min, (uint8_t) tblock->tm_sec, 0);
       
  1015 #endif
       
  1016         if (tblock->tm_isdst) {
       
  1017             Daylight_Savings_Status = true;
       
  1018         } else {
       
  1019             Daylight_Savings_Status = false;
       
  1020         }
       
  1021         /* note: timezone is declared in <time.h> stdlib. */
       
  1022         UTC_Offset = timezone / 60;
       
  1023     } else {
       
  1024         datetime_date_wildcard_set(&Local_Date);
       
  1025         datetime_time_wildcard_set(&Local_Time);
       
  1026         Daylight_Savings_Status = false;
       
  1027     }
       
  1028 }
       
  1029 
       
  1030 void Device_getCurrentDateTime(
       
  1031     BACNET_DATE_TIME * DateTime)
       
  1032 {
       
  1033     Device_Update_Current_Time();
       
  1034 
       
  1035     DateTime->date = Local_Date;
       
  1036     DateTime->time = Local_Time;
       
  1037 }
       
  1038 
       
  1039 int32_t Device_UTC_Offset(void)
       
  1040 {
       
  1041     Device_Update_Current_Time();
       
  1042 
       
  1043     return UTC_Offset;
       
  1044 }
       
  1045 
       
  1046 bool Device_Daylight_Savings_Status(void)
       
  1047 {
       
  1048     return Daylight_Savings_Status;
       
  1049 }
       
  1050 
       
  1051 /* return the length of the apdu encoded or BACNET_STATUS_ERROR for error or
       
  1052    BACNET_STATUS_ABORT for abort message */
       
  1053 int Device_Read_Property_Local(
       
  1054     BACNET_READ_PROPERTY_DATA * rpdata)
       
  1055 {
       
  1056     int apdu_len = 0;   /* return value */
       
  1057     int len = 0;        /* apdu len intermediate value */
       
  1058     BACNET_BIT_STRING bit_string = { 0 };
       
  1059     BACNET_CHARACTER_STRING char_string = { 0 };
       
  1060     unsigned i = 0;
       
  1061     int object_type = 0;
       
  1062     uint32_t instance = 0;
       
  1063     unsigned count = 0;
       
  1064     uint8_t *apdu = NULL;
       
  1065     struct object_functions *pObject = NULL;
       
  1066     bool found = false;
       
  1067 
       
  1068     if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
       
  1069         (rpdata->application_data_len == 0)) {
       
  1070         return 0;
       
  1071     }
       
  1072     apdu = rpdata->application_data;
       
  1073     switch (rpdata->object_property) {
       
  1074         case PROP_OBJECT_IDENTIFIER:
       
  1075             apdu_len =
       
  1076                 encode_application_object_id(&apdu[0], OBJECT_DEVICE,
       
  1077                 Object_Instance_Number);
       
  1078             break;
       
  1079         case PROP_OBJECT_NAME:
       
  1080             apdu_len =
       
  1081                 encode_application_character_string(&apdu[0], &My_Object_Name);
       
  1082             break;
       
  1083         case PROP_OBJECT_TYPE:
       
  1084             apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
       
  1085             break;
       
  1086         case PROP_DESCRIPTION:
       
  1087             characterstring_init_ansi(&char_string, Description);
       
  1088             apdu_len =
       
  1089                 encode_application_character_string(&apdu[0], &char_string);
       
  1090             break;
       
  1091         case PROP_SYSTEM_STATUS:
       
  1092             apdu_len = encode_application_enumerated(&apdu[0], System_Status);
       
  1093             break;
       
  1094         case PROP_VENDOR_NAME:
       
  1095             characterstring_init_ansi(&char_string, Vendor_Name);
       
  1096             apdu_len =
       
  1097                 encode_application_character_string(&apdu[0], &char_string);
       
  1098             break;
       
  1099         case PROP_VENDOR_IDENTIFIER:
       
  1100             apdu_len =
       
  1101                 encode_application_unsigned(&apdu[0], Vendor_Identifier);
       
  1102             break;
       
  1103         case PROP_MODEL_NAME:
       
  1104             characterstring_init_ansi(&char_string, Model_Name);
       
  1105             apdu_len =
       
  1106                 encode_application_character_string(&apdu[0], &char_string);
       
  1107             break;
       
  1108         case PROP_FIRMWARE_REVISION:
       
  1109             characterstring_init_ansi(&char_string, Firmware_Revision);
       
  1110             apdu_len =
       
  1111                 encode_application_character_string(&apdu[0], &char_string);
       
  1112             break;
       
  1113         case PROP_APPLICATION_SOFTWARE_VERSION:
       
  1114             characterstring_init_ansi(&char_string,
       
  1115                 Application_Software_Version);
       
  1116             apdu_len =
       
  1117                 encode_application_character_string(&apdu[0], &char_string);
       
  1118             break;
       
  1119         case PROP_LOCATION:
       
  1120             characterstring_init_ansi(&char_string, Location);
       
  1121             apdu_len =
       
  1122                 encode_application_character_string(&apdu[0], &char_string);
       
  1123             break;
       
  1124         case PROP_LOCAL_TIME:
       
  1125             Device_Update_Current_Time();
       
  1126             apdu_len = encode_application_time(&apdu[0], &Local_Time);
       
  1127             break;
       
  1128         case PROP_UTC_OFFSET:
       
  1129             Device_Update_Current_Time();
       
  1130             apdu_len = encode_application_signed(&apdu[0], UTC_Offset);
       
  1131             break;
       
  1132         case PROP_LOCAL_DATE:
       
  1133             Device_Update_Current_Time();
       
  1134             apdu_len = encode_application_date(&apdu[0], &Local_Date);
       
  1135             break;
       
  1136         case PROP_DAYLIGHT_SAVINGS_STATUS:
       
  1137             Device_Update_Current_Time();
       
  1138             apdu_len =
       
  1139                 encode_application_boolean(&apdu[0], Daylight_Savings_Status);
       
  1140             break;
       
  1141         case PROP_PROTOCOL_VERSION:
       
  1142             apdu_len =
       
  1143                 encode_application_unsigned(&apdu[0],
       
  1144                 Device_Protocol_Version());
       
  1145             break;
       
  1146         case PROP_PROTOCOL_REVISION:
       
  1147             apdu_len =
       
  1148                 encode_application_unsigned(&apdu[0],
       
  1149                 Device_Protocol_Revision());
       
  1150             break;
       
  1151         case PROP_PROTOCOL_SERVICES_SUPPORTED:
       
  1152             /* Note: list of services that are executed, not initiated. */
       
  1153             bitstring_init(&bit_string);
       
  1154             for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
       
  1155                 /* automatic lookup based on handlers set */
       
  1156                 bitstring_set_bit(&bit_string, (uint8_t) i,
       
  1157                     apdu_service_supported((BACNET_SERVICES_SUPPORTED) i));
       
  1158             }
       
  1159             apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
       
  1160             break;
       
  1161         case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
       
  1162             /* Note: this is the list of objects that can be in this device,
       
  1163                not a list of objects that this device can access */
       
  1164             bitstring_init(&bit_string);
       
  1165             for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
       
  1166                 /* initialize all the object types to not-supported */
       
  1167                 bitstring_set_bit(&bit_string, (uint8_t) i, false);
       
  1168             }
       
  1169             /* set the object types with objects to supported */
       
  1170 
       
  1171             pObject = Object_Table;
       
  1172             while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
       
  1173                 if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) {
       
  1174                     bitstring_set_bit(&bit_string, pObject->Object_Type, true);
       
  1175                 }
       
  1176                 pObject++;
       
  1177             }
       
  1178             apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
       
  1179             break;
       
  1180         case PROP_OBJECT_LIST:
       
  1181             count = Device_Object_List_Count();
       
  1182             /* Array element zero is the number of objects in the list */
       
  1183             if (rpdata->array_index == 0)
       
  1184                 apdu_len = encode_application_unsigned(&apdu[0], count);
       
  1185             /* if no index was specified, then try to encode the entire list */
       
  1186             /* into one packet.  Note that more than likely you will have */
       
  1187             /* to return an error if the number of encoded objects exceeds */
       
  1188             /* your maximum APDU size. */
       
  1189             else if (rpdata->array_index == BACNET_ARRAY_ALL) {
       
  1190                 for (i = 1; i <= count; i++) {
       
  1191                     found =
       
  1192                         Device_Object_List_Identifier(i, &object_type,
       
  1193                         &instance);
       
  1194                     if (found) {
       
  1195                         len =
       
  1196                             encode_application_object_id(&apdu[apdu_len],
       
  1197                             object_type, instance);
       
  1198                         apdu_len += len;
       
  1199                         /* assume next one is the same size as this one */
       
  1200                         /* can we all fit into the APDU? Don't check for last entry */
       
  1201                         if ((i != count) && (apdu_len + len) >= MAX_APDU) {
       
  1202                             /* Abort response */
       
  1203                             rpdata->error_code =
       
  1204                                 ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
       
  1205                             apdu_len = BACNET_STATUS_ABORT;
       
  1206                             break;
       
  1207                         }
       
  1208                     } else {
       
  1209                         /* error: internal error? */
       
  1210                         rpdata->error_class = ERROR_CLASS_SERVICES;
       
  1211                         rpdata->error_code = ERROR_CODE_OTHER;
       
  1212                         apdu_len = BACNET_STATUS_ERROR;
       
  1213                         break;
       
  1214                     }
       
  1215                 }
       
  1216             } else {
       
  1217                 found =
       
  1218                     Device_Object_List_Identifier(rpdata->array_index,
       
  1219                     &object_type, &instance);
       
  1220                 if (found) {
       
  1221                     apdu_len =
       
  1222                         encode_application_object_id(&apdu[0], object_type,
       
  1223                         instance);
       
  1224                 } else {
       
  1225                     rpdata->error_class = ERROR_CLASS_PROPERTY;
       
  1226                     rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
       
  1227                     apdu_len = BACNET_STATUS_ERROR;
       
  1228                 }
       
  1229             }
       
  1230             break;
       
  1231         case PROP_MAX_APDU_LENGTH_ACCEPTED:
       
  1232             apdu_len = encode_application_unsigned(&apdu[0], MAX_APDU);
       
  1233             break;
       
  1234         case PROP_SEGMENTATION_SUPPORTED:
       
  1235             apdu_len =
       
  1236                 encode_application_enumerated(&apdu[0],
       
  1237                 Device_Segmentation_Supported());
       
  1238             break;
       
  1239         case PROP_APDU_TIMEOUT:
       
  1240             apdu_len = encode_application_unsigned(&apdu[0], apdu_timeout());
       
  1241             break;
       
  1242         case PROP_NUMBER_OF_APDU_RETRIES:
       
  1243             apdu_len = encode_application_unsigned(&apdu[0], apdu_retries());
       
  1244             break;
       
  1245         case PROP_DEVICE_ADDRESS_BINDING:
       
  1246             /* FIXME: the real max apdu remaining should be passed into function */
       
  1247             apdu_len = address_list_encode(&apdu[0], MAX_APDU);
       
  1248             break;
       
  1249         case PROP_DATABASE_REVISION:
       
  1250             apdu_len =
       
  1251                 encode_application_unsigned(&apdu[0], Database_Revision);
       
  1252             break;
       
  1253 //      case PROP_PROPERTY_LIST:
       
  1254 //          BACnet_encode_array(Device_Properties_List,
       
  1255 //                              property_list_count(Device_Properties_List),
       
  1256 //                              retfalse, encode_application_enumerated);
       
  1257 //          break;
       
  1258         default:
       
  1259             rpdata->error_class = ERROR_CLASS_PROPERTY;
       
  1260             rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
       
  1261             apdu_len = BACNET_STATUS_ERROR;
       
  1262             break;
       
  1263     }
       
  1264     /*  only array properties can have array options */
       
  1265     if ((apdu_len >= 0) && (rpdata->object_property != PROP_OBJECT_LIST) &&
       
  1266 //      (rpdata->object_property != PROP_PROPERTY_LIST) &&
       
  1267         (rpdata->array_index != BACNET_ARRAY_ALL)) {
       
  1268         rpdata->error_class = ERROR_CLASS_PROPERTY;
       
  1269         rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
       
  1270         apdu_len = BACNET_STATUS_ERROR;
       
  1271     }
       
  1272 
       
  1273     return apdu_len;
       
  1274 }
       
  1275 
       
  1276 /** Looks up the requested Object and Property, and encodes its Value in an APDU.
       
  1277  * If the Object or Property can't be found, sets the error class and code.
       
  1278  *
       
  1279  * param: rpdata [in,out] Structure with the desired Object and Property info
       
  1280  *                 on entry, and APDU message on return.
       
  1281  * return: The length of the APDU on success, else BACNET_STATUS_ERROR
       
  1282  */
       
  1283 int Device_Read_Property(
       
  1284     BACNET_READ_PROPERTY_DATA * rpdata)
       
  1285 {
       
  1286     int apdu_len = BACNET_STATUS_ERROR;
       
  1287     struct object_functions *pObject = NULL;
       
  1288 
       
  1289     /* initialize the default return values */
       
  1290     rpdata->error_class = ERROR_CLASS_OBJECT;
       
  1291     rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
       
  1292     pObject = Device_Objects_Find_Functions(rpdata->object_type);
       
  1293     if (pObject != NULL) {
       
  1294         if (pObject->Object_Valid_Instance &&
       
  1295             pObject->Object_Valid_Instance(rpdata->object_instance)) {
       
  1296             if (pObject->Object_Read_Property) {
       
  1297                 apdu_len = pObject->Object_Read_Property(rpdata);
       
  1298             }
       
  1299         }
       
  1300     }
       
  1301 
       
  1302     return apdu_len;
       
  1303 }
       
  1304 
       
  1305 /* returns true if successful */
       
  1306 bool Device_Write_Property_Local(
       
  1307     BACNET_WRITE_PROPERTY_DATA * wp_data)
       
  1308 {
       
  1309     bool status = false;        /* return value */
       
  1310     int len = 0;
       
  1311     BACNET_APPLICATION_DATA_VALUE value;
       
  1312     int object_type = 0;
       
  1313     uint32_t object_instance = 0;
       
  1314     int temp;
       
  1315 
       
  1316     /* decode the some of the request */
       
  1317     len =
       
  1318         bacapp_decode_application_data(wp_data->application_data,
       
  1319         wp_data->application_data_len, &value);
       
  1320     if (len < 0) {
       
  1321         /* error while decoding - a value larger than we can handle */
       
  1322         wp_data->error_class = ERROR_CLASS_PROPERTY;
       
  1323         wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
       
  1324         return false;
       
  1325     }
       
  1326     if ((wp_data->object_property != PROP_OBJECT_LIST) &&
       
  1327         (wp_data->array_index != BACNET_ARRAY_ALL)) {
       
  1328         /*  only array properties can have array options */
       
  1329         wp_data->error_class = ERROR_CLASS_PROPERTY;
       
  1330         wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
       
  1331         return false;
       
  1332     }
       
  1333     /* FIXME: len < application_data_len: more data? */
       
  1334     switch (wp_data->object_property) {
       
  1335         case PROP_OBJECT_IDENTIFIER:
       
  1336             status =
       
  1337                 WPValidateArgType(&value, BACNET_APPLICATION_TAG_OBJECT_ID,
       
  1338                 &wp_data->error_class, &wp_data->error_code);
       
  1339             if (status) {
       
  1340                 if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
       
  1341                     (Device_Set_Object_Instance_Number(value.type.
       
  1342                             Object_Id.instance))) {
       
  1343                     /* FIXME: we could send an I-Am broadcast to let the world know */
       
  1344                 } else {
       
  1345                     status = false;
       
  1346                     wp_data->error_class = ERROR_CLASS_PROPERTY;
       
  1347                     wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
       
  1348                 }
       
  1349             }
       
  1350             break;
       
  1351         case PROP_NUMBER_OF_APDU_RETRIES:
       
  1352             status =
       
  1353                 WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
       
  1354                 &wp_data->error_class, &wp_data->error_code);
       
  1355             if (status) {
       
  1356                 /* FIXME: bounds check? */
       
  1357                 apdu_retries_set((uint8_t) value.type.Unsigned_Int);
       
  1358             }
       
  1359             break;
       
  1360         case PROP_APDU_TIMEOUT:
       
  1361             status =
       
  1362                 WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
       
  1363                 &wp_data->error_class, &wp_data->error_code);
       
  1364             if (status) {
       
  1365                 /* FIXME: bounds check? */
       
  1366                 apdu_timeout_set((uint16_t) value.type.Unsigned_Int);
       
  1367             }
       
  1368             break;
       
  1369         case PROP_VENDOR_IDENTIFIER:
       
  1370             status =
       
  1371                 WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
       
  1372                 &wp_data->error_class, &wp_data->error_code);
       
  1373             if (status) {
       
  1374                 /* FIXME: bounds check? */
       
  1375                 Device_Set_Vendor_Identifier((uint16_t) value.
       
  1376                     type.Unsigned_Int);
       
  1377             }
       
  1378             break;
       
  1379 //       case PROP_SYSTEM_STATUS:
       
  1380 //           status =
       
  1381 //               WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
       
  1382 //               &wp_data->error_class, &wp_data->error_code);
       
  1383 //           if (status) {
       
  1384 //               temp = Device_Set_System_Status((BACNET_DEVICE_STATUS)
       
  1385 //                   value.type.Enumerated, false);
       
  1386 //               if (temp != 0) {
       
  1387 //                   status = false;
       
  1388 //                   wp_data->error_class = ERROR_CLASS_PROPERTY;
       
  1389 //                   if (temp == -1) {
       
  1390 //                       wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
       
  1391 //                   } else {
       
  1392 //                       wp_data->error_code =
       
  1393 //                           ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
       
  1394 //                   }
       
  1395 //               }
       
  1396 //           }
       
  1397 //           break;
       
  1398         case PROP_OBJECT_NAME:
       
  1399             status =
       
  1400                 WPValidateString(&value,
       
  1401                 characterstring_capacity(&My_Object_Name), false,
       
  1402                 &wp_data->error_class, &wp_data->error_code);
       
  1403             if (status) {
       
  1404                 /* All the object names in a device must be unique */
       
  1405                 if (Device_Valid_Object_Name(&value.type.Character_String,
       
  1406                         &object_type, &object_instance)) {
       
  1407                     if ((object_type == wp_data->object_type) &&
       
  1408                         (object_instance == wp_data->object_instance)) {
       
  1409                         /* writing same name to same object */
       
  1410                         status = true;
       
  1411                     } else {
       
  1412                         status = false;
       
  1413                         wp_data->error_class = ERROR_CLASS_PROPERTY;
       
  1414                         wp_data->error_code = ERROR_CODE_DUPLICATE_NAME;
       
  1415                     }
       
  1416                 } else {
       
  1417                     Device_Set_Object_Name(&value.type.Character_String);
       
  1418                 }
       
  1419             }
       
  1420             break;
       
  1421         case PROP_LOCATION:
       
  1422             status =
       
  1423                 WPValidateString(&value, MAX_DEV_LOC_LEN, true,
       
  1424                 &wp_data->error_class, &wp_data->error_code);
       
  1425             if (status) {
       
  1426                 Device_Set_Location(characterstring_value(&value.
       
  1427                         type.Character_String),
       
  1428                     characterstring_length(&value.type.Character_String));
       
  1429             }
       
  1430             break;
       
  1431 
       
  1432         case PROP_DESCRIPTION:
       
  1433             status =
       
  1434                 WPValidateString(&value, MAX_DEV_DESC_LEN, true,
       
  1435                 &wp_data->error_class, &wp_data->error_code);
       
  1436             if (status) {
       
  1437                 Device_Set_Description(characterstring_value(&value.
       
  1438                         type.Character_String),
       
  1439                     characterstring_length(&value.type.Character_String));
       
  1440             }
       
  1441             break;
       
  1442         case PROP_MODEL_NAME:
       
  1443             status =
       
  1444                 WPValidateString(&value, MAX_DEV_MOD_LEN, true,
       
  1445                 &wp_data->error_class, &wp_data->error_code);
       
  1446             if (status) {
       
  1447                 Device_Set_Model_Name(characterstring_value(&value.
       
  1448                         type.Character_String),
       
  1449                     characterstring_length(&value.type.Character_String));
       
  1450             }
       
  1451             break;
       
  1452 
       
  1453         case PROP_OBJECT_TYPE:
       
  1454         case PROP_SYSTEM_STATUS:
       
  1455         case PROP_VENDOR_NAME:
       
  1456         case PROP_FIRMWARE_REVISION:
       
  1457         case PROP_APPLICATION_SOFTWARE_VERSION:
       
  1458         case PROP_LOCAL_TIME:
       
  1459         case PROP_UTC_OFFSET:
       
  1460         case PROP_LOCAL_DATE:
       
  1461         case PROP_DAYLIGHT_SAVINGS_STATUS:
       
  1462         case PROP_PROTOCOL_VERSION:
       
  1463         case PROP_PROTOCOL_REVISION:
       
  1464         case PROP_PROTOCOL_SERVICES_SUPPORTED:
       
  1465         case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
       
  1466         case PROP_OBJECT_LIST:
       
  1467         case PROP_MAX_APDU_LENGTH_ACCEPTED:
       
  1468         case PROP_SEGMENTATION_SUPPORTED:
       
  1469         case PROP_DEVICE_ADDRESS_BINDING:
       
  1470         case PROP_DATABASE_REVISION:
       
  1471 //      case PROP_PROPERTY_LIST:
       
  1472             wp_data->error_class = ERROR_CLASS_PROPERTY;
       
  1473             wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
       
  1474             break;
       
  1475         default:
       
  1476             wp_data->error_class = ERROR_CLASS_PROPERTY;
       
  1477             wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
       
  1478             break;
       
  1479     }
       
  1480 
       
  1481     return status;
       
  1482 }
       
  1483 
       
  1484 /** Looks up the requested Object and Property, and set the new Value in it,
       
  1485  *  if allowed.
       
  1486  * If the Object or Property can't be found, sets the error class and code.
       
  1487  *
       
  1488  * param: wp_data [in,out] Structure with the desired Object and Property info
       
  1489  *              and new Value on entry, and APDU message on return.
       
  1490  * return: True on success, else False if there is an error.
       
  1491  */
       
  1492 bool Device_Write_Property(
       
  1493     BACNET_WRITE_PROPERTY_DATA * wp_data)
       
  1494 {
       
  1495     bool status = false;        /* Ever the pessamist! */
       
  1496     struct object_functions *pObject = NULL;
       
  1497 
       
  1498     /* initialize the default return values */
       
  1499     wp_data->error_class = ERROR_CLASS_OBJECT;
       
  1500     wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
       
  1501     pObject = Device_Objects_Find_Functions(wp_data->object_type);
       
  1502     if (pObject != NULL) {
       
  1503         if (pObject->Object_Valid_Instance &&
       
  1504             pObject->Object_Valid_Instance(wp_data->object_instance)) {
       
  1505             if (pObject->Object_Write_Property) {
       
  1506                 status = pObject->Object_Write_Property(wp_data);
       
  1507             } else {
       
  1508                 wp_data->error_class = ERROR_CLASS_PROPERTY;
       
  1509                 wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
       
  1510             }
       
  1511         } else {
       
  1512             wp_data->error_class = ERROR_CLASS_OBJECT;
       
  1513             wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
       
  1514         }
       
  1515     } else {
       
  1516         wp_data->error_class = ERROR_CLASS_OBJECT;
       
  1517         wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
       
  1518     }
       
  1519 
       
  1520     return (status);
       
  1521 }
       
  1522 
       
  1523 /** Looks up the requested Object, and fills the Property Value list.
       
  1524  * If the Object or Property can't be found, returns false.
       
  1525  * param: [in] The object type to be looked up.
       
  1526  * param: [in] The object instance number to be looked up.
       
  1527  * param: [out] The value list
       
  1528  * return: True if the object instance supports this feature and value changed.
       
  1529  */
       
  1530 bool Device_Encode_Value_List(
       
  1531     BACNET_OBJECT_TYPE object_type,
       
  1532     uint32_t object_instance,
       
  1533     BACNET_PROPERTY_VALUE * value_list)
       
  1534 {
       
  1535     bool status = false;        /* Ever the pessamist! */
       
  1536     struct object_functions *pObject = NULL;
       
  1537 
       
  1538     pObject = Device_Objects_Find_Functions(object_type);
       
  1539     if (pObject != NULL) {
       
  1540         if (pObject->Object_Valid_Instance &&
       
  1541             pObject->Object_Valid_Instance(object_instance)) {
       
  1542             if (pObject->Object_Value_List) {
       
  1543                 status =
       
  1544                     pObject->Object_Value_List(object_instance, value_list);
       
  1545             }
       
  1546         }
       
  1547     }
       
  1548 
       
  1549     return (status);
       
  1550 }
       
  1551 
       
  1552 /** Checks the COV flag in the requested Object
       
  1553  * param: [in] The object type to be looked up.
       
  1554  * param: [in] The object instance to be looked up.
       
  1555  * return: True if the COV flag is set
       
  1556  */
       
  1557 bool Device_COV(
       
  1558     BACNET_OBJECT_TYPE object_type,
       
  1559     uint32_t object_instance)
       
  1560 {
       
  1561     bool status = false;        /* Ever the pessamist! */
       
  1562     struct object_functions *pObject = NULL;
       
  1563 
       
  1564     pObject = Device_Objects_Find_Functions(object_type);
       
  1565     if (pObject != NULL) {
       
  1566         if (pObject->Object_Valid_Instance &&
       
  1567             pObject->Object_Valid_Instance(object_instance)) {
       
  1568             if (pObject->Object_COV) {
       
  1569                 status = pObject->Object_COV(object_instance);
       
  1570             }
       
  1571         }
       
  1572     }
       
  1573 
       
  1574     return (status);
       
  1575 }
       
  1576 
       
  1577 /** Clears the COV flag in the requested Object
       
  1578  * param: [in] The object type to be looked up.
       
  1579  * param: [in] The object instance to be looked up.
       
  1580  */
       
  1581 void Device_COV_Clear(
       
  1582     BACNET_OBJECT_TYPE object_type,
       
  1583     uint32_t object_instance)
       
  1584 {
       
  1585     struct object_functions *pObject = NULL;
       
  1586 
       
  1587     pObject = Device_Objects_Find_Functions(object_type);
       
  1588     if (pObject != NULL) {
       
  1589         if (pObject->Object_Valid_Instance &&
       
  1590             pObject->Object_Valid_Instance(object_instance)) {
       
  1591             if (pObject->Object_COV_Clear) {
       
  1592                 pObject->Object_COV_Clear(object_instance);
       
  1593             }
       
  1594         }
       
  1595     }
       
  1596 }
       
  1597 
       
  1598 
       
  1599 /** Looks up the requested Object to see if the functionality is supported.
       
  1600  * param: [in] The object type to be looked up.
       
  1601  * return: True if the object instance supports this feature.
       
  1602  */
       
  1603 bool Device_Value_List_Supported(
       
  1604     BACNET_OBJECT_TYPE object_type)
       
  1605 {
       
  1606     bool status = false;        /* Ever the pessamist! */
       
  1607     struct object_functions *pObject = NULL;
       
  1608 
       
  1609     pObject = Device_Objects_Find_Functions(object_type);
       
  1610     if (pObject != NULL) {
       
  1611         if (pObject->Object_Value_List) {
       
  1612             status = true;
       
  1613         }
       
  1614     }
       
  1615 
       
  1616     return (status);
       
  1617 }
       
  1618 
       
  1619 /** Initialize the Device Object.
       
  1620  Initialize the group of object helper functions for any supported Object.
       
  1621  Initialize each of the Device Object child Object instances.
       
  1622  * param: The BACnet Object Name of the bacnet server
       
  1623  */
       
  1624 void Device_Init(
       
  1625     const char * Device_Object_Name)
       
  1626 {
       
  1627     struct object_functions *pObject = NULL;
       
  1628 
       
  1629     /* initialize the Device_Properties_List array */
       
  1630     int len = 0;
       
  1631     len += BACnet_Init_Properties_List(Device_Properties_List + len,
       
  1632                                        Device_Properties_Required);
       
  1633     len += BACnet_Init_Properties_List(Device_Properties_List + len,
       
  1634                                        Device_Properties_Optional);
       
  1635     len += BACnet_Init_Properties_List(Device_Properties_List + len,
       
  1636                                        Device_Properties_Proprietary);
       
  1637 
       
  1638     characterstring_init_ansi(&My_Object_Name, Device_Object_Name);
       
  1639     Object_Table = &My_Object_Table[0]; // sets glogbal variable!
       
  1640     pObject = Object_Table;
       
  1641     while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
       
  1642         if (pObject->Object_Init) {
       
  1643             pObject->Object_Init();
       
  1644         }
       
  1645         pObject++;
       
  1646     }
       
  1647 }
       
  1648 
       
  1649 bool DeviceGetRRInfo(
       
  1650     BACNET_READ_RANGE_DATA * pRequest,  /* Info on the request */
       
  1651     RR_PROP_INFO * pInfo)
       
  1652 {       /* Where to put the response */
       
  1653     bool status = false;        /* return value */
       
  1654 
       
  1655     switch (pRequest->object_property) {
       
  1656         case PROP_VT_CLASSES_SUPPORTED:
       
  1657         case PROP_ACTIVE_VT_SESSIONS:
       
  1658         case PROP_LIST_OF_SESSION_KEYS:
       
  1659         case PROP_TIME_SYNCHRONIZATION_RECIPIENTS:
       
  1660         case PROP_MANUAL_SLAVE_ADDRESS_BINDING:
       
  1661         case PROP_SLAVE_ADDRESS_BINDING:
       
  1662         case PROP_RESTART_NOTIFICATION_RECIPIENTS:
       
  1663         case PROP_UTC_TIME_SYNCHRONIZATION_RECIPIENTS:
       
  1664             pInfo->RequestTypes = RR_BY_POSITION;
       
  1665             pRequest->error_class = ERROR_CLASS_PROPERTY;
       
  1666             pRequest->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
       
  1667             break;
       
  1668 
       
  1669         case PROP_DEVICE_ADDRESS_BINDING:
       
  1670             pInfo->RequestTypes = RR_BY_POSITION;
       
  1671             pInfo->Handler = rr_address_list_encode;
       
  1672             status = true;
       
  1673             break;
       
  1674 
       
  1675         default:
       
  1676             pRequest->error_class = ERROR_CLASS_SERVICES;
       
  1677             pRequest->error_code = ERROR_CODE_PROPERTY_IS_NOT_A_LIST;
       
  1678             break;
       
  1679     }
       
  1680 
       
  1681     return status;
       
  1682 }
       
  1683 
       
  1684 
       
  1685