Removed the object-table function macros from each demo object header file since it was very difficult to maintain when new functions are added. Added device-client.c file which is a small device object just for simple clients. Updated most Makefiles of client demo applications to utilize device-client.c file.
Added two device object table functions for COV support. Corrected demo COV handler interaction with TSM, COV flags, and multiple subscriptions for the same object.
This commit is contained in:
@@ -8,7 +8,8 @@ TARGET = bacdcc
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -51,13 +51,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -123,7 +116,7 @@ void MyDeviceCommunicationControlSimpleAckHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ BORLAND_DIR_Not_Defined:
|
|||||||
!endif
|
!endif
|
||||||
|
|
||||||
# target
|
# target
|
||||||
PRODUCT = bacdcc
|
PRODUCT = bacdcc ..\handler\device-client.c
|
||||||
PRODUCT_EXE = $(PRODUCT).exe
|
PRODUCT_EXE = $(PRODUCT).exe
|
||||||
|
|
||||||
# tools
|
# tools
|
||||||
@@ -42,7 +42,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
<Unit filename="main.c">
|
<Unit filename="main.c">
|
||||||
<Option compilerVar="CC" />
|
<Option compilerVar="CC" />
|
||||||
</Unit>
|
</Unit>
|
||||||
|
<Unit filename="..\object\device-client.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
<Extensions>
|
<Extensions>
|
||||||
<code_completion />
|
<code_completion />
|
||||||
<envvars />
|
<envvars />
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
*
|
*
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
|
|
||||||
/** @file epics/bacepics.c Command line tool to build a full VTS3 EPICS file,
|
/** @file epics/bacepics.c Command line tool to build a full VTS3 EPICS file,
|
||||||
* including the heading information. */
|
* including the heading information. */
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -69,13 +69,6 @@
|
|||||||
* 3) Postpends the tail information to complete the EPICS file.
|
* 3) Postpends the tail information to complete the EPICS file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -299,7 +292,7 @@ void MyReadPropertyMultipleAckHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
|
|
||||||
#if BAC_ROUTING
|
#if BAC_ROUTING
|
||||||
uint32_t Object_Instance;
|
uint32_t Object_Instance;
|
||||||
@@ -335,12 +328,12 @@ static void Init_Service_Handlers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Determine if this is a writable property, and, if so,
|
/** Determine if this is a writable property, and, if so,
|
||||||
* note that in the EPICS output.
|
* note that in the EPICS output.
|
||||||
* This function may need a lot of customization for different implementations;
|
* This function may need a lot of customization for different implementations;
|
||||||
* but as a starting point, take the Device object-instance and -name as writable.
|
* but as a starting point, take the Device object-instance and -name as writable.
|
||||||
* For the EPICS output to VTS3, printing 'w' after the property is sufficient,
|
* For the EPICS output to VTS3, printing 'w' after the property is sufficient,
|
||||||
* but to aid readability for human eyes, printing as "Writable".
|
* but to aid readability for human eyes, printing as "Writable".
|
||||||
*
|
*
|
||||||
* @param object_type [in] The BACnet Object type of this object.
|
* @param object_type [in] The BACnet Object type of this object.
|
||||||
* @note object_instance [in] The ID number for this object.
|
* @note object_instance [in] The ID number for this object.
|
||||||
@@ -348,7 +341,7 @@ static void Init_Service_Handlers(
|
|||||||
* Value, and Error information.
|
* Value, and Error information.
|
||||||
*/
|
*/
|
||||||
void CheckIsWritableProperty(
|
void CheckIsWritableProperty(
|
||||||
BACNET_OBJECT_TYPE object_type,
|
BACNET_OBJECT_TYPE object_type,
|
||||||
/* uint32_t object_instance, */
|
/* uint32_t object_instance, */
|
||||||
BACNET_PROPERTY_REFERENCE * rpm_property)
|
BACNET_PROPERTY_REFERENCE * rpm_property)
|
||||||
{
|
{
|
||||||
@@ -639,11 +632,11 @@ void PrintReadPropertyData(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* First, if this is a date type, it needs a different format
|
/* First, if this is a date type, it needs a different format
|
||||||
* for VTS, so pretty print it. */
|
* for VTS, so pretty print it. */
|
||||||
if (ShowValues && (object_value.value->tag == BACNET_APPLICATION_TAG_DATE))
|
if (ShowValues && (object_value.value->tag == BACNET_APPLICATION_TAG_DATE))
|
||||||
{
|
{
|
||||||
/* This would be PROP_LOCAL_DATE, or OBJECT_DATETIME_VALUE,
|
/* This would be PROP_LOCAL_DATE, or OBJECT_DATETIME_VALUE,
|
||||||
* or OBJECT_DATE_VALUE */
|
* or OBJECT_DATE_VALUE */
|
||||||
PrettyPrintPropertyValue(stdout, &object_value);
|
PrettyPrintPropertyValue(stdout, &object_value);
|
||||||
} else {
|
} else {
|
||||||
@@ -684,7 +677,7 @@ void PrintReadPropertyData(
|
|||||||
/* Closing brace for this multi-valued array */
|
/* Closing brace for this multi-valued array */
|
||||||
fprintf(stdout, " }");
|
fprintf(stdout, " }");
|
||||||
}
|
}
|
||||||
CheckIsWritableProperty(object_type, /* object_instance, */
|
CheckIsWritableProperty(object_type, /* object_instance, */
|
||||||
rpm_property);
|
rpm_property);
|
||||||
fprintf(stdout, "\r\n");
|
fprintf(stdout, "\r\n");
|
||||||
}
|
}
|
||||||
@@ -714,7 +707,7 @@ void Print_Property_Identifier(
|
|||||||
|
|
||||||
/** Build a list of properties to request with RPM.
|
/** Build a list of properties to request with RPM.
|
||||||
* @param rpm_object [out] The structure holding our linked list of properties to request.
|
* @param rpm_object [out] The structure holding our linked list of properties to request.
|
||||||
* @param propList [in] Simple list of properties (ptr to array), terminated with -1
|
* @param propList [in] Simple list of properties (ptr to array), terminated with -1
|
||||||
*/
|
*/
|
||||||
void BuildPropRequest( BACNET_READ_ACCESS_DATA *rpm_object, int32_t *propList )
|
void BuildPropRequest( BACNET_READ_ACCESS_DATA *rpm_object, int32_t *propList )
|
||||||
{
|
{
|
||||||
@@ -870,8 +863,8 @@ EPICS_STATES ProcessRPMData(
|
|||||||
free(old_value);
|
free(old_value);
|
||||||
}
|
}
|
||||||
} else if ( myState == GET_HEADING_RESPONSE ) {
|
} else if ( myState == GET_HEADING_RESPONSE ) {
|
||||||
InitIdValues[i++] = rpm_property->value;
|
InitIdValues[i++] = rpm_property->value;
|
||||||
/* copy this pointer.
|
/* copy this pointer.
|
||||||
* On error, the pointer will be null
|
* On error, the pointer will be null
|
||||||
* We won't free these values*/
|
* We won't free these values*/
|
||||||
} else {
|
} else {
|
||||||
@@ -892,7 +885,7 @@ EPICS_STATES ProcessRPMData(
|
|||||||
|
|
||||||
/* Now determine the next state */
|
/* Now determine the next state */
|
||||||
if ( myState == GET_HEADING_RESPONSE )
|
if ( myState == GET_HEADING_RESPONSE )
|
||||||
nextState = PRINT_HEADING;
|
nextState = PRINT_HEADING;
|
||||||
/* press ahead with or without the data */
|
/* press ahead with or without the data */
|
||||||
else if (bSuccess && (myState == GET_ALL_RESPONSE))
|
else if (bSuccess && (myState == GET_ALL_RESPONSE))
|
||||||
nextState = NEXT_OBJECT;
|
nextState = NEXT_OBJECT;
|
||||||
@@ -1038,7 +1031,7 @@ void PrintHeading( )
|
|||||||
char *relation = "for"; /* Text for Gateways */
|
char *relation = "for"; /* Text for Gateways */
|
||||||
if ( Target_Address.net != 0 )
|
if ( Target_Address.net != 0 )
|
||||||
relation = "provided by"; /* Text for child routed devices */
|
relation = "provided by"; /* Text for child routed devices */
|
||||||
|
|
||||||
printf("PICS 0\r\n");
|
printf("PICS 0\r\n");
|
||||||
printf("BACnet Protocol Implementation Conformance Statement\r\n\r\n");
|
printf("BACnet Protocol Implementation Conformance Statement\r\n\r\n");
|
||||||
|
|
||||||
@@ -1046,14 +1039,14 @@ void PrintHeading( )
|
|||||||
printf("-- BACnet/IP Interface for BACnet-stack Devices\r\n");
|
printf("-- BACnet/IP Interface for BACnet-stack Devices\r\n");
|
||||||
printf("-- http://sourceforge.net/projects/bacnet/ \r\n");
|
printf("-- http://sourceforge.net/projects/bacnet/ \r\n");
|
||||||
printf("-- \r\n-- \r\n\r\n");
|
printf("-- \r\n-- \r\n\r\n");
|
||||||
/* InitIdValues , , , */
|
/* InitIdValues , , , */
|
||||||
|
|
||||||
value = InitIdValues[INIT_VENDOR_NAME];
|
value = InitIdValues[INIT_VENDOR_NAME];
|
||||||
if ( value != NULL )
|
if ( value != NULL )
|
||||||
printf("Vendor Name: \"%s\"\r\n", characterstring_value( &value->type.Character_String) );
|
printf("Vendor Name: \"%s\"\r\n", characterstring_value( &value->type.Character_String) );
|
||||||
else
|
else
|
||||||
printf("Vendor Name: \"bacnet-stack\"\r\n");
|
printf("Vendor Name: \"bacnet-stack\"\r\n");
|
||||||
|
|
||||||
value = InitIdValues[INIT_MODEL_NAME];
|
value = InitIdValues[INIT_MODEL_NAME];
|
||||||
/* Best we can do with Product Name and Model Number is use the same text */
|
/* Best we can do with Product Name and Model Number is use the same text */
|
||||||
if ( value != NULL ) {
|
if ( value != NULL ) {
|
||||||
@@ -1079,11 +1072,11 @@ void PrintHeading( )
|
|||||||
printf(" DM-DOB-B\r\n");
|
printf(" DM-DOB-B\r\n");
|
||||||
printf(" DM-DCC-B\r\n");
|
printf(" DM-DCC-B\r\n");
|
||||||
printf(" DM-RD-B\r\n");
|
printf(" DM-RD-B\r\n");
|
||||||
#ifdef BAC_ROUTING
|
#ifdef BAC_ROUTING
|
||||||
/* Next line only for the gateway (ie, if not addressing a subNet) */
|
/* Next line only for the gateway (ie, if not addressing a subNet) */
|
||||||
if ( Target_Address.net == 0 )
|
if ( Target_Address.net == 0 )
|
||||||
printf(" NM-RC-B\r\n");
|
printf(" NM-RC-B\r\n");
|
||||||
#endif
|
#endif
|
||||||
printf("}\r\n\r\n");
|
printf("}\r\n\r\n");
|
||||||
/* You might add some of:
|
/* You might add some of:
|
||||||
* -- DS-COV-A DS-COV-B
|
* -- DS-COV-A DS-COV-B
|
||||||
@@ -1104,7 +1097,7 @@ void PrintHeading( )
|
|||||||
printf(" Who-Is Initiate Execute\r\n");
|
printf(" Who-Is Initiate Execute\r\n");
|
||||||
printf(" I-Am Initiate\r\n");
|
printf(" I-Am Initiate\r\n");
|
||||||
printf(" ReinitializeDevice Execute\r\n");
|
printf(" ReinitializeDevice Execute\r\n");
|
||||||
#ifdef BAC_ROUTING
|
#ifdef BAC_ROUTING
|
||||||
if ( Target_Address.net == 0 )
|
if ( Target_Address.net == 0 )
|
||||||
{
|
{
|
||||||
printf(" -- Note: The following Routing Services are Supported:\r\n");
|
printf(" -- Note: The following Routing Services are Supported:\r\n");
|
||||||
@@ -1113,7 +1106,7 @@ void PrintHeading( )
|
|||||||
printf(" -- Initialize-Routing-Table Execute\r\n");
|
printf(" -- Initialize-Routing-Table Execute\r\n");
|
||||||
printf(" -- Initialize-Routing-Table-Ack Initiate\r\n");
|
printf(" -- Initialize-Routing-Table-Ack Initiate\r\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
printf("}\r\n\r\n");
|
printf("}\r\n\r\n");
|
||||||
/* You might want to add some of:
|
/* You might want to add some of:
|
||||||
* -- AcknowledgeAlarm Initiate Execute
|
* -- AcknowledgeAlarm Initiate Execute
|
||||||
@@ -1132,10 +1125,10 @@ void PrintHeading( )
|
|||||||
printf("Standard Object-Types Supported:\r\n");
|
printf("Standard Object-Types Supported:\r\n");
|
||||||
printf("{\r\n");
|
printf("{\r\n");
|
||||||
value = InitIdValues[INIT_OBJ_TYPES];
|
value = InitIdValues[INIT_OBJ_TYPES];
|
||||||
/* We have to process this bit string and determine which Object Types we have,
|
/* We have to process this bit string and determine which Object Types we have,
|
||||||
* and show them
|
* and show them
|
||||||
*/
|
*/
|
||||||
if ( ( value != NULL ) && (value->tag == BACNET_APPLICATION_TAG_BIT_STRING) )
|
if ( ( value != NULL ) && (value->tag == BACNET_APPLICATION_TAG_BIT_STRING) )
|
||||||
{
|
{
|
||||||
int i, len = bitstring_bits_used(&value->type.Bit_String);
|
int i, len = bitstring_bits_used(&value->type.Bit_String);
|
||||||
for ( i = 0; i < len; i++) {
|
for ( i = 0; i < len; i++) {
|
||||||
@@ -1148,8 +1141,8 @@ void PrintHeading( )
|
|||||||
printf(" Binary Input\r\n");
|
printf(" Binary Input\r\n");
|
||||||
printf(" Binary Value\r\n");
|
printf(" Binary Value\r\n");
|
||||||
printf(" Device\r\n");
|
printf(" Device\r\n");
|
||||||
printf(" Multi-state Input\r\n");
|
printf(" Multi-state Input\r\n");
|
||||||
printf(" Multi-state Value\r\n");
|
printf(" Multi-state Value\r\n");
|
||||||
printf(" Structured View\r\n");
|
printf(" Structured View\r\n");
|
||||||
printf(" Characterstring Value\r\n");
|
printf(" Characterstring Value\r\n");
|
||||||
printf(" Datetime Value\r\n");
|
printf(" Datetime Value\r\n");
|
||||||
@@ -1163,7 +1156,7 @@ void PrintHeading( )
|
|||||||
* -- Multi-state Output
|
* -- Multi-state Output
|
||||||
* -- Trend Log Createable Deleteable
|
* -- Trend Log Createable Deleteable
|
||||||
* -- Load Control
|
* -- Load Control
|
||||||
* -- Bitstring Value
|
* -- Bitstring Value
|
||||||
* -- Date Pattern Value
|
* -- Date Pattern Value
|
||||||
* -- Date Value
|
* -- Date Value
|
||||||
* -- Datetime Pattern Value
|
* -- Datetime Pattern Value
|
||||||
@@ -1172,7 +1165,7 @@ void PrintHeading( )
|
|||||||
* -- Time Pattern Value
|
* -- Time Pattern Value
|
||||||
* -- Time Value
|
* -- Time Value
|
||||||
*/
|
*/
|
||||||
|
|
||||||
printf("Data Link Layer Option:\r\n");
|
printf("Data Link Layer Option:\r\n");
|
||||||
printf("{\r\n");
|
printf("{\r\n");
|
||||||
printf(" BACnet/IP, 'DIX' Ethernet\r\n");
|
printf(" BACnet/IP, 'DIX' Ethernet\r\n");
|
||||||
@@ -1187,8 +1180,8 @@ void PrintHeading( )
|
|||||||
printf("{\r\n");
|
printf("{\r\n");
|
||||||
printf(" Maximum APDU size in octets: 1476\r\n");
|
printf(" Maximum APDU size in octets: 1476\r\n");
|
||||||
printf("}\r\n\r\n");
|
printf("}\r\n\r\n");
|
||||||
|
|
||||||
printf("List of Objects in Test Device:\r\n");
|
printf("List of Objects in Test Device:\r\n");
|
||||||
/* Print Opening brace, then kick off the Device Object */
|
/* Print Opening brace, then kick off the Device Object */
|
||||||
printf("{\r\n");
|
printf("{\r\n");
|
||||||
printf(" {\r\n"); /* And opening brace for the first object */
|
printf(" {\r\n"); /* And opening brace for the first object */
|
||||||
@@ -1342,7 +1335,7 @@ int main(
|
|||||||
myState = GET_HEADING_INFO;
|
myState = GET_HEADING_INFO;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GET_HEADING_INFO:
|
case GET_HEADING_INFO:
|
||||||
last_seconds = current_seconds;
|
last_seconds = current_seconds;
|
||||||
StartNextObject(rpm_object, &myObject);
|
StartNextObject(rpm_object, &myObject);
|
||||||
@@ -1414,7 +1407,7 @@ int main(
|
|||||||
elapsed_seconds = 0;
|
elapsed_seconds = 0;
|
||||||
invoke_id = 0;
|
invoke_id = 0;
|
||||||
if ( myState == GET_HEADING_RESPONSE )
|
if ( myState == GET_HEADING_RESPONSE )
|
||||||
myState = PRINT_HEADING;
|
myState = PRINT_HEADING;
|
||||||
/* just press ahead without the data */
|
/* just press ahead without the data */
|
||||||
else if (Error_Detected) {
|
else if (Error_Detected) {
|
||||||
/* The normal case for Device Object */
|
/* The normal case for Device Object */
|
||||||
@@ -1442,7 +1435,7 @@ int main(
|
|||||||
invoke_id = 0;
|
invoke_id = 0;
|
||||||
elapsed_seconds = 0;
|
elapsed_seconds = 0;
|
||||||
if ( myState == GET_HEADING_RESPONSE )
|
if ( myState == GET_HEADING_RESPONSE )
|
||||||
myState = PRINT_HEADING;
|
myState = PRINT_HEADING;
|
||||||
/* just press ahead without the data */
|
/* just press ahead without the data */
|
||||||
else
|
else
|
||||||
myState = GET_ALL_REQUEST; /* Let's try again */
|
myState = GET_ALL_REQUEST; /* Let's try again */
|
||||||
@@ -1451,7 +1444,7 @@ int main(
|
|||||||
elapsed_seconds = 0;
|
elapsed_seconds = 0;
|
||||||
invoke_id = 0;
|
invoke_id = 0;
|
||||||
if ( myState == GET_HEADING_RESPONSE )
|
if ( myState == GET_HEADING_RESPONSE )
|
||||||
myState = PRINT_HEADING;
|
myState = PRINT_HEADING;
|
||||||
/* just press ahead without the data */
|
/* just press ahead without the data */
|
||||||
else
|
else
|
||||||
myState = NEXT_OBJECT; /* Give up and move on to the next. */
|
myState = NEXT_OBJECT; /* Give up and move on to the next. */
|
||||||
|
|||||||
@@ -59,20 +59,6 @@
|
|||||||
#ifdef BACNET_TEST_VMAC
|
#ifdef BACNET_TEST_VMAC
|
||||||
#include "vmac.h"
|
#include "vmac.h"
|
||||||
#endif
|
#endif
|
||||||
#include "ai.h"
|
|
||||||
#include "ao.h"
|
|
||||||
#include "av.h"
|
|
||||||
#include "bi.h"
|
|
||||||
#include "bo.h"
|
|
||||||
#include "bv.h"
|
|
||||||
#include "lc.h"
|
|
||||||
#include "lsp.h"
|
|
||||||
#include "mso.h"
|
|
||||||
#include "ms-input.h"
|
|
||||||
#include "trendlog.h"
|
|
||||||
#if defined(BACFILE)
|
|
||||||
#include "bacfile.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** @file gateway/main.c Example virtual gateway application using the BACnet Stack. */
|
/** @file gateway/main.c Example virtual gateway application using the BACnet Stack. */
|
||||||
|
|
||||||
@@ -139,10 +125,10 @@ static void Init_Service_Handlers(
|
|||||||
Routing_Device_Init(first_object_instance);
|
Routing_Device_Init(first_object_instance);
|
||||||
|
|
||||||
/* we need to handle who-is to support dynamic device binding
|
/* we need to handle who-is to support dynamic device binding
|
||||||
* For the gateway, we will use the unicast variety so we can
|
* For the gateway, we will use the unicast variety so we can
|
||||||
* get back through switches to different subnets.
|
* get back through switches to different subnets.
|
||||||
* Don't need the routed versions, since the npdu handler calls
|
* Don't need the routed versions, since the npdu handler calls
|
||||||
* each device in turn.
|
* each device in turn.
|
||||||
*/
|
*/
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
|
||||||
handler_who_is_unicast);
|
handler_who_is_unicast);
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ typedef struct BACnet_COV_Subscription {
|
|||||||
uint32_t subscriberProcessIdentifier;
|
uint32_t subscriberProcessIdentifier;
|
||||||
BACNET_OBJECT_ID monitoredObjectIdentifier;
|
BACNET_OBJECT_ID monitoredObjectIdentifier;
|
||||||
bool issueConfirmedNotifications; /* optional */
|
bool issueConfirmedNotifications; /* optional */
|
||||||
|
uint8_t invokeID; /* for confirmed COV */
|
||||||
uint32_t lifetime; /* optional */
|
uint32_t lifetime; /* optional */
|
||||||
bool send_requested;
|
bool send_requested;
|
||||||
} BACNET_COV_SUBSCRIPTION;
|
} BACNET_COV_SUBSCRIPTION;
|
||||||
@@ -223,6 +224,7 @@ void handler_cov_init(
|
|||||||
OBJECT_ANALOG_INPUT;
|
OBJECT_ANALOG_INPUT;
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance = 0;
|
COV_Subscriptions[index].monitoredObjectIdentifier.instance = 0;
|
||||||
COV_Subscriptions[index].issueConfirmedNotifications = false;
|
COV_Subscriptions[index].issueConfirmedNotifications = false;
|
||||||
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
COV_Subscriptions[index].lifetime = 0;
|
COV_Subscriptions[index].lifetime = 0;
|
||||||
COV_Subscriptions[index].send_requested = false;
|
COV_Subscriptions[index].send_requested = false;
|
||||||
}
|
}
|
||||||
@@ -261,6 +263,10 @@ static bool cov_list_subscribe(
|
|||||||
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
||||||
COV_Subscriptions[index].send_requested = true;
|
COV_Subscriptions[index].send_requested = true;
|
||||||
}
|
}
|
||||||
|
if (COV_Subscriptions[index].invokeID) {
|
||||||
|
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
||||||
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -283,6 +289,7 @@ static bool cov_list_subscribe(
|
|||||||
cov_data->subscriberProcessIdentifier;
|
cov_data->subscriberProcessIdentifier;
|
||||||
COV_Subscriptions[index].issueConfirmedNotifications =
|
COV_Subscriptions[index].issueConfirmedNotifications =
|
||||||
cov_data->issueConfirmedNotifications;
|
cov_data->issueConfirmedNotifications;
|
||||||
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
COV_Subscriptions[index].lifetime = cov_data->lifetime;
|
||||||
COV_Subscriptions[index].send_requested = true;
|
COV_Subscriptions[index].send_requested = true;
|
||||||
} else if (!existing_entry) {
|
} else if (!existing_entry) {
|
||||||
@@ -335,6 +342,7 @@ static bool cov_send_request(
|
|||||||
if (cov_subscription->issueConfirmedNotifications) {
|
if (cov_subscription->issueConfirmedNotifications) {
|
||||||
invoke_id = tsm_next_free_invokeID();
|
invoke_id = tsm_next_free_invokeID();
|
||||||
if (invoke_id) {
|
if (invoke_id) {
|
||||||
|
cov_subscription->invokeID = invoke_id;
|
||||||
len =
|
len =
|
||||||
ccov_notify_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
ccov_notify_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||||
invoke_id, &cov_data);
|
invoke_id, &cov_data);
|
||||||
@@ -385,19 +393,13 @@ static bool cov_send_request(
|
|||||||
*
|
*
|
||||||
* @param elapsed_seconds [in] How many seconds have elapsed since last called.
|
* @param elapsed_seconds [in] How many seconds have elapsed since last called.
|
||||||
*/
|
*/
|
||||||
void handler_cov_task(
|
void handler_cov_timer_seconds(
|
||||||
uint32_t elapsed_seconds)
|
uint32_t elapsed_seconds)
|
||||||
{
|
{
|
||||||
int index = 0, index2 = 0;
|
int index = 0;
|
||||||
uint32_t lifetime_seconds = 0;
|
uint32_t lifetime_seconds = 0;
|
||||||
uint16_t object_type = 0, object_type2 = 0;
|
|
||||||
uint32_t object_instance = 0, object_instance2 = 0;
|
|
||||||
bool status = false;
|
|
||||||
BACNET_PROPERTY_VALUE value_list[2];
|
|
||||||
|
|
||||||
value_list[0].next = &value_list[1];
|
/* handle the subscription timeouts */
|
||||||
value_list[1].next = NULL;
|
|
||||||
/* existing? - match Object ID and Process ID */
|
|
||||||
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
if (COV_Subscriptions[index].valid) {
|
if (COV_Subscriptions[index].valid) {
|
||||||
/* handle timeouts */
|
/* handle timeouts */
|
||||||
@@ -413,44 +415,102 @@ void handler_cov_task(
|
|||||||
}
|
}
|
||||||
if (COV_Subscriptions[index].lifetime == 0) {
|
if (COV_Subscriptions[index].lifetime == 0) {
|
||||||
COV_Subscriptions[index].valid = false;
|
COV_Subscriptions[index].valid = false;
|
||||||
|
if (COV_Subscriptions[index].issueConfirmedNotifications) {
|
||||||
|
if (COV_Subscriptions[index].invokeID) {
|
||||||
|
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
||||||
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* handle COV notifications */
|
}
|
||||||
object_type =
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handler_cov_task(void)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
BACNET_OBJECT_TYPE object_type = MAX_BACNET_OBJECT_TYPE;
|
||||||
|
uint32_t object_instance = 0;
|
||||||
|
bool status = false;
|
||||||
|
BACNET_PROPERTY_VALUE value_list[2];
|
||||||
|
|
||||||
|
/* configure the linked list for the two properties */
|
||||||
|
value_list[0].next = &value_list[1];
|
||||||
|
value_list[1].next = NULL;
|
||||||
|
/* mark any subscriptions where the value has changed */
|
||||||
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
|
if (COV_Subscriptions[index].valid) {
|
||||||
|
object_type = (BACNET_OBJECT_TYPE)
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
||||||
object_instance =
|
object_instance =
|
||||||
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
||||||
status =
|
status = Device_COV(object_type, object_instance);
|
||||||
Device_Encode_Value_List(object_type, object_instance,
|
|
||||||
&value_list[0]);
|
|
||||||
if (status) {
|
if (status) {
|
||||||
COV_Subscriptions[index].send_requested = true;
|
COV_Subscriptions[index].send_requested = true;
|
||||||
}
|
}
|
||||||
if (COV_Subscriptions[index].send_requested) {
|
}
|
||||||
cov_send_request(&COV_Subscriptions[index], &value_list[0]);
|
}
|
||||||
COV_Subscriptions[index].send_requested = false;
|
/* clear the COV flag after checking all subscriptions (dup objects) */
|
||||||
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
|
if (COV_Subscriptions[index].valid) {
|
||||||
|
object_type = (BACNET_OBJECT_TYPE)
|
||||||
|
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
||||||
|
object_instance =
|
||||||
|
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
||||||
|
status = Device_COV(object_type, object_instance);
|
||||||
|
if (status) {
|
||||||
|
Device_COV_Clear(object_type, object_instance);
|
||||||
}
|
}
|
||||||
if (status && ((index + 1) < MAX_COV_SUBCRIPTIONS)) {
|
}
|
||||||
/* if more than one subscription for this object instance */
|
}
|
||||||
for (index2 = index + 1; index2 < MAX_COV_SUBCRIPTIONS;
|
/* confirmed notification house keeping */
|
||||||
index2++) {
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
object_type2 =
|
if (COV_Subscriptions[index].valid) {
|
||||||
COV_Subscriptions[index2].monitoredObjectIdentifier.
|
if (COV_Subscriptions[index].issueConfirmedNotifications) {
|
||||||
type;
|
if (COV_Subscriptions[index].invokeID) {
|
||||||
object_instance2 =
|
if (tsm_invoke_id_free(COV_Subscriptions[index].invokeID)) {
|
||||||
COV_Subscriptions[index2].monitoredObjectIdentifier.
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
instance;
|
} else if (tsm_invoke_id_failed(
|
||||||
if ((COV_Subscriptions[index].lifetime) &&
|
COV_Subscriptions[index].invokeID)) {
|
||||||
(COV_Subscriptions[index].valid) &&
|
tsm_free_invoke_id(COV_Subscriptions[index].invokeID);
|
||||||
(object_type == object_type2) &&
|
COV_Subscriptions[index].invokeID = 0;
|
||||||
(object_instance == object_instance2)) {
|
|
||||||
cov_send_request(&COV_Subscriptions[index2],
|
|
||||||
&value_list[0]);
|
|
||||||
COV_Subscriptions[index2].send_requested = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* send any COVs that are requested */
|
||||||
|
for (index = 0; index < MAX_COV_SUBCRIPTIONS; index++) {
|
||||||
|
if (COV_Subscriptions[index].valid) {
|
||||||
|
if (COV_Subscriptions[index].send_requested) {
|
||||||
|
if (COV_Subscriptions[index].issueConfirmedNotifications) {
|
||||||
|
if (COV_Subscriptions[index].invokeID != 0) {
|
||||||
|
/* already sending - be patient! */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!tsm_transaction_available()) {
|
||||||
|
/* no free transactions - be patient! */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
object_type = (BACNET_OBJECT_TYPE)
|
||||||
|
COV_Subscriptions[index].monitoredObjectIdentifier.type;
|
||||||
|
object_instance =
|
||||||
|
COV_Subscriptions[index].monitoredObjectIdentifier.instance;
|
||||||
|
(void)Device_Encode_Value_List(object_type, object_instance,
|
||||||
|
&value_list[0]);
|
||||||
|
status = cov_send_request(
|
||||||
|
&COV_Subscriptions[index],
|
||||||
|
&value_list[0]);
|
||||||
|
if (status) {
|
||||||
|
COV_Subscriptions[index].send_requested = false;
|
||||||
|
} else {
|
||||||
|
/* must be out of PDU space - stop for now */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cov_subscribe(
|
static bool cov_subscribe(
|
||||||
@@ -460,10 +520,10 @@ static bool cov_subscribe(
|
|||||||
BACNET_ERROR_CODE * error_code)
|
BACNET_ERROR_CODE * error_code)
|
||||||
{
|
{
|
||||||
bool status = false; /* return value */
|
bool status = false; /* return value */
|
||||||
uint16_t object_type = 0;
|
BACNET_OBJECT_TYPE object_type = MAX_BACNET_OBJECT_TYPE;
|
||||||
uint32_t object_instance = 0;
|
uint32_t object_instance = 0;
|
||||||
|
|
||||||
object_type = cov_data->monitoredObjectIdentifier.type;
|
object_type = (BACNET_OBJECT_TYPE)cov_data->monitoredObjectIdentifier.type;
|
||||||
object_instance = cov_data->monitoredObjectIdentifier.instance;
|
object_instance = cov_data->monitoredObjectIdentifier.instance;
|
||||||
status = Device_Valid_Object_Id(object_type, object_instance);
|
status = Device_Valid_Object_Id(object_type, object_instance);
|
||||||
if (status) {
|
if (status) {
|
||||||
@@ -518,7 +578,7 @@ void handler_cov_subscribe(
|
|||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
/* initialize a common abort code */
|
/* initialize a common abort code */
|
||||||
cov_data.error_code = ABORT_REASON_SEGMENTATION_NOT_SUPPORTED;
|
cov_data.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
/* encode the NPDU portion of the packet */
|
/* encode the NPDU portion of the packet */
|
||||||
datalink_get_my_address(&my_address);
|
datalink_get_my_address(&my_address);
|
||||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||||
|
|||||||
@@ -45,20 +45,66 @@ void handler_unconfirmed_private_transfer(
|
|||||||
BACNET_ADDRESS * src)
|
BACNET_ADDRESS * src)
|
||||||
{
|
{
|
||||||
BACNET_PRIVATE_TRANSFER_DATA private_data;
|
BACNET_PRIVATE_TRANSFER_DATA private_data;
|
||||||
|
BACNET_OBJECT_PROPERTY_VALUE object_value; /* for bacapp printing */
|
||||||
|
BACNET_APPLICATION_DATA_VALUE value; /* for decode value data */
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
uint8_t *application_data;
|
||||||
|
int application_data_len;
|
||||||
|
bool first_value = true;
|
||||||
|
bool print_brace = false;
|
||||||
|
|
||||||
#if PRINT_ENABLED
|
#if PRINT_ENABLED
|
||||||
fprintf(stderr, "Received Unconfirmed Private Transfer Request!\n");
|
fprintf(stderr, "Received Unconfirmed Private Transfer Request!\n");
|
||||||
#endif
|
#endif
|
||||||
(void) src;
|
len = ptransfer_decode_service_request(
|
||||||
len =
|
service_request, service_len, &private_data);
|
||||||
ptransfer_decode_service_request(service_request, service_len,
|
|
||||||
&private_data);
|
|
||||||
if (len >= 0) {
|
if (len >= 0) {
|
||||||
#if PRINT_ENABLED
|
#if PRINT_ENABLED
|
||||||
fprintf(stderr,
|
printf("PrivateTransfer:vendorID=%u\r\n",
|
||||||
"UnconfirmedPrivateTransfer: " "vendorID=%u serviceNumber=%u\n",
|
(unsigned)private_data.vendorID);
|
||||||
private_data.vendorID, private_data.serviceNumber);
|
printf("PrivateTransfer:serviceNumber=%lu\r\n",
|
||||||
|
(unsigned long)private_data.serviceNumber);
|
||||||
|
#endif
|
||||||
|
application_data = private_data.serviceParameters;
|
||||||
|
application_data_len = private_data.serviceParametersLen;
|
||||||
|
for (;;) {
|
||||||
|
len =
|
||||||
|
bacapp_decode_application_data(application_data,
|
||||||
|
(uint8_t) application_data_len, &value);
|
||||||
|
if (first_value && (len < application_data_len)) {
|
||||||
|
first_value = false;
|
||||||
|
#if PRINT_ENABLED
|
||||||
|
fprintf(stdout, "{");
|
||||||
|
#endif
|
||||||
|
print_brace = true;
|
||||||
|
}
|
||||||
|
/* private transfer doesn't provide any clues */
|
||||||
|
object_value.object_type = MAX_BACNET_OBJECT_TYPE;
|
||||||
|
object_value.object_instance = BACNET_MAX_INSTANCE;
|
||||||
|
object_value.object_property = MAX_BACNET_PROPERTY_ID;
|
||||||
|
object_value.array_index = BACNET_ARRAY_ALL;
|
||||||
|
object_value.value = &value;
|
||||||
|
bacapp_print_value(stdout, &object_value);
|
||||||
|
if (len > 0) {
|
||||||
|
if (len < application_data_len) {
|
||||||
|
application_data += len;
|
||||||
|
application_data_len -= len;
|
||||||
|
/* there's more! */
|
||||||
|
#if PRINT_ENABLED
|
||||||
|
fprintf(stdout, ",");
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if PRINT_ENABLED
|
||||||
|
if (print_brace)
|
||||||
|
fprintf(stdout, "}");
|
||||||
|
fprintf(stdout, "\r\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ TARGET = baciamr
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -46,15 +46,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
|
||||||
/* static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; */
|
|
||||||
|
|
||||||
/* global variables used in this file */
|
/* global variables used in this file */
|
||||||
#define MAX_ROUTER_DNETS 64
|
#define MAX_ROUTER_DNETS 64
|
||||||
static int Target_Router_Networks[MAX_ROUTER_DNETS] = { -1 };
|
static int Target_Router_Networks[MAX_ROUTER_DNETS] = { -1 };
|
||||||
@@ -90,7 +81,7 @@ void MyRejectHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ TARGET = bacinitr
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -48,12 +48,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -220,7 +214,7 @@ static void My_NPDU_Handler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -143,9 +143,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define ANALOG_INPUT_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, \
|
|
||||||
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, \
|
|
||||||
Analog_Input_Object_Name, Analog_Input_Read_Property, NULL, \
|
|
||||||
Analog_Input_Property_Lists, NULL, NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -100,10 +100,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define ANALOG_OUTPUT_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_ANALOG_OUTPUT, Analog_Output_Init, Analog_Output_Count, \
|
|
||||||
Analog_Output_Index_To_Instance, Analog_Output_Valid_Instance, \
|
|
||||||
Analog_Output_Object_Name, Analog_Output_Read_Property, \
|
|
||||||
Analog_Output_Write_Property, Analog_Output_Property_Lists, \
|
|
||||||
NULL, NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -132,10 +132,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define ANALOG_VALUE_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count, \
|
|
||||||
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance, \
|
|
||||||
Analog_Value_Object_Name, Analog_Value_Read_Property, \
|
|
||||||
Analog_Value_Write_Property, Analog_Value_Property_Lists, NULL, \
|
|
||||||
NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -98,8 +98,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define FILE_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_FILE, bacfile_init, bacfile_count, bacfile_index_to_instance, \
|
|
||||||
bacfile_valid_instance, bacfile_object_name, bacfile_read_property, \
|
|
||||||
bacfile_write_property, BACfile_Property_Lists, NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ bool Binary_Input_Out_Of_Service(
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Binary_Input_Change_Of_Value(
|
bool Binary_Input_Change_Of_Value(
|
||||||
uint32_t object_instance)
|
uint32_t object_instance)
|
||||||
{
|
{
|
||||||
bool status = false;
|
bool status = false;
|
||||||
@@ -197,7 +197,7 @@ static bool Binary_Input_Change_Of_Value(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Binary_Input_Change_Of_Value_Clear(
|
void Binary_Input_Change_Of_Value_Clear(
|
||||||
uint32_t object_instance)
|
uint32_t object_instance)
|
||||||
{
|
{
|
||||||
unsigned index;
|
unsigned index;
|
||||||
@@ -249,7 +249,6 @@ bool Binary_Input_Encode_Value_List(
|
|||||||
value_list->priority = BACNET_NO_PRIORITY;
|
value_list->priority = BACNET_NO_PRIORITY;
|
||||||
}
|
}
|
||||||
status = Binary_Input_Change_Of_Value(object_instance);
|
status = Binary_Input_Change_Of_Value(object_instance);
|
||||||
Binary_Input_Change_Of_Value_Clear(object_instance);
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ extern "C" {
|
|||||||
bool Binary_Input_Encode_Value_List(
|
bool Binary_Input_Encode_Value_List(
|
||||||
uint32_t object_instance,
|
uint32_t object_instance,
|
||||||
BACNET_PROPERTY_VALUE * value_list);
|
BACNET_PROPERTY_VALUE * value_list);
|
||||||
|
bool Binary_Input_Change_Of_Value(
|
||||||
|
uint32_t instance);
|
||||||
|
void Binary_Input_Change_Of_Value_Clear(
|
||||||
|
uint32_t instance);
|
||||||
|
|
||||||
int Binary_Input_Read_Property(
|
int Binary_Input_Read_Property(
|
||||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||||
@@ -110,9 +114,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define BINARY_INPUT_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count, \
|
|
||||||
Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance, \
|
|
||||||
Binary_Input_Object_Name, Binary_Input_Read_Property, NULL, \
|
|
||||||
Binary_Input_Property_Lists, NULL, NULL, Binary_Input_Encode_Value_List
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -109,10 +109,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define BINARY_OUTPUT_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, \
|
|
||||||
Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, \
|
|
||||||
Binary_Output_Object_Name, Binary_Output_Read_Property, \
|
|
||||||
Binary_Output_Write_Property, Binary_Output_Property_Lists, \
|
|
||||||
NULL, NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -71,10 +71,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define BINARY_VALUE_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count, \
|
|
||||||
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance, \
|
|
||||||
Binary_Value_Object_Name, Binary_Value_Read_Property, \
|
|
||||||
Binary_Value_Write_Property, Binary_Value_Property_Lists, NULL, \
|
|
||||||
NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,908 @@
|
|||||||
|
/**************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
/** @file device-client.c Lightweight base "class" for handling all
|
||||||
|
* BACnet objects belonging to a BACnet device, as well as
|
||||||
|
* Device-specific properties. This Device instance is designed to
|
||||||
|
* meet minimal functionality for simple clients. */
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h> /* for memmove */
|
||||||
|
#include <time.h> /* for timezone, localtime */
|
||||||
|
#include "bacdef.h"
|
||||||
|
#include "bacdcode.h"
|
||||||
|
#include "bacenum.h"
|
||||||
|
#include "bacapp.h"
|
||||||
|
#include "config.h" /* the custom stuff */
|
||||||
|
#include "apdu.h"
|
||||||
|
#include "rp.h" /* ReadProperty handling */
|
||||||
|
#include "version.h"
|
||||||
|
#include "handlers.h"
|
||||||
|
#include "datalink.h"
|
||||||
|
#include "address.h"
|
||||||
|
/* include the device object */
|
||||||
|
#include "device.h" /* me */
|
||||||
|
|
||||||
|
/* note: you really only need to define variables for
|
||||||
|
properties that are writable or that may change.
|
||||||
|
The properties that are constant can be hard coded
|
||||||
|
into the read-property encoding. */
|
||||||
|
|
||||||
|
static uint32_t Object_Instance_Number = 260001;
|
||||||
|
static BACNET_CHARACTER_STRING My_Object_Name;
|
||||||
|
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||||
|
static char *Vendor_Name = BACNET_VENDOR_NAME;
|
||||||
|
static uint16_t Vendor_Identifier = BACNET_VENDOR_ID;
|
||||||
|
static char *Model_Name = "GNU";
|
||||||
|
static char *Application_Software_Version = "1.0";
|
||||||
|
static char *Location = "USA";
|
||||||
|
static char *Description = "command line client";
|
||||||
|
/* static uint8_t Protocol_Version = 1; - constant, not settable */
|
||||||
|
/* static uint8_t Protocol_Revision = 4; - constant, not settable */
|
||||||
|
/* Protocol_Services_Supported - dynamically generated */
|
||||||
|
/* Protocol_Object_Types_Supported - in RP encoding */
|
||||||
|
/* Object_List - dynamically generated */
|
||||||
|
/* static BACNET_SEGMENTATION Segmentation_Supported = SEGMENTATION_NONE; */
|
||||||
|
/* static uint8_t Max_Segments_Accepted = 0; */
|
||||||
|
/* VT_Classes_Supported */
|
||||||
|
/* Active_VT_Sessions */
|
||||||
|
/* static BACNET_TIME Local_Time; rely on OS, if there is one */
|
||||||
|
/* static BACNET_DATE Local_Date; rely on OS, if there is one */
|
||||||
|
/* NOTE: BACnet UTC Offset is inverse of common practice.
|
||||||
|
If your UTC offset is -5hours of GMT,
|
||||||
|
then BACnet UTC offset is +5hours.
|
||||||
|
BACnet UTC offset is expressed in minutes. */
|
||||||
|
/* static int32_t UTC_Offset = 5 * 60; */
|
||||||
|
/* static bool Daylight_Savings_Status = false; rely on OS */
|
||||||
|
/* List_Of_Session_Keys */
|
||||||
|
/* Time_Synchronization_Recipients */
|
||||||
|
/* Max_Master - rely on MS/TP subsystem, if there is one */
|
||||||
|
/* Max_Info_Frames - rely on MS/TP subsystem, if there is one */
|
||||||
|
/* Device_Address_Binding - required, but relies on binding cache */
|
||||||
|
static uint32_t Database_Revision = 0;
|
||||||
|
/* Configuration_Files */
|
||||||
|
/* Last_Restore_Time */
|
||||||
|
/* Backup_Failure_Timeout */
|
||||||
|
/* Active_COV_Subscriptions */
|
||||||
|
/* Slave_Proxy_Enable */
|
||||||
|
/* Manual_Slave_Address_Binding */
|
||||||
|
/* Auto_Slave_Discovery */
|
||||||
|
/* Slave_Address_Binding */
|
||||||
|
/* Profile_Name */
|
||||||
|
|
||||||
|
/* local forward (semi-private) and external prototypes */
|
||||||
|
int Device_Read_Property_Local(
|
||||||
|
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||||
|
|
||||||
|
/* All included BACnet objects */
|
||||||
|
static object_functions_t Object_Table[] = {
|
||||||
|
{OBJECT_DEVICE,
|
||||||
|
NULL /* Init - don't init Device or it will recourse! */,
|
||||||
|
Device_Count,
|
||||||
|
Device_Index_To_Instance,
|
||||||
|
Device_Valid_Object_Instance_Number,
|
||||||
|
Device_Object_Name,
|
||||||
|
Device_Read_Property_Local,
|
||||||
|
NULL /* Write_Property */,
|
||||||
|
NULL /* Property_Lists */,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */},
|
||||||
|
{MAX_BACNET_OBJECT_TYPE,
|
||||||
|
NULL /* Init */,
|
||||||
|
NULL /* Count */,
|
||||||
|
NULL /* Index_To_Instance */,
|
||||||
|
NULL /* Valid_Instance */,
|
||||||
|
NULL /* Object_Name */,
|
||||||
|
NULL /* Read_Property */,
|
||||||
|
NULL /* Write_Property */,
|
||||||
|
NULL /* Property_Lists */,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Glue function to let the Device object, when called by a handler,
|
||||||
|
* lookup which Object type needs to be invoked.
|
||||||
|
* @ingroup ObjHelpers
|
||||||
|
* @param Object_Type [in] The type of BACnet Object the handler wants to access.
|
||||||
|
* @return Pointer to the group of object helper functions that implement this
|
||||||
|
* type of Object.
|
||||||
|
*/
|
||||||
|
static struct object_functions *Device_Objects_Find_Functions(
|
||||||
|
BACNET_OBJECT_TYPE Object_Type)
|
||||||
|
{
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
pObject = &Object_Table[0];
|
||||||
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
|
/* handle each object type */
|
||||||
|
if (pObject->Object_Type == Object_Type) {
|
||||||
|
return (pObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
pObject++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Device_Count(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Device_Index_To_Instance(
|
||||||
|
unsigned index)
|
||||||
|
{
|
||||||
|
index = index;
|
||||||
|
return Object_Instance_Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* methods to manipulate the data */
|
||||||
|
|
||||||
|
/** Return the Object Instance number for our (single) Device Object.
|
||||||
|
* This is a key function, widely invoked by the handler code, since
|
||||||
|
* it provides "our" (ie, local) address.
|
||||||
|
* @ingroup ObjIntf
|
||||||
|
* @return The Instance number used in the BACNET_OBJECT_ID for the Device.
|
||||||
|
*/
|
||||||
|
uint32_t Device_Object_Instance_Number(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
#ifdef BAC_ROUTING
|
||||||
|
return Routed_Device_Object_Instance_Number();
|
||||||
|
#else
|
||||||
|
return Object_Instance_Number;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device_Set_Object_Instance_Number(
|
||||||
|
uint32_t object_id)
|
||||||
|
{
|
||||||
|
bool status = true; /* return value */
|
||||||
|
|
||||||
|
if (object_id <= BACNET_MAX_INSTANCE) {
|
||||||
|
/* Make the change and update the database revision */
|
||||||
|
Object_Instance_Number = object_id;
|
||||||
|
Device_Inc_Database_Revision();
|
||||||
|
} else
|
||||||
|
status = false;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device_Valid_Object_Instance_Number(
|
||||||
|
uint32_t object_id)
|
||||||
|
{
|
||||||
|
/* BACnet allows for a wildcard instance number */
|
||||||
|
return ((Object_Instance_Number == object_id) ||
|
||||||
|
(object_id == BACNET_MAX_INSTANCE));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device_Object_Name(
|
||||||
|
uint32_t object_instance,
|
||||||
|
BACNET_CHARACTER_STRING * object_name)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
if (object_instance == Object_Instance_Number) {
|
||||||
|
status = characterstring_copy(object_name, &My_Object_Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device_Set_Object_Name(
|
||||||
|
BACNET_CHARACTER_STRING * object_name)
|
||||||
|
{
|
||||||
|
bool status = false; /*return value */
|
||||||
|
|
||||||
|
if (!characterstring_same(&My_Object_Name, object_name)) {
|
||||||
|
/* Make the change and update the database revision */
|
||||||
|
status = characterstring_copy(&My_Object_Name, object_name);
|
||||||
|
Device_Inc_Database_Revision();
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
BACNET_DEVICE_STATUS Device_System_Status(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return System_Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Device_Set_System_Status(
|
||||||
|
BACNET_DEVICE_STATUS status,
|
||||||
|
bool local)
|
||||||
|
{
|
||||||
|
int result = 0; /*return value - 0 = ok, -1 = bad value, -2 = not allowed */
|
||||||
|
|
||||||
|
/* We limit the options available depending on whether the source is
|
||||||
|
* internal or external. */
|
||||||
|
if (local) {
|
||||||
|
switch (status) {
|
||||||
|
case STATUS_OPERATIONAL:
|
||||||
|
case STATUS_OPERATIONAL_READ_ONLY:
|
||||||
|
case STATUS_DOWNLOAD_REQUIRED:
|
||||||
|
case STATUS_DOWNLOAD_IN_PROGRESS:
|
||||||
|
case STATUS_NON_OPERATIONAL:
|
||||||
|
System_Status = status;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Don't support backup at present so don't allow setting */
|
||||||
|
case STATUS_BACKUP_IN_PROGRESS:
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (status) {
|
||||||
|
/* Allow these for the moment as a way to easily alter
|
||||||
|
* overall device operation. The lack of password protection
|
||||||
|
* or other authentication makes allowing writes to this
|
||||||
|
* property a risky facility to provide.
|
||||||
|
*/
|
||||||
|
case STATUS_OPERATIONAL:
|
||||||
|
case STATUS_OPERATIONAL_READ_ONLY:
|
||||||
|
case STATUS_NON_OPERATIONAL:
|
||||||
|
System_Status = status;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Don't allow outsider set this - it should probably
|
||||||
|
* be set if the device config is incomplete or
|
||||||
|
* corrupted or perhaps after some sort of operator
|
||||||
|
* wipe operation.
|
||||||
|
*/
|
||||||
|
case STATUS_DOWNLOAD_REQUIRED:
|
||||||
|
/* Don't allow outsider set this - it should be set
|
||||||
|
* internally at the start of a multi packet download
|
||||||
|
* perhaps indirectly via PT or WF to a config file.
|
||||||
|
*/
|
||||||
|
case STATUS_DOWNLOAD_IN_PROGRESS:
|
||||||
|
/* Don't support backup at present so don't allow setting */
|
||||||
|
case STATUS_BACKUP_IN_PROGRESS:
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Device_Vendor_Name(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return Vendor_Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the Vendor ID for this Device.
|
||||||
|
* See the assignments at http://www.bacnet.org/VendorID/BACnet%20Vendor%20IDs.htm
|
||||||
|
* @return The Vendor ID of this Device.
|
||||||
|
*/
|
||||||
|
uint16_t Device_Vendor_Identifier(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return Vendor_Identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device_Set_Vendor_Identifier(
|
||||||
|
uint16_t vendor_id)
|
||||||
|
{
|
||||||
|
Vendor_Identifier = vendor_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Device_Model_Name(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return Model_Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device_Set_Model_Name(
|
||||||
|
const char *name,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
bool status = false; /*return value */
|
||||||
|
|
||||||
|
if (length < sizeof(Model_Name)) {
|
||||||
|
memmove(Model_Name, name, length);
|
||||||
|
Model_Name[length] = 0;
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Device_Firmware_Revision(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return BACnet_Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Device_Application_Software_Version(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return Application_Software_Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device_Set_Application_Software_Version(
|
||||||
|
const char *name,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
bool status = false; /*return value */
|
||||||
|
|
||||||
|
if (length < sizeof(Application_Software_Version)) {
|
||||||
|
memmove(Application_Software_Version, name, length);
|
||||||
|
Application_Software_Version[length] = 0;
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Device_Description(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device_Set_Description(
|
||||||
|
const char *name,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
bool status = false; /*return value */
|
||||||
|
|
||||||
|
if (length < sizeof(Description)) {
|
||||||
|
memmove(Description, name, length);
|
||||||
|
Description[length] = 0;
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *Device_Location(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return Location;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device_Set_Location(
|
||||||
|
const char *name,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
bool status = false; /*return value */
|
||||||
|
|
||||||
|
if (length < sizeof(Location)) {
|
||||||
|
memmove(Location, name, length);
|
||||||
|
Location[length] = 0;
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Device_Protocol_Version(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return BACNET_PROTOCOL_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Device_Protocol_Revision(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return BACNET_PROTOCOL_REVISION;
|
||||||
|
}
|
||||||
|
|
||||||
|
BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return SEGMENTATION_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Device_Database_Revision(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
return Database_Revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device_Set_Database_Revision(
|
||||||
|
uint32_t revision)
|
||||||
|
{
|
||||||
|
Database_Revision = revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shortcut for incrementing database revision as this is potentially
|
||||||
|
* the most common operation if changing object names and ids is
|
||||||
|
* implemented.
|
||||||
|
*/
|
||||||
|
void Device_Inc_Database_Revision(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
Database_Revision++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the total count of objects supported by this Device Object.
|
||||||
|
* @note Since many network clients depend on the object list
|
||||||
|
* for discovery, it must be consistent!
|
||||||
|
* @return The count of objects, for all supported Object types.
|
||||||
|
*/
|
||||||
|
unsigned Device_Object_List_Count(
|
||||||
|
void)
|
||||||
|
{
|
||||||
|
unsigned count = 0; /* number of objects */
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
/* initialize the default return values */
|
||||||
|
pObject = &Object_Table[0];
|
||||||
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
|
if (pObject->Object_Count) {
|
||||||
|
count += pObject->Object_Count();
|
||||||
|
}
|
||||||
|
pObject++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Lookup the Object at the given array index in the Device's Object List.
|
||||||
|
* Even though we don't keep a single linear array of objects in the Device,
|
||||||
|
* this method acts as though we do and works through a virtual, concatenated
|
||||||
|
* array of all of our object type arrays.
|
||||||
|
*
|
||||||
|
* @param array_index [in] The desired array index (1 to N)
|
||||||
|
* @param object_type [out] The object's type, if found.
|
||||||
|
* @param instance [out] The object's instance number, if found.
|
||||||
|
* @return True if found, else false.
|
||||||
|
*/
|
||||||
|
bool Device_Object_List_Identifier(
|
||||||
|
unsigned array_index,
|
||||||
|
int *object_type,
|
||||||
|
uint32_t * instance)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
unsigned count = 0;
|
||||||
|
unsigned object_index = 0;
|
||||||
|
unsigned temp_index = 0;
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
/* array index zero is length - so invalid */
|
||||||
|
if (array_index == 0) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
object_index = array_index - 1;
|
||||||
|
/* initialize the default return values */
|
||||||
|
pObject = &Object_Table[0];
|
||||||
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
|
if (pObject->Object_Count) {
|
||||||
|
object_index -= count;
|
||||||
|
count = pObject->Object_Count();
|
||||||
|
if (object_index < count) {
|
||||||
|
/* Use the iterator function if available otherwise
|
||||||
|
* look for the index to instance to get the ID */
|
||||||
|
if (pObject->Object_Iterator) {
|
||||||
|
/* First find the first object */
|
||||||
|
temp_index = pObject->Object_Iterator(~(unsigned) 0);
|
||||||
|
/* Then step through the objects to find the nth */
|
||||||
|
while (object_index != 0) {
|
||||||
|
temp_index = pObject->Object_Iterator(temp_index);
|
||||||
|
object_index--;
|
||||||
|
}
|
||||||
|
/* set the object_index up before falling through to next bit */
|
||||||
|
object_index = temp_index;
|
||||||
|
}
|
||||||
|
if (pObject->Object_Index_To_Instance) {
|
||||||
|
*object_type = pObject->Object_Type;
|
||||||
|
*instance =
|
||||||
|
pObject->Object_Index_To_Instance(object_index);
|
||||||
|
status = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pObject++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determine if we have an object with the given object_name.
|
||||||
|
* If the object_type and object_instance pointers are not null,
|
||||||
|
* and the lookup succeeds, they will be given the resulting values.
|
||||||
|
* @param object_name [in] The desired Object Name to look for.
|
||||||
|
* @param object_type [out] The BACNET_OBJECT_TYPE of the matching Object.
|
||||||
|
* @param object_instance [out] The object instance number of the matching Object.
|
||||||
|
* @return True on success or else False if not found.
|
||||||
|
*/
|
||||||
|
bool Device_Valid_Object_Name(
|
||||||
|
BACNET_CHARACTER_STRING * object_name1,
|
||||||
|
int *object_type,
|
||||||
|
uint32_t * object_instance)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
int type = 0;
|
||||||
|
uint32_t instance;
|
||||||
|
unsigned max_objects = 0, i = 0;
|
||||||
|
bool check_id = false;
|
||||||
|
BACNET_CHARACTER_STRING object_name2;
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
max_objects = Device_Object_List_Count();
|
||||||
|
for (i = 0; i < max_objects; i++) {
|
||||||
|
check_id = Device_Object_List_Identifier(i, &type, &instance);
|
||||||
|
if (check_id) {
|
||||||
|
pObject = Device_Objects_Find_Functions(type);
|
||||||
|
if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
|
||||||
|
(pObject->Object_Name(instance, &object_name2) &&
|
||||||
|
characterstring_same(object_name1, &object_name2))) {
|
||||||
|
found = true;
|
||||||
|
if (object_type) {
|
||||||
|
*object_type = type;
|
||||||
|
}
|
||||||
|
if (object_instance) {
|
||||||
|
*object_instance = instance;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Determine if we have an object of this type and instance number.
|
||||||
|
* @param object_type [in] The desired BACNET_OBJECT_TYPE
|
||||||
|
* @param object_instance [in] The object instance number to be looked up.
|
||||||
|
* @return True if found, else False if no such Object in this device.
|
||||||
|
*/
|
||||||
|
bool Device_Valid_Object_Id(
|
||||||
|
int object_type,
|
||||||
|
uint32_t object_instance)
|
||||||
|
{
|
||||||
|
bool status = false; /* return value */
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
pObject = Device_Objects_Find_Functions(object_type);
|
||||||
|
if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
|
||||||
|
status = pObject->Object_Valid_Instance(object_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy a child object's object_name value, given its ID.
|
||||||
|
* @param object_type [in] The BACNET_OBJECT_TYPE of the child Object.
|
||||||
|
* @param object_instance [in] The object instance number of the child Object.
|
||||||
|
* @param object_name [out] The Object Name found for this child Object.
|
||||||
|
* @return True on success or else False if not found.
|
||||||
|
*/
|
||||||
|
bool Device_Object_Name_Copy(
|
||||||
|
BACNET_OBJECT_TYPE object_type,
|
||||||
|
uint32_t object_instance,
|
||||||
|
BACNET_CHARACTER_STRING * object_name)
|
||||||
|
{
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
pObject = Device_Objects_Find_Functions(object_type);
|
||||||
|
if ((pObject != NULL) && (pObject->Object_Name != NULL)) {
|
||||||
|
found = pObject->Object_Name(object_instance, object_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error or
|
||||||
|
BACNET_STATUS_ABORT for abort message */
|
||||||
|
int Device_Read_Property_Local(
|
||||||
|
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;
|
||||||
|
unsigned i = 0;
|
||||||
|
int object_type = 0;
|
||||||
|
uint32_t instance = 0;
|
||||||
|
unsigned count = 0;
|
||||||
|
uint8_t *apdu = NULL;
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||||
|
(rpdata->application_data_len == 0)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
apdu = rpdata->application_data;
|
||||||
|
switch (rpdata->object_property) {
|
||||||
|
case PROP_OBJECT_IDENTIFIER:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||||
|
Object_Instance_Number);
|
||||||
|
break;
|
||||||
|
case PROP_OBJECT_NAME:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_character_string(&apdu[0], &My_Object_Name);
|
||||||
|
break;
|
||||||
|
case PROP_OBJECT_TYPE:
|
||||||
|
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||||
|
break;
|
||||||
|
case PROP_DESCRIPTION:
|
||||||
|
characterstring_init_ansi(&char_string, Description);
|
||||||
|
apdu_len =
|
||||||
|
encode_application_character_string(&apdu[0], &char_string);
|
||||||
|
break;
|
||||||
|
case PROP_SYSTEM_STATUS:
|
||||||
|
apdu_len = encode_application_enumerated(&apdu[0], System_Status);
|
||||||
|
break;
|
||||||
|
case PROP_VENDOR_NAME:
|
||||||
|
characterstring_init_ansi(&char_string, Vendor_Name);
|
||||||
|
apdu_len =
|
||||||
|
encode_application_character_string(&apdu[0], &char_string);
|
||||||
|
break;
|
||||||
|
case PROP_VENDOR_IDENTIFIER:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_unsigned(&apdu[0], Vendor_Identifier);
|
||||||
|
break;
|
||||||
|
case PROP_MODEL_NAME:
|
||||||
|
characterstring_init_ansi(&char_string, Model_Name);
|
||||||
|
apdu_len =
|
||||||
|
encode_application_character_string(&apdu[0], &char_string);
|
||||||
|
break;
|
||||||
|
case PROP_FIRMWARE_REVISION:
|
||||||
|
characterstring_init_ansi(&char_string, BACnet_Version);
|
||||||
|
apdu_len =
|
||||||
|
encode_application_character_string(&apdu[0], &char_string);
|
||||||
|
break;
|
||||||
|
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||||
|
characterstring_init_ansi(&char_string,
|
||||||
|
Application_Software_Version);
|
||||||
|
apdu_len =
|
||||||
|
encode_application_character_string(&apdu[0], &char_string);
|
||||||
|
break;
|
||||||
|
case PROP_LOCATION:
|
||||||
|
characterstring_init_ansi(&char_string, Location);
|
||||||
|
apdu_len =
|
||||||
|
encode_application_character_string(&apdu[0], &char_string);
|
||||||
|
break;
|
||||||
|
case PROP_PROTOCOL_VERSION:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_unsigned(&apdu[0],
|
||||||
|
Device_Protocol_Version());
|
||||||
|
break;
|
||||||
|
case PROP_PROTOCOL_REVISION:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_unsigned(&apdu[0],
|
||||||
|
Device_Protocol_Revision());
|
||||||
|
break;
|
||||||
|
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||||
|
/* Note: list of services that are executed, not initiated. */
|
||||||
|
bitstring_init(&bit_string);
|
||||||
|
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
|
||||||
|
/* automatic lookup based on handlers set */
|
||||||
|
bitstring_set_bit(&bit_string, (uint8_t) i,
|
||||||
|
apdu_service_supported((BACNET_SERVICES_SUPPORTED) i));
|
||||||
|
}
|
||||||
|
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||||
|
break;
|
||||||
|
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
|
||||||
|
/* Note: this is the list of objects that can be in this device,
|
||||||
|
not a list of objects that this device can access */
|
||||||
|
bitstring_init(&bit_string);
|
||||||
|
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
||||||
|
/* initialize all the object types to not-supported */
|
||||||
|
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
||||||
|
}
|
||||||
|
/* set the object types with objects to supported */
|
||||||
|
|
||||||
|
pObject = &Object_Table[0];
|
||||||
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
|
if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) {
|
||||||
|
bitstring_set_bit(&bit_string, pObject->Object_Type, true);
|
||||||
|
}
|
||||||
|
pObject++;
|
||||||
|
}
|
||||||
|
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||||
|
break;
|
||||||
|
case PROP_OBJECT_LIST:
|
||||||
|
count = Device_Object_List_Count();
|
||||||
|
/* Array element zero is the number of objects in the list */
|
||||||
|
if (rpdata->array_index == 0)
|
||||||
|
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||||
|
/* if no index was specified, then try to encode the entire list */
|
||||||
|
/* into one packet. Note that more than likely you will have */
|
||||||
|
/* to return an error if the number of encoded objects exceeds */
|
||||||
|
/* your maximum APDU size. */
|
||||||
|
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
|
||||||
|
for (i = 1; i <= count; i++) {
|
||||||
|
found =
|
||||||
|
Device_Object_List_Identifier(i, &object_type,
|
||||||
|
&instance);
|
||||||
|
if (found) {
|
||||||
|
len =
|
||||||
|
encode_application_object_id(&apdu[apdu_len],
|
||||||
|
object_type, instance);
|
||||||
|
apdu_len += len;
|
||||||
|
/* assume next one is the same size as this one */
|
||||||
|
/* can we all fit into the APDU? Don't check for last entry */
|
||||||
|
if ((i != count) && (apdu_len + len) >= MAX_APDU) {
|
||||||
|
/* Abort response */
|
||||||
|
rpdata->error_code =
|
||||||
|
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||||
|
apdu_len = BACNET_STATUS_ABORT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* error: internal error? */
|
||||||
|
rpdata->error_class = ERROR_CLASS_SERVICES;
|
||||||
|
rpdata->error_code = ERROR_CODE_OTHER;
|
||||||
|
apdu_len = BACNET_STATUS_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
found =
|
||||||
|
Device_Object_List_Identifier(rpdata->array_index,
|
||||||
|
&object_type, &instance);
|
||||||
|
if (found) {
|
||||||
|
apdu_len =
|
||||||
|
encode_application_object_id(&apdu[0], object_type,
|
||||||
|
instance);
|
||||||
|
} else {
|
||||||
|
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||||
|
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||||
|
apdu_len = BACNET_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PROP_MAX_APDU_LENGTH_ACCEPTED:
|
||||||
|
apdu_len = encode_application_unsigned(&apdu[0], MAX_APDU);
|
||||||
|
break;
|
||||||
|
case PROP_SEGMENTATION_SUPPORTED:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_enumerated(&apdu[0],
|
||||||
|
Device_Segmentation_Supported());
|
||||||
|
break;
|
||||||
|
case PROP_APDU_TIMEOUT:
|
||||||
|
apdu_len = encode_application_unsigned(&apdu[0], apdu_timeout());
|
||||||
|
break;
|
||||||
|
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||||
|
apdu_len = encode_application_unsigned(&apdu[0], apdu_retries());
|
||||||
|
break;
|
||||||
|
case PROP_DEVICE_ADDRESS_BINDING:
|
||||||
|
/* FIXME: the real max apdu remaining should be passed into function */
|
||||||
|
apdu_len = address_list_encode(&apdu[0], MAX_APDU);
|
||||||
|
break;
|
||||||
|
case PROP_DATABASE_REVISION:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_unsigned(&apdu[0], Database_Revision);
|
||||||
|
break;
|
||||||
|
#if defined(BACDL_MSTP)
|
||||||
|
case PROP_MAX_INFO_FRAMES:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_unsigned(&apdu[0],
|
||||||
|
dlmstp_max_info_frames());
|
||||||
|
break;
|
||||||
|
case PROP_MAX_MASTER:
|
||||||
|
apdu_len =
|
||||||
|
encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case PROP_ACTIVE_COV_SUBSCRIPTIONS:
|
||||||
|
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_OBJECT_LIST) &&
|
||||||
|
(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Looks up the requested Object and Property, and encodes its Value in an APDU.
|
||||||
|
* @ingroup ObjIntf
|
||||||
|
* If the Object or Property can't be found, sets the error class and code.
|
||||||
|
*
|
||||||
|
* @param rpdata [in,out] Structure with the desired Object and Property info
|
||||||
|
* on entry, and APDU message on return.
|
||||||
|
* @return The length of the APDU on success, else BACNET_STATUS_ERROR
|
||||||
|
*/
|
||||||
|
int Device_Read_Property(
|
||||||
|
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||||
|
{
|
||||||
|
int apdu_len = BACNET_STATUS_ERROR;
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
/* initialize the default return values */
|
||||||
|
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||||
|
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||||
|
pObject = Device_Objects_Find_Functions(rpdata->object_type);
|
||||||
|
if (pObject != NULL) {
|
||||||
|
if (pObject->Object_Valid_Instance &&
|
||||||
|
pObject->Object_Valid_Instance(rpdata->object_instance)) {
|
||||||
|
if (pObject->Object_Read_Property) {
|
||||||
|
apdu_len = pObject->Object_Read_Property(rpdata);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||||
|
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||||
|
rpdata->error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return apdu_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initialize the Device Object.
|
||||||
|
Initialize the group of object helper functions for any supported Object.
|
||||||
|
Initialize each of the Device Object child Object instances.
|
||||||
|
* @ingroup ObjIntf
|
||||||
|
* @param object_table [in,out] array of structure with object functions.
|
||||||
|
* Each Child Object must provide some implementation of each of these
|
||||||
|
* functions in order to properly support the default handlers.
|
||||||
|
*/
|
||||||
|
void Device_Init(
|
||||||
|
object_functions_t * object_table)
|
||||||
|
{
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
characterstring_init_ansi(&My_Object_Name, "SimpleClient");
|
||||||
|
/* we don't use the object table passed in */
|
||||||
|
(void) object_table;
|
||||||
|
pObject = &Object_Table[0];
|
||||||
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
|
if (pObject->Object_Init) {
|
||||||
|
pObject->Object_Init();
|
||||||
|
}
|
||||||
|
pObject++;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,87 +83,209 @@ extern int Routed_Device_Read_Property_Local(
|
|||||||
extern bool Routed_Device_Write_Property_Local(
|
extern bool Routed_Device_Write_Property_Local(
|
||||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||||
|
|
||||||
|
/* may be overridden by outside table */
|
||||||
|
static object_functions_t *Object_Table;
|
||||||
|
|
||||||
static object_functions_t Object_Table[] = {
|
static object_functions_t My_Object_Table[] = {
|
||||||
{
|
{OBJECT_DEVICE,
|
||||||
OBJECT_DEVICE, NULL, Device_Count, /* don't init - recursive! */
|
NULL /* Init - don't init Device or it will recourse! */,
|
||||||
Device_Index_To_Instance, Device_Valid_Object_Instance_Number,
|
Device_Count,
|
||||||
Device_Object_Name, Device_Read_Property_Local,
|
Device_Index_To_Instance,
|
||||||
Device_Write_Property_Local, Device_Property_Lists,
|
Device_Valid_Object_Instance_Number,
|
||||||
NULL, NULL, NULL, NULL}, {
|
Device_Object_Name,
|
||||||
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
|
Device_Read_Property_Local,
|
||||||
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
|
Device_Write_Property_Local,
|
||||||
Analog_Input_Object_Name, Analog_Input_Read_Property,
|
Device_Property_Lists,
|
||||||
Analog_Input_Write_Property, Analog_Input_Property_Lists,
|
NULL /* ReadRangeInfo */,
|
||||||
NULL, NULL, NULL, Analog_Input_Intrinsic_Reporting}, {
|
NULL /* Iterator */,
|
||||||
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,
|
NULL /* Value_Lists */,
|
||||||
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance,
|
NULL /* COV */,
|
||||||
Analog_Value_Object_Name, Analog_Value_Read_Property,
|
NULL /* COV Clear */,
|
||||||
Analog_Value_Write_Property, Analog_Value_Property_Lists,
|
NULL /* Intrinsic Reporting */},
|
||||||
NULL, NULL, NULL, Analog_Value_Intrinsic_Reporting}, {
|
{OBJECT_ANALOG_INPUT,
|
||||||
OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count,
|
Analog_Input_Init,
|
||||||
Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance,
|
Analog_Input_Count,
|
||||||
Binary_Input_Object_Name, Binary_Input_Read_Property,
|
Analog_Input_Index_To_Instance,
|
||||||
NULL, Binary_Input_Property_Lists,
|
Analog_Input_Valid_Instance,
|
||||||
NULL, NULL, NULL, NULL}, {
|
Analog_Input_Object_Name,
|
||||||
OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count,
|
Analog_Input_Read_Property,
|
||||||
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance,
|
Analog_Input_Write_Property,
|
||||||
Binary_Value_Object_Name, Binary_Value_Read_Property,
|
Analog_Input_Property_Lists,
|
||||||
Binary_Value_Write_Property, Binary_Value_Property_Lists,
|
NULL /* ReadRangeInfo */,
|
||||||
NULL, NULL, NULL, NULL}, {
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
Analog_Input_Intrinsic_Reporting},
|
||||||
|
{OBJECT_ANALOG_VALUE,
|
||||||
|
Analog_Value_Init,
|
||||||
|
Analog_Value_Count,
|
||||||
|
Analog_Value_Index_To_Instance,
|
||||||
|
Analog_Value_Valid_Instance,
|
||||||
|
Analog_Value_Object_Name,
|
||||||
|
Analog_Value_Read_Property,
|
||||||
|
Analog_Value_Write_Property,
|
||||||
|
Analog_Value_Property_Lists,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
Analog_Value_Intrinsic_Reporting},
|
||||||
|
{OBJECT_BINARY_INPUT,
|
||||||
|
Binary_Input_Init,
|
||||||
|
Binary_Input_Count,
|
||||||
|
Binary_Input_Index_To_Instance,
|
||||||
|
Binary_Input_Valid_Instance,
|
||||||
|
Binary_Input_Object_Name,
|
||||||
|
Binary_Input_Read_Property,
|
||||||
|
NULL /* Write Property */,
|
||||||
|
Binary_Input_Property_Lists,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
Binary_Input_Encode_Value_List,
|
||||||
|
Binary_Input_Change_Of_Value,
|
||||||
|
Binary_Input_Change_Of_Value_Clear,
|
||||||
|
NULL /* Intrinsic Reporting */},
|
||||||
|
{OBJECT_BINARY_VALUE,
|
||||||
|
Binary_Value_Init,
|
||||||
|
Binary_Value_Count,
|
||||||
|
Binary_Value_Index_To_Instance,
|
||||||
|
Binary_Value_Valid_Instance,
|
||||||
|
Binary_Value_Object_Name,
|
||||||
|
Binary_Value_Read_Property,
|
||||||
|
Binary_Value_Write_Property,
|
||||||
|
Binary_Value_Property_Lists,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */},
|
||||||
#if defined(INTRINSIC_REPORTING)
|
#if defined(INTRINSIC_REPORTING)
|
||||||
OBJECT_NOTIFICATION_CLASS, Notification_Class_Init,
|
{OBJECT_NOTIFICATION_CLASS,
|
||||||
Notification_Class_Count,
|
Notification_Class_Init,
|
||||||
Notification_Class_Index_To_Instance,
|
Notification_Class_Count,
|
||||||
Notification_Class_Valid_Instance,
|
Notification_Class_Index_To_Instance,
|
||||||
Notification_Class_Object_Name, Notification_Class_Read_Property,
|
Notification_Class_Valid_Instance,
|
||||||
Notification_Class_Write_Property,
|
Notification_Class_Object_Name,
|
||||||
Notification_Class_Property_Lists,
|
Notification_Class_Read_Property,
|
||||||
NULL, NULL, NULL, NULL}, {
|
Notification_Class_Write_Property,
|
||||||
|
Notification_Class_Property_Lists,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */},
|
||||||
#endif
|
#endif
|
||||||
OBJECT_LIFE_SAFETY_POINT, Life_Safety_Point_Init,
|
{OBJECT_LIFE_SAFETY_POINT,
|
||||||
Life_Safety_Point_Count,
|
Life_Safety_Point_Init,
|
||||||
Life_Safety_Point_Index_To_Instance,
|
Life_Safety_Point_Count,
|
||||||
Life_Safety_Point_Valid_Instance,
|
Life_Safety_Point_Index_To_Instance,
|
||||||
Life_Safety_Point_Object_Name, Life_Safety_Point_Read_Property,
|
Life_Safety_Point_Valid_Instance,
|
||||||
Life_Safety_Point_Write_Property, Life_Safety_Point_Property_Lists,
|
Life_Safety_Point_Object_Name,
|
||||||
NULL, NULL, NULL, NULL}, {
|
Life_Safety_Point_Read_Property,
|
||||||
OBJECT_LOAD_CONTROL, Load_Control_Init, Load_Control_Count,
|
Life_Safety_Point_Write_Property,
|
||||||
Load_Control_Index_To_Instance, Load_Control_Valid_Instance,
|
Life_Safety_Point_Property_Lists,
|
||||||
Load_Control_Object_Name, Load_Control_Read_Property,
|
NULL /* ReadRangeInfo */,
|
||||||
Load_Control_Write_Property, Load_Control_Property_Lists,
|
NULL /* Iterator */,
|
||||||
NULL, NULL, NULL, NULL}, {
|
NULL /* Value_Lists */,
|
||||||
OBJECT_MULTI_STATE_OUTPUT, Multistate_Output_Init,
|
NULL /* COV */,
|
||||||
Multistate_Output_Count,
|
NULL /* COV Clear */,
|
||||||
Multistate_Output_Index_To_Instance,
|
NULL /* Intrinsic Reporting */},
|
||||||
Multistate_Output_Valid_Instance,
|
{OBJECT_LOAD_CONTROL,
|
||||||
Multistate_Output_Object_Name, Multistate_Output_Read_Property,
|
Load_Control_Init,
|
||||||
Multistate_Output_Write_Property, Multistate_Output_Property_Lists,
|
Load_Control_Count,
|
||||||
NULL, NULL, NULL, NULL}, {
|
Load_Control_Index_To_Instance,
|
||||||
OBJECT_MULTI_STATE_INPUT, Multistate_Input_Init,
|
Load_Control_Valid_Instance,
|
||||||
Multistate_Input_Count,
|
Load_Control_Object_Name,
|
||||||
Multistate_Input_Index_To_Instance,
|
Load_Control_Read_Property,
|
||||||
Multistate_Input_Valid_Instance,
|
Load_Control_Write_Property,
|
||||||
Multistate_Input_Object_Name, Multistate_Input_Read_Property,
|
Load_Control_Property_Lists,
|
||||||
Multistate_Input_Write_Property, Multistate_Input_Property_Lists,
|
NULL /* ReadRangeInfo */,
|
||||||
NULL, NULL, NULL, NULL}, {
|
NULL /* Iterator */,
|
||||||
OBJECT_TRENDLOG, Trend_Log_Init, Trend_Log_Count,
|
NULL /* Value_Lists */,
|
||||||
Trend_Log_Index_To_Instance, Trend_Log_Valid_Instance,
|
NULL /* COV */,
|
||||||
Trend_Log_Object_Name, Trend_Log_Read_Property,
|
NULL /* COV Clear */,
|
||||||
Trend_Log_Write_Property, Trend_Log_Property_Lists,
|
NULL /* Intrinsic Reporting */},
|
||||||
TrendLogGetRRInfo, NULL, NULL, NULL}, {
|
{OBJECT_MULTI_STATE_OUTPUT,
|
||||||
|
Multistate_Output_Init,
|
||||||
|
Multistate_Output_Count,
|
||||||
|
Multistate_Output_Index_To_Instance,
|
||||||
|
Multistate_Output_Valid_Instance,
|
||||||
|
Multistate_Output_Object_Name,
|
||||||
|
Multistate_Output_Read_Property,
|
||||||
|
Multistate_Output_Write_Property,
|
||||||
|
Multistate_Output_Property_Lists,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */},
|
||||||
|
{OBJECT_MULTI_STATE_INPUT,
|
||||||
|
Multistate_Input_Init,
|
||||||
|
Multistate_Input_Count,
|
||||||
|
Multistate_Input_Index_To_Instance,
|
||||||
|
Multistate_Input_Valid_Instance,
|
||||||
|
Multistate_Input_Object_Name,
|
||||||
|
Multistate_Input_Read_Property,
|
||||||
|
Multistate_Input_Write_Property,
|
||||||
|
Multistate_Input_Property_Lists,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */},
|
||||||
|
{OBJECT_TRENDLOG,
|
||||||
|
Trend_Log_Init,
|
||||||
|
Trend_Log_Count,
|
||||||
|
Trend_Log_Index_To_Instance,
|
||||||
|
Trend_Log_Valid_Instance,
|
||||||
|
Trend_Log_Object_Name,
|
||||||
|
Trend_Log_Read_Property,
|
||||||
|
Trend_Log_Write_Property,
|
||||||
|
Trend_Log_Property_Lists,
|
||||||
|
TrendLogGetRRInfo,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */},
|
||||||
#if defined(BACFILE)
|
#if defined(BACFILE)
|
||||||
OBJECT_FILE, bacfile_init, bacfile_count,
|
{OBJECT_FILE,
|
||||||
bacfile_index_to_instance, bacfile_valid_instance,
|
bacfile_init,
|
||||||
bacfile_object_name, bacfile_read_property,
|
bacfile_count,
|
||||||
bacfile_write_property, BACfile_Property_Lists,
|
bacfile_index_to_instance,
|
||||||
NULL, NULL, NULL, NULL}, {
|
bacfile_valid_instance,
|
||||||
|
bacfile_object_name,
|
||||||
|
bacfile_read_property,
|
||||||
|
bacfile_write_property,
|
||||||
|
BACfile_Property_Lists,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */},
|
||||||
#endif
|
#endif
|
||||||
MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
{MAX_BACNET_OBJECT_TYPE,
|
||||||
NULL, NULL, NULL, NULL, NULL}
|
NULL /* Init */,
|
||||||
|
NULL /* Count */,
|
||||||
|
NULL /* Index_To_Instance */,
|
||||||
|
NULL /* Valid_Instance */,
|
||||||
|
NULL /* Object_Name */,
|
||||||
|
NULL /* Read_Property */,
|
||||||
|
NULL /* Write_Property */,
|
||||||
|
NULL /* Property_Lists */,
|
||||||
|
NULL /* ReadRangeInfo */,
|
||||||
|
NULL /* Iterator */,
|
||||||
|
NULL /* Value_Lists */,
|
||||||
|
NULL /* COV */,
|
||||||
|
NULL /* COV Clear */,
|
||||||
|
NULL /* Intrinsic Reporting */}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Glue function to let the Device object, when called by a handler,
|
/** Glue function to let the Device object, when called by a handler,
|
||||||
* lookup which Object type needs to be invoked.
|
* lookup which Object type needs to be invoked.
|
||||||
* @ingroup ObjHelpers
|
* @ingroup ObjHelpers
|
||||||
@@ -176,13 +298,12 @@ static struct object_functions *Device_Objects_Find_Functions(
|
|||||||
{
|
{
|
||||||
struct object_functions *pObject = NULL;
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
pObject = &Object_Table[0];
|
pObject = Object_Table;
|
||||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
/* handle each object type */
|
/* handle each object type */
|
||||||
if (pObject->Object_Type == Object_Type) {
|
if (pObject->Object_Type == Object_Type) {
|
||||||
return (pObject);
|
return (pObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
pObject++;
|
pObject++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,16 +462,16 @@ static const int Device_Properties_Required[] = {
|
|||||||
PROP_SEGMENTATION_SUPPORTED,
|
PROP_SEGMENTATION_SUPPORTED,
|
||||||
PROP_APDU_TIMEOUT,
|
PROP_APDU_TIMEOUT,
|
||||||
PROP_NUMBER_OF_APDU_RETRIES,
|
PROP_NUMBER_OF_APDU_RETRIES,
|
||||||
#if defined(BACDL_MSTP)
|
|
||||||
PROP_MAX_MASTER,
|
|
||||||
PROP_MAX_INFO_FRAMES,
|
|
||||||
#endif
|
|
||||||
PROP_DEVICE_ADDRESS_BINDING,
|
PROP_DEVICE_ADDRESS_BINDING,
|
||||||
PROP_DATABASE_REVISION,
|
PROP_DATABASE_REVISION,
|
||||||
-1
|
-1
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int Device_Properties_Optional[] = {
|
static const int Device_Properties_Optional[] = {
|
||||||
|
#if defined(BACDL_MSTP)
|
||||||
|
PROP_MAX_MASTER,
|
||||||
|
PROP_MAX_INFO_FRAMES,
|
||||||
|
#endif
|
||||||
PROP_DESCRIPTION,
|
PROP_DESCRIPTION,
|
||||||
PROP_LOCAL_TIME,
|
PROP_LOCAL_TIME,
|
||||||
PROP_UTC_OFFSET,
|
PROP_UTC_OFFSET,
|
||||||
@@ -744,7 +865,7 @@ unsigned Device_Object_List_Count(
|
|||||||
struct object_functions *pObject = NULL;
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
/* initialize the default return values */
|
/* initialize the default return values */
|
||||||
pObject = &Object_Table[0];
|
pObject = Object_Table;
|
||||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
if (pObject->Object_Count) {
|
if (pObject->Object_Count) {
|
||||||
count += pObject->Object_Count();
|
count += pObject->Object_Count();
|
||||||
@@ -782,7 +903,7 @@ bool Device_Object_List_Identifier(
|
|||||||
}
|
}
|
||||||
object_index = array_index - 1;
|
object_index = array_index - 1;
|
||||||
/* initialize the default return values */
|
/* initialize the default return values */
|
||||||
pObject = &Object_Table[0];
|
pObject = Object_Table;
|
||||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
if (pObject->Object_Count) {
|
if (pObject->Object_Count) {
|
||||||
object_index -= count;
|
object_index -= count;
|
||||||
@@ -887,7 +1008,7 @@ bool Device_Valid_Object_Id(
|
|||||||
* @return True on success or else False if not found.
|
* @return True on success or else False if not found.
|
||||||
*/
|
*/
|
||||||
bool Device_Object_Name_Copy(
|
bool Device_Object_Name_Copy(
|
||||||
BACNET_OBJECT_TYPE object_type,
|
BACNET_OBJECT_TYPE object_type,
|
||||||
uint32_t object_instance,
|
uint32_t object_instance,
|
||||||
BACNET_CHARACTER_STRING * object_name)
|
BACNET_CHARACTER_STRING * object_name)
|
||||||
{
|
{
|
||||||
@@ -1087,7 +1208,7 @@ int Device_Read_Property_Local(
|
|||||||
}
|
}
|
||||||
/* set the object types with objects to supported */
|
/* set the object types with objects to supported */
|
||||||
|
|
||||||
pObject = &Object_Table[0];
|
pObject = Object_Table;
|
||||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) {
|
if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) {
|
||||||
bitstring_set_bit(&bit_string, pObject->Object_Type, true);
|
bitstring_set_bit(&bit_string, pObject->Object_Type, true);
|
||||||
@@ -1206,7 +1327,7 @@ int Device_Read_Property_Local(
|
|||||||
* If the Object or Property can't be found, sets the error class and code.
|
* If the Object or Property can't be found, sets the error class and code.
|
||||||
*
|
*
|
||||||
* @param rpdata [in,out] Structure with the desired Object and Property info
|
* @param rpdata [in,out] Structure with the desired Object and Property info
|
||||||
* on entry, and APDU message on return.
|
* on entry, and APDU message on return.
|
||||||
* @return The length of the APDU on success, else BACNET_STATUS_ERROR
|
* @return The length of the APDU on success, else BACNET_STATUS_ERROR
|
||||||
*/
|
*/
|
||||||
int Device_Read_Property(
|
int Device_Read_Property(
|
||||||
@@ -1483,6 +1604,43 @@ bool Device_Encode_Value_List(
|
|||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Device_COV(
|
||||||
|
BACNET_OBJECT_TYPE object_type,
|
||||||
|
uint32_t object_instance)
|
||||||
|
{
|
||||||
|
bool status = false; /* Ever the pessamist! */
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
pObject = Device_Objects_Find_Functions(object_type);
|
||||||
|
if (pObject != NULL) {
|
||||||
|
if (pObject->Object_Valid_Instance &&
|
||||||
|
pObject->Object_Valid_Instance(object_instance)) {
|
||||||
|
if (pObject->Object_COV) {
|
||||||
|
status = pObject->Object_COV(
|
||||||
|
object_instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device_COV_Clear(
|
||||||
|
BACNET_OBJECT_TYPE object_type,
|
||||||
|
uint32_t object_instance)
|
||||||
|
{
|
||||||
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
|
pObject = Device_Objects_Find_Functions(object_type);
|
||||||
|
if (pObject != NULL) {
|
||||||
|
if (pObject->Object_Valid_Instance &&
|
||||||
|
pObject->Object_Valid_Instance(object_instance)) {
|
||||||
|
if (pObject->Object_COV_Clear) {
|
||||||
|
pObject->Object_COV_Clear(object_instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(INTRINSIC_REPORTING)
|
#if defined(INTRINSIC_REPORTING)
|
||||||
void Device_local_reporting(
|
void Device_local_reporting(
|
||||||
@@ -1548,10 +1706,12 @@ void Device_Init(
|
|||||||
struct object_functions *pObject = NULL;
|
struct object_functions *pObject = NULL;
|
||||||
|
|
||||||
characterstring_init_ansi(&My_Object_Name, "SimpleServer");
|
characterstring_init_ansi(&My_Object_Name, "SimpleServer");
|
||||||
/* we don't use the object table passed in
|
if (object_table) {
|
||||||
since there is extra stuff we don't need in there. */
|
Object_Table = object_table;
|
||||||
(void) object_table;
|
} else {
|
||||||
pObject = &Object_Table[0];
|
Object_Table = &My_Object_Table[0];
|
||||||
|
}
|
||||||
|
pObject = Object_Table;
|
||||||
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
|
||||||
if (pObject->Object_Init) {
|
if (pObject->Object_Init) {
|
||||||
pObject->Object_Init();
|
pObject->Object_Init();
|
||||||
@@ -1625,7 +1785,7 @@ void Routing_Device_Init(
|
|||||||
Add_Routed_Device(first_object_instance, &My_Object_Name, Description);
|
Add_Routed_Device(first_object_instance, &My_Object_Name, Description);
|
||||||
|
|
||||||
/* Now substitute our routed versions of the main object functions. */
|
/* Now substitute our routed versions of the main object functions. */
|
||||||
pDevObject = &Object_Table[0];
|
pDevObject = Object_Table;
|
||||||
pDevObject->Object_Index_To_Instance = Routed_Device_Index_To_Instance;
|
pDevObject->Object_Index_To_Instance = Routed_Device_Index_To_Instance;
|
||||||
pDevObject->Object_Valid_Instance =
|
pDevObject->Object_Valid_Instance =
|
||||||
Routed_Device_Valid_Object_Instance_Number;
|
Routed_Device_Valid_Object_Instance_Number;
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ typedef uint32_t(
|
|||||||
* @param object_name [in,out] Pointer to a character_string structure that
|
* @param object_name [in,out] Pointer to a character_string structure that
|
||||||
* will hold a copy of the object name if this is a valid object_instance.
|
* will hold a copy of the object name if this is a valid object_instance.
|
||||||
* @return True if the object_instance is valid and object_name has been
|
* @return True if the object_instance is valid and object_name has been
|
||||||
* filled with a copy of the Object's name.
|
* filled with a copy of the Object's name.
|
||||||
*/
|
*/
|
||||||
typedef bool(
|
typedef bool(
|
||||||
*object_name_function)
|
*object_name_function)
|
||||||
@@ -113,6 +113,23 @@ typedef bool(
|
|||||||
uint32_t object_instance,
|
uint32_t object_instance,
|
||||||
BACNET_PROPERTY_VALUE * value_list);
|
BACNET_PROPERTY_VALUE * value_list);
|
||||||
|
|
||||||
|
/** Look in the table of objects for this instance to see if value changed.
|
||||||
|
* @ingroup ObjHelpers
|
||||||
|
* @param [in] The object instance number to be looked up.
|
||||||
|
* @return True if the object instance has changed.
|
||||||
|
*/
|
||||||
|
typedef bool(
|
||||||
|
*object_cov_function) (
|
||||||
|
uint32_t object_instance);
|
||||||
|
|
||||||
|
/** Look in the table of objects for this instance to clear the changed flag.
|
||||||
|
* @ingroup ObjHelpers
|
||||||
|
* @param [in] The object instance number to be looked up.
|
||||||
|
*/
|
||||||
|
typedef void(
|
||||||
|
*object_cov_clear_function) (
|
||||||
|
uint32_t object_instance);
|
||||||
|
|
||||||
/** Intrinsic Reporting funcionality.
|
/** Intrinsic Reporting funcionality.
|
||||||
* @ingroup ObjHelpers
|
* @ingroup ObjHelpers
|
||||||
* @param [in] Object instance.
|
* @param [in] Object instance.
|
||||||
@@ -127,7 +144,7 @@ typedef void (
|
|||||||
* Each Object must provide some implementation of each of these helpers
|
* Each Object must provide some implementation of each of these helpers
|
||||||
* in order to properly support the handlers. Eg, the ReadProperty handler
|
* in order to properly support the handlers. Eg, the ReadProperty handler
|
||||||
* handler_read_property() relies on the instance of Object_Read_Property
|
* handler_read_property() relies on the instance of Object_Read_Property
|
||||||
* for each Object type.
|
* for each Object type, or configure the function as NULL.
|
||||||
* In both appearance and operation, this group of functions acts like
|
* In both appearance and operation, this group of functions acts like
|
||||||
* they are member functions of a C++ Object base class.
|
* they are member functions of a C++ Object base class.
|
||||||
*/
|
*/
|
||||||
@@ -144,6 +161,8 @@ typedef struct object_functions {
|
|||||||
rr_info_function Object_RR_Info;
|
rr_info_function Object_RR_Info;
|
||||||
object_iterate_function Object_Iterator;
|
object_iterate_function Object_Iterator;
|
||||||
object_value_list_function Object_Value_List;
|
object_value_list_function Object_Value_List;
|
||||||
|
object_cov_function Object_COV;
|
||||||
|
object_cov_clear_function Object_COV_Clear;
|
||||||
object_intrinsic_reporting_function Object_Intrinsic_Reporting;
|
object_intrinsic_reporting_function Object_Intrinsic_Reporting;
|
||||||
} object_functions_t;
|
} object_functions_t;
|
||||||
|
|
||||||
@@ -224,13 +243,19 @@ extern "C" {
|
|||||||
void Device_Objects_Property_List(
|
void Device_Objects_Property_List(
|
||||||
BACNET_OBJECT_TYPE object_type,
|
BACNET_OBJECT_TYPE object_type,
|
||||||
struct special_property_list_t *pPropertyList);
|
struct special_property_list_t *pPropertyList);
|
||||||
|
/* functions to support COV */
|
||||||
bool Device_Encode_Value_List(
|
bool Device_Encode_Value_List(
|
||||||
BACNET_OBJECT_TYPE object_type,
|
BACNET_OBJECT_TYPE object_type,
|
||||||
uint32_t object_instance,
|
uint32_t object_instance,
|
||||||
BACNET_PROPERTY_VALUE * value_list);
|
BACNET_PROPERTY_VALUE * value_list);
|
||||||
bool Device_Value_List_Supported(
|
bool Device_Value_List_Supported(
|
||||||
BACNET_OBJECT_TYPE object_type);
|
BACNET_OBJECT_TYPE object_type);
|
||||||
|
bool Device_COV(
|
||||||
|
BACNET_OBJECT_TYPE object_type,
|
||||||
|
uint32_t object_instance);
|
||||||
|
void Device_COV_Clear(
|
||||||
|
BACNET_OBJECT_TYPE object_type,
|
||||||
|
uint32_t object_instance);
|
||||||
|
|
||||||
uint32_t Device_Object_Instance_Number(
|
uint32_t Device_Object_Instance_Number(
|
||||||
void);
|
void);
|
||||||
@@ -401,11 +426,7 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define DEVICE_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_DEVICE, NULL, Device_Count, Device_Index_To_Instance, \
|
|
||||||
Device_Valid_Object_Instance_Number, Device_Object_Name, \
|
|
||||||
Device_Read_Property_Local, Device_Write_Property_Local, \
|
|
||||||
Device_Property_Lists, DeviceGetRRInfo, NULL, NULL
|
|
||||||
/** @defgroup ObjFrmwk Object Framework
|
/** @defgroup ObjFrmwk Object Framework
|
||||||
* The modules in this section describe the BACnet-stack's framework for
|
* The modules in this section describe the BACnet-stack's framework for
|
||||||
* BACnet-defined Objects (Device, Analog Input, etc). There are two submodules
|
* BACnet-defined Objects (Device, Analog Input, etc). There are two submodules
|
||||||
@@ -415,11 +436,15 @@ extern "C" {
|
|||||||
* - The interface between the implemented Objects and the BAC-stack services,
|
* - The interface between the implemented Objects and the BAC-stack services,
|
||||||
* specifically the handlers, which are mediated through function calls to
|
* specifically the handlers, which are mediated through function calls to
|
||||||
* the Device object.
|
* the Device object.
|
||||||
*//** @defgroup ObjHelpers Object Helper Functions
|
*/
|
||||||
|
|
||||||
|
/** @defgroup ObjHelpers Object Helper Functions
|
||||||
* @ingroup ObjFrmwk
|
* @ingroup ObjFrmwk
|
||||||
* This section describes the function templates for the helper functions that
|
* This section describes the function templates for the helper functions that
|
||||||
* provide common object support.
|
* provide common object support.
|
||||||
*//** @defgroup ObjIntf Handler-to-Object Interface Functions
|
*/
|
||||||
|
|
||||||
|
/** @defgroup ObjIntf Handler-to-Object Interface Functions
|
||||||
* @ingroup ObjFrmwk
|
* @ingroup ObjFrmwk
|
||||||
* This section describes the fairly limited set of functions that link the
|
* This section describes the fairly limited set of functions that link the
|
||||||
* BAC-stack handlers to the BACnet Object instances. All of these calls are
|
* BAC-stack handlers to the BACnet Object instances. All of these calls are
|
||||||
|
|||||||
@@ -76,10 +76,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define LOAD_CONTROL_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_LOAD_CONTROL, Load_Control_Init, Load_Control_Count, \
|
|
||||||
Load_Control_Index_To_Instance, Load_Control_Valid_Instance, \
|
|
||||||
Load_Control_Object_Name, Load_Control_Read_Property, \
|
|
||||||
Load_Control_Write_Property, Load_Control_Property_Lists, NULL, \
|
|
||||||
NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -69,11 +69,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define LIFE_SAFETY_POINT_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_LIFE_SAFETY_POINT, Life_Safety_Point_Init, \
|
|
||||||
Life_Safety_Point_Count, Life_Safety_Point_Index_To_Instance, \
|
|
||||||
Life_Safety_Point_Valid_Instance, Life_Safety_Point_Object_Name, \
|
|
||||||
Life_Safety_Point_Read_Property, \
|
|
||||||
Life_Safety_Point_Write_Property, \
|
|
||||||
Life_Safety_Point_Property_Lists, NULL, NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -96,11 +96,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define MULTI_STATE_INPUT_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_MULTI_STATE_INPUT, Multistate_Input_Init, \
|
|
||||||
Multistate_Input_Count, Multistate_Input_Index_To_Instance, \
|
|
||||||
Multistate_Input_Valid_Instance, Multistate_Input_Object_Name, \
|
|
||||||
Multistate_Input_Read_Property, \
|
|
||||||
Multistate_Input_Write_Property, \
|
|
||||||
Multistate_Input_Property_Lists, NULL, NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -71,11 +71,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define MULTI_STATE_OUTPUT_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_MULTI_STATE_OUTPUT, Multistate_Output_Init, \
|
|
||||||
Multistate_Output_Count, Multistate_Output_Index_To_Instance, \
|
|
||||||
Multistate_Output_Valid_Instance, Multistate_Output_Object_Name, \
|
|
||||||
Multistate_Output_Read_Property, \
|
|
||||||
Multistate_Output_Write_Property, \
|
|
||||||
Multistate_Output_Property_Lists, NULL, NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -138,10 +138,5 @@ BACnetRecipient ::= CHOICE {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define NOTIFICATION_CLASS_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_NOTIFICATION_CLASS, Notification_Class_Init, Notification_Class_Count, \
|
|
||||||
Notification_Class_Index_To_Instance, Notification_Class_Valid_Instance, \
|
|
||||||
Notification_Class_Object_Name, Notification_Class_Read_Property, \
|
|
||||||
Notification_Class_Write_Property, Notification_Class_Property_Lists, \
|
|
||||||
NULL, NULL, NULL
|
|
||||||
#endif /* NC_H */
|
#endif /* NC_H */
|
||||||
|
|||||||
@@ -197,10 +197,5 @@ extern "C" {
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#define TRENDLOG_OBJ_FUNCTIONS \
|
|
||||||
OBJECT_TRENDLOG, Trend_Log_Init, Trend_Log_Count, \
|
|
||||||
Trend_Log_Index_To_Instance, Trend_Log_Valid_Instance, \
|
|
||||||
Trend_Log_Object_Name, Trend_Log_Read_Property, \
|
|
||||||
Trend_Log_Write_Property, Trend_Log_Property_Lists, \
|
|
||||||
TrendLogGetRRInfo, NULL, NULL
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,37 +1,44 @@
|
|||||||
#Makefile to build BACnet Application for the Linux Port
|
#Makefile to build BACnet Application using GCC compiler
|
||||||
|
|
||||||
# tools - only if you need them.
|
# tools - only if you need them.
|
||||||
# Most platforms have this already defined
|
# Most platforms have this already defined
|
||||||
# CC = gcc
|
# CC = gcc
|
||||||
|
# AR = ar
|
||||||
TARGET = ptransfer
|
# MAKE = make
|
||||||
|
# SIZE = size
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
#
|
||||||
|
# Assumes rm and cp are available
|
||||||
SRCS = main.c
|
|
||||||
|
# Executable file name
|
||||||
OBJS = ${SRCS:.c=.o}
|
TARGET = ptransfer
|
||||||
|
|
||||||
all: ${BACNET_LIB_TARGET} Makefile ${TARGET_BIN}
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
${TARGET_BIN}: ${OBJS} Makefile ${BACNET_LIB_TARGET}
|
SRCS = main.c \
|
||||||
${CC} ${PFLAGS} ${OBJS} ${LFLAGS} -o $@
|
../object/device-client.c
|
||||||
size $@
|
|
||||||
cp $@ ../../bin
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
lib: ${BACNET_LIB_TARGET}
|
all: ${BACNET_LIB_TARGET} Makefile ${TARGET_BIN}
|
||||||
|
|
||||||
${BACNET_LIB_TARGET}:
|
${TARGET_BIN}: ${OBJS} Makefile ${BACNET_LIB_TARGET}
|
||||||
( cd ${BACNET_LIB_DIR} ; $(MAKE) clean ; $(MAKE) )
|
${CC} ${PFLAGS} ${OBJS} ${LFLAGS} -o $@
|
||||||
|
size $@
|
||||||
.c.o:
|
cp $@ ../../bin
|
||||||
${CC} -c ${CFLAGS} $*.c -o $@
|
|
||||||
|
lib: ${BACNET_LIB_TARGET}
|
||||||
depend:
|
|
||||||
rm -f .depend
|
${BACNET_LIB_TARGET}:
|
||||||
${CC} -MM ${CFLAGS} *.c >> .depend
|
( cd ${BACNET_LIB_DIR} ; $(MAKE) clean ; $(MAKE) )
|
||||||
|
|
||||||
clean:
|
.c.o:
|
||||||
rm -f core ${TARGET_BIN} ${OBJS} ${BACNET_LIB_TARGET} $(TARGET).map
|
${CC} -c ${CFLAGS} $*.c -o $@
|
||||||
|
|
||||||
include: .depend
|
depend:
|
||||||
|
rm -f .depend
|
||||||
|
${CC} -MM ${CFLAGS} *.c >> .depend
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf core ${TARGET_BIN} ${OBJS} ${BACNET_LIB_TARGET}
|
||||||
|
|
||||||
|
include: .depend
|
||||||
|
|||||||
@@ -68,13 +68,6 @@ uint8_t Send_Private_Transfer_Request(
|
|||||||
char block_number,
|
char block_number,
|
||||||
DATABLOCK * block);
|
DATABLOCK * block);
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -132,7 +125,7 @@ void MyRejectHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ TARGET = bacarf
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -50,13 +50,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -186,7 +179,7 @@ static void LocalIAmHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ TARGET = bacrp
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -53,13 +53,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -150,7 +143,7 @@ void My_Read_Property_Ack_Handler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ TARGET = bacrpm
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -54,13 +54,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -195,7 +188,7 @@ void My_Read_Property_Multiple_Ack_Handler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -80,13 +80,6 @@
|
|||||||
#define _stricmp stricmp
|
#define _stricmp stricmp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -144,7 +137,7 @@ void MyRejectHandler(
|
|||||||
static void Init_Objects(
|
static void Init_Objects(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ TARGET = bacrd
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -51,13 +51,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -121,7 +114,7 @@ void MyReinitializeDeviceSimpleAckHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ TARGET = bacscov
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -54,13 +54,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -121,7 +114,7 @@ void MyRejectHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ BUILD_DEFINE = -DMAX_PROPERTY_VALUES=64
|
|||||||
|
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) $(BUILD_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) $(BUILD_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,9 @@ static void Init_Service_Handlers(
|
|||||||
/* handle communication so we can shutup when asked */
|
/* handle communication so we can shutup when asked */
|
||||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||||
handler_device_communication_control);
|
handler_device_communication_control);
|
||||||
|
/* handle the data coming back from private requests */
|
||||||
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_PRIVATE_TRANSFER,
|
||||||
|
handler_unconfirmed_private_transfer);
|
||||||
#if defined(INTRINSIC_REPORTING)
|
#if defined(INTRINSIC_REPORTING)
|
||||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM,
|
apdu_set_confirmed_handler(SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM,
|
||||||
handler_alarm_ack);
|
handler_alarm_ack);
|
||||||
@@ -202,15 +205,16 @@ int main(
|
|||||||
dlenv_maintenance_timer(elapsed_seconds);
|
dlenv_maintenance_timer(elapsed_seconds);
|
||||||
Load_Control_State_Machine_Handler();
|
Load_Control_State_Machine_Handler();
|
||||||
elapsed_milliseconds = elapsed_seconds * 1000;
|
elapsed_milliseconds = elapsed_seconds * 1000;
|
||||||
if (dcc_communication_enabled()) {
|
handler_cov_timer_seconds(elapsed_seconds);
|
||||||
handler_cov_task(elapsed_seconds);
|
|
||||||
}
|
|
||||||
tsm_timer_milliseconds(elapsed_milliseconds);
|
tsm_timer_milliseconds(elapsed_milliseconds);
|
||||||
trend_log_timer(elapsed_seconds);
|
trend_log_timer(elapsed_seconds);
|
||||||
#if defined(INTRINSIC_REPORTING)
|
#if defined(INTRINSIC_REPORTING)
|
||||||
Device_local_reporting();
|
Device_local_reporting();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (dcc_communication_enabled()) {
|
||||||
|
handler_cov_task();
|
||||||
|
}
|
||||||
/* scan cache address */
|
/* scan cache address */
|
||||||
address_binding_tmr += elapsed_seconds;
|
address_binding_tmr += elapsed_seconds;
|
||||||
if (address_binding_tmr >= 60) {
|
if (address_binding_tmr >= 60) {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ TARGET = bacts
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -46,13 +46,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -93,7 +86,7 @@ void MyRejectHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ TARGET = bacucov
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -50,17 +50,10 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ TARGET = bacupt
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -54,13 +54,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -124,74 +117,10 @@ void MyRejectHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyUnconfirmedPrivateTransferHandler(
|
|
||||||
uint8_t * service_request,
|
|
||||||
uint16_t service_len,
|
|
||||||
BACNET_ADDRESS * src)
|
|
||||||
{
|
|
||||||
BACNET_PRIVATE_TRANSFER_DATA private_data;
|
|
||||||
BACNET_OBJECT_PROPERTY_VALUE object_value; /* for bacapp printing */
|
|
||||||
BACNET_APPLICATION_DATA_VALUE value; /* for decode value data */
|
|
||||||
int len = 0;
|
|
||||||
uint8_t *application_data;
|
|
||||||
int application_data_len;
|
|
||||||
bool first_value = true;
|
|
||||||
bool print_brace = false;
|
|
||||||
|
|
||||||
len = ptransfer_decode_service_request(
|
|
||||||
service_request, service_len, &private_data);
|
|
||||||
if (len >= 0) {
|
|
||||||
printf("PrivateTransfer:vendorID=%u\r\n",
|
|
||||||
(unsigned)private_data.vendorID);
|
|
||||||
printf("PrivateTransfer:serviceNumber=%lu\r\n",
|
|
||||||
(unsigned long)private_data.serviceNumber);
|
|
||||||
application_data = private_data.serviceParameters;
|
|
||||||
application_data_len = private_data.serviceParametersLen;
|
|
||||||
for (;;) {
|
|
||||||
len =
|
|
||||||
bacapp_decode_application_data(application_data,
|
|
||||||
(uint8_t) application_data_len, &value);
|
|
||||||
if (first_value && (len < application_data_len)) {
|
|
||||||
first_value = false;
|
|
||||||
#if PRINT_ENABLED
|
|
||||||
fprintf(stdout, "{");
|
|
||||||
#endif
|
|
||||||
print_brace = true;
|
|
||||||
}
|
|
||||||
/* private transfer doesn't provide any clues */
|
|
||||||
object_value.object_type = MAX_BACNET_OBJECT_TYPE;
|
|
||||||
object_value.object_instance = BACNET_MAX_INSTANCE;
|
|
||||||
object_value.object_property = MAX_BACNET_PROPERTY_ID;
|
|
||||||
object_value.array_index = BACNET_ARRAY_ALL;
|
|
||||||
object_value.value = &value;
|
|
||||||
bacapp_print_value(stdout, &object_value);
|
|
||||||
if (len > 0) {
|
|
||||||
if (len < application_data_len) {
|
|
||||||
application_data += len;
|
|
||||||
application_data_len -= len;
|
|
||||||
/* there's more! */
|
|
||||||
#if PRINT_ENABLED
|
|
||||||
fprintf(stdout, ",");
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if PRINT_ENABLED
|
|
||||||
if (print_brace)
|
|
||||||
fprintf(stdout, "}");
|
|
||||||
fprintf(stdout, "\r\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
@@ -204,9 +133,9 @@ static void Init_Service_Handlers(
|
|||||||
/* we must implement read property - it's required! */
|
/* we must implement read property - it's required! */
|
||||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
|
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
|
||||||
handler_read_property);
|
handler_read_property);
|
||||||
/* handle the data coming back from confirmed requests */
|
/* handle the data coming back from requests */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_PRIVATE_TRANSFER,
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_PRIVATE_TRANSFER,
|
||||||
MyUnconfirmedPrivateTransferHandler);
|
handler_unconfirmed_private_transfer);
|
||||||
/* handle any errors coming back */
|
/* handle any errors coming back */
|
||||||
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
|
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
|
||||||
apdu_set_abort_handler(MyAbortHandler);
|
apdu_set_abort_handler(MyAbortHandler);
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ BUILD_DEFINE = -DMAX_PROPERTY_VALUES=64
|
|||||||
|
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) $(BUILD_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) $(BUILD_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ TARGET = bacwh
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -50,13 +50,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -96,7 +89,7 @@ void MyRejectHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ TARGET = bacwi
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -50,13 +50,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -97,7 +90,7 @@ void MyRejectHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* Note: this applications doesn't need to handle who-is
|
/* Note: this applications doesn't need to handle who-is
|
||||||
it is confusing for the user! */
|
it is confusing for the user! */
|
||||||
/* set the handler for all the services we don't implement
|
/* set the handler for all the services we don't implement
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ TARGET = bacwir
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -51,12 +51,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -175,7 +169,7 @@ void My_NPDU_Handler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ TARGET = bacawf
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -50,13 +50,6 @@
|
|||||||
#include "txbuf.h"
|
#include "txbuf.h"
|
||||||
#include "dlenv.h"
|
#include "dlenv.h"
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -140,7 +133,7 @@ static void LocalIAmHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL
|
|||||||
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
BACDL_DEFINE=-DBACDL_BIP=1 -DUSE_INADDR=1
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ TARGET = bacwp
|
|||||||
|
|
||||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
../object/device-client.c
|
||||||
|
|
||||||
OBJS = ${SRCS:.c=.o}
|
OBJS = ${SRCS:.c=.o}
|
||||||
|
|
||||||
|
|||||||
@@ -56,13 +56,6 @@
|
|||||||
#define MAX_PROPERTY_VALUES 64
|
#define MAX_PROPERTY_VALUES 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL,
|
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -141,7 +134,7 @@ void MyWritePropertySimpleAckHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Init(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
/* we need to handle who-is
|
/* we need to handle who-is
|
||||||
to support dynamic device binding to us */
|
to support dynamic device binding to us */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ WRITEPROPS_DEFINE = -DMAX_PROPERTY_VALUES=64
|
|||||||
|
|
||||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) $(WRITEPROPS_DEFINE)
|
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE) $(WRITEPROPS_DEFINE)
|
||||||
|
|
||||||
SRCS = main.c
|
SRCS = main.c \
|
||||||
|
$(BACNET_OBJECT)\device-client.c
|
||||||
|
|
||||||
OBJS = $(SRCS:.c=.obj)
|
OBJS = $(SRCS:.c=.obj)
|
||||||
|
|
||||||
|
|||||||
@@ -215,7 +215,8 @@ extern "C" {
|
|||||||
uint16_t service_len,
|
uint16_t service_len,
|
||||||
BACNET_ADDRESS * src,
|
BACNET_ADDRESS * src,
|
||||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||||
void handler_cov_task(
|
void handler_cov_task(void);
|
||||||
|
void handler_cov_timer_seconds(
|
||||||
uint32_t elapsed_seconds);
|
uint32_t elapsed_seconds);
|
||||||
void handler_cov_init(
|
void handler_cov_init(
|
||||||
void);
|
void);
|
||||||
|
|||||||
@@ -59,26 +59,6 @@
|
|||||||
#include "bacfile.h"
|
#include "bacfile.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* All included BACnet objects */
|
|
||||||
static object_functions_t Object_Table[] = {
|
|
||||||
{DEVICE_OBJ_FUNCTIONS},
|
|
||||||
{ANALOG_INPUT_OBJ_FUNCTIONS},
|
|
||||||
{ANALOG_OUTPUT_OBJ_FUNCTIONS},
|
|
||||||
{ANALOG_VALUE_OBJ_FUNCTIONS},
|
|
||||||
{BINARY_INPUT_OBJ_FUNCTIONS},
|
|
||||||
{BINARY_OUTPUT_OBJ_FUNCTIONS},
|
|
||||||
{BINARY_VALUE_OBJ_FUNCTIONS},
|
|
||||||
{LIFE_SAFETY_POINT_OBJ_FUNCTIONS},
|
|
||||||
{LOAD_CONTROL_OBJ_FUNCTIONS},
|
|
||||||
{MULTI_STATE_OUTPUT_OBJ_FUNCTIONS},
|
|
||||||
{MULTI_STATE_INPUT_OBJ_FUNCTIONS},
|
|
||||||
{TRENDLOG_OBJ_FUNCTIONS},
|
|
||||||
#if defined(BACFILE)
|
|
||||||
{FILE_OBJ_FUNCTIONS},
|
|
||||||
#endif
|
|
||||||
{MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* buffer used for receive */
|
/* buffer used for receive */
|
||||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||||
|
|
||||||
@@ -189,8 +169,7 @@ static void LocalIAmHandler(
|
|||||||
static void Init_Service_Handlers(
|
static void Init_Service_Handlers(
|
||||||
void)
|
void)
|
||||||
{
|
{
|
||||||
Device_Initialize_Object_Functions(&Object_Table[0]);
|
Device_Init(NULL);
|
||||||
Device_Init();
|
|
||||||
|
|
||||||
/* we need to handle who-is to support dynamic device binding */
|
/* we need to handle who-is to support dynamic device binding */
|
||||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||||
|
|||||||
Reference in New Issue
Block a user