Created I-Have service encoding/decoding/unit test.

Added handlers for I-Have and Who-Has.
Added send for I-Have and Who-Has.
Created demo for WhoHas.
Added I-Have handling in server demo.
This commit is contained in:
skarg
2006-02-16 21:35:06 +00:00
parent b07b27e6ea
commit 5fcf45a781
24 changed files with 1383 additions and 54 deletions
+20 -2
View File
@@ -1,6 +1,6 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
* Copyright (C) 2006 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
@@ -37,10 +37,28 @@
extern "C" {
#endif /* __cplusplus */
/* unconfirmed requests */
void Send_WhoIs(
int32_t low_limit,
int32_t high_limit);
void Send_WhoHas_Object(
int32_t low_limit,
int32_t high_limit,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance);
void Send_WhoHas_Name(
int32_t low_limit,
int32_t high_limit,
char *object_name);
void Send_I_Have(
uint32_t device_id,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
char *object_name);
/* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Read_Property_Request(
uint32_t device_id, /* destination device */
@@ -71,7 +89,7 @@ uint8_t Send_Device_Communication_Control_Request(
uint16_t timeDuration, /* 0=optional */
BACNET_COMMUNICATION_ENABLE_DISABLE state,
char *password); /* NULL=optional */
#ifdef __cplusplus
}
#endif /* __cplusplus */
+62
View File
@@ -0,0 +1,62 @@
/**************************************************************************
*
* Copyright (C) 2006 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.
*
*********************************************************************/
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "config.h"
#include "txbuf.h"
#include "bacdef.h"
#include "bacdcode.h"
#include "bactext.h"
#include "ihave.h"
void handler_i_have(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src)
{
int len = 0;
BACNET_I_HAVE_DATA data;
(void)service_len;
(void)src;
len = ihave_decode_service_request(
service_request,
service_len,
&data);
if (len != -1)
{
fprintf(stderr,"I-Have: %s %d from %s %u!\r\n",
bactext_object_type_name(data.object_id.type),
data.object_id.instance,
bactext_object_type_name(data.device_id.type),
data.device_id.instance);
}
else
fprintf(stderr,"I-Have: received, but unable to decode!\n");
return;
}
+99
View File
@@ -0,0 +1,99 @@
/**************************************************************************
*
* Copyright (C) 2006 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.
*
*********************************************************************/
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "config.h"
#include "txbuf.h"
#include "bacdef.h"
#include "bacdcode.h"
#include "whohas.h"
#include "device.h"
#include "client.h"
void handler_who_has(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src)
{
int len = 0;
BACNET_WHO_HAS_DATA data;
bool directed_to_me = false;
int object_type = 0;
uint32_t object_instance = 0;
char *object_name = NULL;
bool found = false;
(void)src;
len = whohas_decode_service_request(
service_request,
service_len,
&data);
if (len > 0)
{
if ((data.low_limit == -1) || (data.high_limit == -1))
directed_to_me = true;
else if ((Device_Object_Instance_Number() >= (uint32_t)data.low_limit) &&
(Device_Object_Instance_Number() <= (uint32_t)data.high_limit))
directed_to_me = true;
if (directed_to_me)
{
/* do we have such an object? If so, send an I-Have.
note: we should have only 1 of such an object */
if (data.object_name)
{
/* valid name in my device? */
object_name = characterstring_value(&data.object.name);
found = Device_Valid_Object_Name(
object_name,
&object_type,
&object_instance);
if (found)
Send_I_Have(
Device_Object_Instance_Number(),
object_type,
object_instance,
object_name);
}
else
{
/* valid object in my device? */
object_name = Device_Valid_Object_Id(
data.object.identifier.type,
data.object.identifier.instance);
if (object_name)
Send_I_Have(
Device_Object_Instance_Number(),
data.object.identifier.type,
data.object.identifier.instance,
object_name);
}
}
}
return;
}
+11 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
* Copyright (C) 2005-2006 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
@@ -49,6 +49,11 @@ void handler_who_is(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src);
void handler_who_has(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src);
void handler_i_am_add(
uint8_t *service_request,
@@ -102,6 +107,11 @@ void handler_device_communication_control(
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void handler_i_have(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+85
View File
@@ -0,0 +1,85 @@
/**************************************************************************
*
* Copyright (C) 2006 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.
*
*********************************************************************/
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
#include "config.h"
#include "config.h"
#include "txbuf.h"
#include "bacdef.h"
#include "bacdcode.h"
#include "address.h"
#include "tsm.h"
#include "npdu.h"
#include "apdu.h"
#include "device.h"
#include "datalink.h"
#include "dcc.h"
#include "ihave.h"
/* some demo stuff needed */
#include "handlers.h"
#include "txbuf.h"
/* find a specific device, or use -1 for limit if you want unlimited */
void Send_I_Have(
uint32_t device_id,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
char *object_name)
{
int pdu_len = 0;
BACNET_ADDRESS dest;
int bytes_sent = 0;
BACNET_I_HAVE_DATA data;
/* if we are forbidden to send, don't send! */
if (!dcc_communication_enabled())
return;
/* Who-Has is a global broadcast */
datalink_get_broadcast_address(&dest);
/* encode the NPDU portion of the packet */
pdu_len = npdu_encode_apdu(
&Handler_Transmit_Buffer[0],
&dest,
NULL,
false, /* true for confirmed messages */
MESSAGE_PRIORITY_NORMAL);
/* encode the APDU portion of the packet */
data.device_id.type = OBJECT_DEVICE;
data.device_id.instance = device_id;
data.object_id.type = object_type;
data.object_id.instance = object_instance;
characterstring_init_ansi(&data.object_name,object_name);
pdu_len += ihave_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
&data);
/* send the data */
bytes_sent = datalink_send_pdu(
&dest, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send I-Have Reply (%s)!\n", strerror(errno));
}
+125
View File
@@ -0,0 +1,125 @@
/**************************************************************************
*
* Copyright (C) 2006 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.
*
*********************************************************************/
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
#include "config.h"
#include "config.h"
#include "txbuf.h"
#include "bacdef.h"
#include "bacdcode.h"
#include "address.h"
#include "tsm.h"
#include "npdu.h"
#include "apdu.h"
#include "device.h"
#include "datalink.h"
#include "dcc.h"
#include "whohas.h"
/* some demo stuff needed */
#include "handlers.h"
#include "txbuf.h"
/* find a specific device, or use -1 for limit if you want unlimited */
void Send_WhoHas_Name(
int32_t low_limit,
int32_t high_limit,
char *object_name)
{
int pdu_len = 0;
BACNET_ADDRESS dest;
int bytes_sent = 0;
BACNET_WHO_HAS_DATA data;
/* if we are forbidden to send, don't send! */
if (!dcc_communication_enabled())
return;
/* Who-Has is a global broadcast */
datalink_get_broadcast_address(&dest);
/* encode the NPDU portion of the packet */
pdu_len = npdu_encode_apdu(
&Handler_Transmit_Buffer[0],
&dest,
NULL,
false, /* true for confirmed messages */
MESSAGE_PRIORITY_NORMAL);
/* encode the APDU portion of the packet */
data.low_limit = low_limit;
data.high_limit = high_limit;
data.object_name = true;
characterstring_init_ansi(&data.object.name,object_name);
pdu_len += whohas_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
&data);
/* send the data */
bytes_sent = datalink_send_pdu(
&dest, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send Who-Has Request (%s)!\n", strerror(errno));
}
/* find a specific device, or use -1 for limit if you want unlimited */
void Send_WhoHas_Object(
int32_t low_limit,
int32_t high_limit,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance)
{
int pdu_len = 0;
BACNET_ADDRESS dest;
int bytes_sent = 0;
BACNET_WHO_HAS_DATA data;
/* if we are forbidden to send, don't send! */
if (!dcc_communication_enabled())
return;
/* Who-Has is a global broadcast */
datalink_get_broadcast_address(&dest);
/* encode the NPDU portion of the packet */
pdu_len = npdu_encode_apdu(
&Handler_Transmit_Buffer[0],
&dest,
NULL,
false, /* true for confirmed messages */
MESSAGE_PRIORITY_NORMAL);
/* encode the APDU portion of the packet */
data.low_limit = low_limit;
data.high_limit = high_limit;
data.object_name = false;
data.object.identifier.type = object_type;
data.object.identifier.instance = object_instance;
pdu_len += whohas_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
&data);
/* send the data */
bytes_sent = datalink_send_pdu(
&dest, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send Who-Has Request (%s)!\n", strerror(errno));
}
+15 -2
View File
@@ -61,7 +61,21 @@ uint32_t Analog_Input_Index_To_Instance(unsigned index)
return index;
}
char *Analog_Input_Name(uint32_t object_instance)
{
static char text_string[32] = ""; /* okay for single thread */
if (object_instance < MAX_ANALOG_INPUTS)
{
sprintf(text_string,"ANALOG INPUT %u",object_instance);
return text_string;
}
return NULL;
}
/* return apdu length, or -1 on error */
/* assumption - object has already exists */
int Analog_Input_Encode_Property_APDU(
uint8_t *apdu,
uint32_t object_instance,
@@ -85,8 +99,7 @@ int Analog_Input_Encode_Property_APDU(
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
sprintf(text_string,"ANALOG INPUT %u",object_instance);
characterstring_init_ansi(&char_string, text_string);
characterstring_init_ansi(&char_string, Analog_Input_Name(object_instance));
apdu_len = encode_tagged_character_string(&apdu[0],
&char_string);
break;
+1
View File
@@ -36,6 +36,7 @@ extern "C" {
bool Analog_Input_Valid_Instance(uint32_t object_instance);
unsigned Analog_Input_Count(void);
uint32_t Analog_Input_Index_To_Instance(unsigned index);
char *Analog_Input_Name(uint32_t object_instance);
int Analog_Input_Encode_Property_APDU(
uint8_t *apdu,
+15 -3
View File
@@ -141,6 +141,20 @@ static float Analog_Output_Present_Value(uint32_t object_instance)
return value;
}
/* note: the object name must be unique within this device */
char *Analog_Output_Name(uint32_t object_instance)
{
static char text_string[32] = ""; /* okay for single thread */
if (object_instance < MAX_ANALOG_OUTPUTS)
{
sprintf(text_string,"ANALOG OUTPUT %u",object_instance);
return text_string;
}
return NULL;
}
/* return apdu len, or -1 on error */
int Analog_Output_Encode_Property_APDU(
uint8_t *apdu,
@@ -168,9 +182,7 @@ int Analog_Output_Encode_Property_APDU(
break;
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
// note: the object name must be unique within this device
sprintf(text_string,"ANALOG OUTPUT %u",object_instance);
characterstring_init_ansi(&char_string, text_string);
characterstring_init_ansi(&char_string, Analog_Output_Name(object_instance));
apdu_len = encode_tagged_character_string(&apdu[0],
&char_string);
break;
+1
View File
@@ -38,6 +38,7 @@ extern "C" {
bool Analog_Output_Valid_Instance(uint32_t object_instance);
unsigned Analog_Output_Count(void);
uint32_t Analog_Output_Index_To_Instance(unsigned index);
char *Analog_Output_Name(uint32_t object_instance);
int Analog_Output_Encode_Property_APDU(
uint8_t *apdu,
+106 -36
View File
@@ -29,60 +29,65 @@
#include "bacdef.h"
#include "bacdcode.h"
#include "bacenum.h"
#include "config.h" // the custom stuff
#include "config.h" /* the custom stuff */
#include "apdu.h"
#include "ai.h" // object list dependency
#include "ao.h" // object list dependency
#include "wp.h" // write property handling
#include "ai.h" /* object list dependency */
#include "ao.h" /* object list dependency */
#include "wp.h" /* write property handling */
#include "device.h" /* me */
#if BACFILE
#include "bacfile.h" // object list dependency
#include "bacfile.h" /* object list dependency */
#endif
/* 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 = 0;
static char Object_Name[16] = "SimpleServer";
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
static char Vendor_Name[16] = "ASHRAE";
// vendor id assigned by ASHRAE
/* FIXME: your vendor id assigned by ASHRAE */
static uint16_t Vendor_Identifier = 0;
static char Model_Name[16] = "GNU";
static char Firmware_Revision[16] = "1.0";
static char Application_Software_Version[16] = "1.0";
static char Location[16] = "USA";
static char Description[16] = "server";
//static uint8_t Protocol_Version = 1; - constant, not settable
//static uint8_t Protocol_Revision = 4; - constant, not settable
//Protocol_Services_Supported
//Protocol_Object_Types_Supported
//Object_List
//static uint16_t Max_APDU_Length_Accepted = MAX_APDU; - constant
//static BACNET_SEGMENTATION Segmentation_Supported = SEGMENTATION_NONE;
//static uint8_t Max_Segments_Accepted = 0;
//VT_Classes_Supported
//Active_VT_Sessions
//Local_Time - rely on OS, if there is one
//Local_Date - rely on OS, if there is one
//UTC_Offset - rely on OS, if there is one
//Daylight_Savings_Status - rely on OS, if there is one
//APDU_Segment_Timeout
/* 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 uint16_t Max_APDU_Length_Accepted = MAX_APDU; - constant */
/* static BACNET_SEGMENTATION Segmentation_Supported = SEGMENTATION_NONE; */
/* static uint8_t Max_Segments_Accepted = 0; */
/* VT_Classes_Supported */
/* Active_VT_Sessions */
/* Local_Time - rely on OS, if there is one */
/* Local_Date - rely on OS, if there is one */
/* UTC_Offset - rely on OS, if there is one */
/* Daylight_Savings_Status - rely on OS, if there is one */
/* APDU_Segment_Timeout */
static uint16_t APDU_Timeout = 3000;
static uint8_t Number_Of_APDU_Retries = 3;
//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
/* 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 uint8_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
/* 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 */
// methods to manipulate the data
/* methods to manipulate the data */
uint32_t Device_Object_Instance_Number(void)
{
return Object_Instance_Number;
@@ -379,6 +384,71 @@ bool Device_Object_List_Identifier(unsigned array_index,
return status;
}
bool Device_Valid_Object_Name(
const char *object_name,
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;
char *name = 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)
{
name = Device_Valid_Object_Id(type,instance);
if (strcmp(name,object_name) == 0)
{
found = true;
if (object_type)
*object_type = type;
if (object_instance)
*object_instance = instance;
break;
}
}
}
return found;
}
/* returns the name or NULL if not found */
char *Device_Valid_Object_Id(
int object_type,
uint32_t object_instance)
{
char *name = NULL; /* return value */
switch (object_type)
{
case OBJECT_ANALOG_INPUT:
name = Analog_Input_Name(object_instance);
break;
case OBJECT_ANALOG_OUTPUT:
name = Analog_Output_Name(object_instance);
break;
#if BACFILE
case OBJECT_FILE:
name = bacfile_name(object_instance);
break;
#endif
case OBJECT_DEVICE:
if (object_instance == Object_Instance_Number)
name = Object_Name;
break;
default:
break;
}
return name;
}
// return the length of the apdu encoded or -1 for error
int Device_Encode_Property_APDU(
uint8_t *apdu,
+8
View File
@@ -91,6 +91,14 @@ void Device_Set_Number_Of_APDU_Retries(uint8_t retries);
uint8_t Device_Database_Revision(void);
void Device_Set_Database_Revision(uint8_t revision);
bool Device_Valid_Object_Name(
const char *object_name,
int *object_type,
uint32_t *object_instance);
char *Device_Valid_Object_Id(
int object_type,
uint32_t object_instance);
int Device_Encode_Property_APDU(
uint8_t *apdu,
BACNET_PROPERTY_ID property,
+4
View File
@@ -31,6 +31,8 @@ SRCS = server.c \
$(BACNET_HANDLER)/h_arf.c \
$(BACNET_HANDLER)/h_rd.c \
$(BACNET_HANDLER)/h_dcc.c \
$(BACNET_HANDLER)/h_whohas.c \
$(BACNET_HANDLER)/s_ihave.c \
$(BACNET_OBJECT)/device.c \
$(BACNET_OBJECT)/ai.c \
$(BACNET_OBJECT)/ao.c \
@@ -46,6 +48,8 @@ SRCS = server.c \
$(BACNET_ROOT)/bigend.c \
$(BACNET_ROOT)/whois.c \
$(BACNET_ROOT)/iam.c \
$(BACNET_ROOT)/whohas.c \
$(BACNET_ROOT)/ihave.c \
$(BACNET_ROOT)/rp.c \
$(BACNET_ROOT)/wp.c \
$(BACNET_ROOT)/arf.c \
+9 -4
View File
@@ -30,6 +30,8 @@ SRCS = server.c \
..\..\demo\handler\h_arf.c \
..\..\demo\handler\h_rd.c \
..\..\demo\handler\h_dcc.c \
..\..\demo\handler\h_whohas.c \
..\..\demo\handler\s_ihave.c \
..\..\bacdcode.c \
..\..\bacapp.c \
..\..\bacstr.c \
@@ -38,6 +40,8 @@ SRCS = server.c \
..\..\bigend.c \
..\..\whois.c \
..\..\iam.c \
..\..\whohas.c \
..\..\ihave.c \
..\..\rp.c \
..\..\wp.c \
..\..\arf.c \
@@ -59,7 +63,8 @@ OBJS = $(SRCS:.c=.obj)
# Compiler definitions
#
CC = $(BORLAND_DIR)\bin\bcc32 +bcc32.cfg
BCC_CFG = bcc32.cfg
CC = $(BORLAND_DIR)\bin\bcc32 +$(BCC_CFG)
#LINK = $(BORLAND_DIR)\bin\tlink32
LINK = $(BORLAND_DIR)\bin\ilink32
TLIB = $(BORLAND_DIR)\bin\tlib
@@ -84,7 +89,7 @@ $(C_LIB_DIR)\CW32MT.lib
#
# This should be the first one in the makefile
all : bcc32.cfg $(PRODUCT_EXE)
all : $(BCC_CFG) $(PRODUCT_EXE)
# Linker specific: the link below is for BCC linker/compiler. If you link
# with a different linker - please change accordingly.
@@ -113,7 +118,7 @@ clean :
del ..\..\ports\win32\*.obj
del $(PRODUCT_EXE)
del *.map
del bcc32.cfg
del $(BCC_CFG)
#
# Generic rules
@@ -127,7 +132,7 @@ clean :
$(CC) -o$@ $<
# Compiler configuration file
bcc32.cfg :
$(BCC_CFG) :
Copy &&|
$(CFLAGS)
-c
+3
View File
@@ -56,6 +56,9 @@ static void Init_Service_Handlers(void)
apdu_set_unconfirmed_handler(
SERVICE_UNCONFIRMED_WHO_IS,
handler_who_is);
apdu_set_unconfirmed_handler(
SERVICE_UNCONFIRMED_WHO_HAS,
handler_who_has);
/* set the handler for all the services we don't implement */
/* It is required to send the proper reject message... */
apdu_set_unrecognized_service_handler_handler(
+79
View File
@@ -0,0 +1,79 @@
#Makefile to build BACnet Application for the Linux Port
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -O2 -g
# Note: you can strip out symbols using the strip command
# to get an idea of how big the compile really is.
#DEFINES = -DBACFILE=1 -DBACDL_ETHERNET=1
#DEFINES = -DBACFILE=1 -DBACDL_ARCNET=1
#DEFINES = -DBACFILE=1 -DBACDL_MSTP=1
DEFINES = -DBACFILE=1 -DTSM_ENABLED=1 -DBACDL_BIP=1
BACNET_PORT = ../../ports/linux
BACNET_OBJECT = ../object
BACNET_HANDLER = ../handler
BACNET_ROOT = ../..
INCLUDES = -I$(BACNET_ROOT) -I$(BACNET_PORT) -I$(BACNET_OBJECT) -I$(BACNET_HANDLER)
CFLAGS = -Wall -g $(INCLUDES) $(DEFINES)
TARGET = bacrd
SRCS = main.c \
$(BACNET_ROOT)/rd.c \
$(BACNET_PORT)/bip-init.c \
$(BACNET_ROOT)/bip.c \
$(BACNET_HANDLER)/txbuf.c \
$(BACNET_HANDLER)/noserv.c \
$(BACNET_HANDLER)/h_whois.c \
$(BACNET_HANDLER)/h_rp.c \
$(BACNET_HANDLER)/h_iam.c \
$(BACNET_HANDLER)/s_whois.c \
$(BACNET_HANDLER)/s_rd.c \
$(BACNET_OBJECT)/device.c \
$(BACNET_OBJECT)/ai.c \
$(BACNET_OBJECT)/ao.c \
$(BACNET_OBJECT)/bacfile.c \
$(BACNET_ROOT)/filename.c \
$(BACNET_ROOT)/rp.c \
$(BACNET_ROOT)/wp.c \
$(BACNET_ROOT)/bacdcode.c \
$(BACNET_ROOT)/bacapp.c \
$(BACNET_ROOT)/bacprop.c \
$(BACNET_ROOT)/bacstr.c \
$(BACNET_ROOT)/bactext.c \
$(BACNET_ROOT)/indtext.c \
$(BACNET_ROOT)/bigend.c \
$(BACNET_ROOT)/whois.c \
$(BACNET_ROOT)/iam.c \
$(BACNET_ROOT)/tsm.c \
$(BACNET_ROOT)/datalink.c \
$(BACNET_ROOT)/address.c \
$(BACNET_ROOT)/arf.c \
$(BACNET_ROOT)/dcc.c \
$(BACNET_ROOT)/abort.c \
$(BACNET_ROOT)/reject.c \
$(BACNET_ROOT)/bacerror.c \
$(BACNET_ROOT)/apdu.c \
$(BACNET_ROOT)/npdu.c
OBJS = ${SRCS:.c=.o}
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak ports/linux/*.bak *.1 *.ini
include: .depend
+252
View File
@@ -0,0 +1,252 @@
/**************************************************************************
*
* Copyright (C) 2006 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.
*
*********************************************************************/
/* WRITEPROP: command line tool that writes a property to a BACnet device. */
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h> /* for time */
#include <errno.h>
#include "bactext.h"
#include "iam.h"
#include "arf.h"
#include "tsm.h"
#include "address.h"
#include "config.h"
#include "bacdef.h"
#include "npdu.h"
#include "apdu.h"
#include "device.h"
#include "net.h"
#include "datalink.h"
#include "whohas.h"
/* some demo stuff needed */
#include "filename.h"
#include "handlers.h"
#include "client.h"
#include "txbuf.h"
// buffer used for receive
static uint8_t Rx_Buf[MAX_MPDU] = {0};
/* global variables used in this file */
static BACNET_OBJECT_TYPE Target_Object_Type = MAX_BACNET_OBJECT_TYPE;
static uint32_t Target_Object_Instance = BACNET_MAX_INSTANCE;
static char *Target_Object_Name = NULL;
static bool Error_Detected = false;
void MyAbortHandler(
BACNET_ADDRESS *src,
uint8_t invoke_id,
uint8_t abort_reason)
{
/* FIXME: verify src and invoke id */
(void)src;
(void)invoke_id;
printf("BACnet Abort: %s\r\n",
bactext_abort_reason_name(abort_reason));
Error_Detected = true;
}
void MyRejectHandler(
BACNET_ADDRESS *src,
uint8_t invoke_id,
uint8_t reject_reason)
{
/* FIXME: verify src and invoke id */
(void)src;
(void)invoke_id;
printf("BACnet Reject: %s\r\n",
bactext_reject_reason_name(reject_reason));
Error_Detected = true;
}
static void Init_Service_Handlers(void)
{
/* we need to handle who-is
to support dynamic device binding to us */
apdu_set_unconfirmed_handler(
SERVICE_UNCONFIRMED_WHO_IS,
handler_who_is);
/* set the handler for all the services we don't implement
It is required to send the proper reject message... */
apdu_set_unrecognized_service_handler_handler(
handler_unrecognized_service);
/* we must implement read property - it's required! */
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property);
/* handle the reply (request) coming back */
apdu_set_unconfirmed_handler(
SERVICE_UNCONFIRMED_I_HAVE,
handler_i_have);
/* handle any errors coming back */
apdu_set_abort_handler(
MyAbortHandler);
apdu_set_reject_handler(
MyRejectHandler);
}
#ifdef BIP_DEBUG
static void print_address(
char *name,
BACNET_ADDRESS *dest) // destination address
{
int i = 0; // counter
if (dest)
{
printf("%s: ",name);
for (i = 0; i < dest->mac_len; i++)
{
printf("%02X",dest->mac[i]);
}
printf("\n");
}
}
#endif
int main(int argc, char *argv[])
{
BACNET_ADDRESS src = {0}; // address where message came from
uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds
unsigned max_apdu = 0;
time_t elapsed_seconds = 0;
time_t last_seconds = 0;
time_t current_seconds = 0;
time_t timeout_seconds = 0;
uint8_t invoke_id = 0;
bool found = false;
#ifdef BIP_DEBUG
BACNET_ADDRESS my_address, broadcast_address;
#endif
if (argc < 2)
{
/* note: priority 16 and 0 should produce the same end results... */
printf(
"Usage: %s <object-type object-instance | object-name>\r\n"
"Send BACnet WhoHas request to devices, and wait for responses.\r\n"
"\r\n"
"Use either:\r\n"
"The object-type can be 0 to %d.\r\n"
"The object-instance can be 0 to %d.\r\n"
"or:\r\n"
"The object-name can be any string of characters.\r\n",
filename_remove_path(argv[0]),
MAX_BACNET_OBJECT_TYPE-1,
BACNET_MAX_INSTANCE-1);
return 0;
}
/* decode the command line parameters */
if (argc < 3)
{
Target_Object_Name = argv[1];
}
else
{
Target_Object_Type = strtol(argv[1],NULL,0);
Target_Object_Instance = strtol(argv[2],NULL,0);
}
if (Target_Object_Instance > BACNET_MAX_INSTANCE)
{
fprintf(stderr,"object-instance=%u - it must be less than %u\r\n",
Target_Object_Instance,BACNET_MAX_INSTANCE+1);
return 1;
}
if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE)
{
fprintf(stderr,"object-type=%u - it must be less than %u\r\n",
Target_Object_Type,MAX_BACNET_OBJECT_TYPE+1);
return 1;
}
/* setup my info */
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
Init_Service_Handlers();
/* configure standard BACnet/IP port */
bip_set_interface("eth0"); /* for linux */
bip_set_port(0xBAC0);
if (!bip_init())
return 1;
#ifdef BIP_DEBUG
datalink_get_broadcast_address(&broadcast_address);
print_address("Broadcast",&broadcast_address);
datalink_get_my_address(&my_address);
print_address("Address",&my_address);
#endif
/* configure the timeout values */
last_seconds = time(NULL);
timeout_seconds = Device_APDU_Timeout() / 1000;
/* don't send an I-Am unless asked */
I_Am_Request = false;
/* send the request */
if (argc < 3)
Send_WhoHas_Name(-1, -1, Target_Object_Name);
else
Send_WhoHas_Object(-1, -1,
Target_Object_Type,
Target_Object_Instance);
/* loop forever */
for (;;)
{
/* increment timer - exit if timed out */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */
pdu_len = bip_receive(
&src,
&Rx_Buf[0],
MAX_MPDU,
timeout);
/* process */
if (pdu_len)
{
npdu_handler(
&src,
&Rx_Buf[0],
pdu_len);
}
if (Error_Detected)
break;
if (I_Am_Request)
{
I_Am_Request = false;
iam_send(&Handler_Transmit_Buffer[0]);
}
else
{
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds)
break;
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0;
}
+148
View File
@@ -0,0 +1,148 @@
#
# Simple makefile to build an executable for Win32
#
# This makefile assumes Borland bcc32 development environment
# on Windows NT/9x/2000/XP
#
!ifndef BORLAND_DIR
BORLAND_DIR_Not_Defined:
@echo .
@echo You must define environment variable BORLAND_DIR to compile.
!endif
PRODUCT = bacwh
PRODUCT_EXE = $(PRODUCT).exe
# Choose the Data Link Layer to Enable
DEFINES = -DBACDL_BIP=1;TSM_ENABLED=0;USE_INADDR=1
SRCS = main.c \
..\..\rd.c \
..\..\ports\win32\bip-init.c \
..\..\filename.c \
..\..\bip.c \
..\..\demo\handler\txbuf.c \
..\..\demo\handler\noserv.c \
..\..\demo\handler\h_whois.c \
..\..\demo\handler\h_iam.c \
..\..\demo\handler\h_ihave.c \
..\..\demo\handler\h_rp.c \
..\..\demo\handler\s_ihave.c \
..\..\demo\handler\s_whohas.c \
..\..\bacdcode.c \
..\..\bacapp.c \
..\..\bacstr.c \
..\..\bactext.c \
..\..\indtext.c \
..\..\bigend.c \
..\..\whois.c \
..\..\ihave.c \
..\..\whohas.c \
..\..\iam.c \
..\..\rp.c \
..\..\wp.c \
..\..\arf.c \
..\..\awf.c \
..\..\dcc.c \
..\..\demo\object\bacfile.c \
..\..\demo\object\device.c \
..\..\demo\object\ai.c \
..\..\demo\object\ao.c \
..\..\datalink.c \
..\..\abort.c \
..\..\reject.c \
..\..\bacerror.c \
..\..\apdu.c \
..\..\npdu.c
OBJS = $(SRCS:.c=.obj)
# Compiler definitions
#
CC = $(BORLAND_DIR)\bin\bcc32 +bcc32.cfg
#LINK = $(BORLAND_DIR)\bin\tlink32
LINK = $(BORLAND_DIR)\bin\ilink32
TLIB = $(BORLAND_DIR)\bin\tlib
#
# Include directories
#
CC_DIR = $(BORLAND_DIR)\BIN
INCL_DIRS = -I$(BORLAND_DIR)\include;..\..\;..\..\demo\object\;..\..\demo\handler\;..\..\ports\win32\;.
CFLAGS = $(INCL_DIRS) $(CS_FLAGS) $(DEFINES)
# Libraries
#
C_LIB_DIR = $(BORLAND_DIR)\lib
LIBS = $(C_LIB_DIR)\IMPORT32.lib \
$(C_LIB_DIR)\CW32MT.lib
#
# Main target
#
# This should be the first one in the makefile
all : bcc32.cfg $(PRODUCT_EXE)
# Linker specific: the link below is for BCC linker/compiler. If you link
# with a different linker - please change accordingly.
#
# need a temp response file (@&&) because command line is too long
$(PRODUCT_EXE) : $(OBJS)
@echo Running Linker for $(PRODUCT_EXE)
$(LINK) -L$(C_LIB_DIR) -m -c -s -v @&&| # temp response file, starts with |
$(BORLAND_DIR)\lib\c0x32.obj $** # $** lists each dependency
$<
$*.map
$(LIBS)
| # end of temp response file
#
# Utilities
clean :
@echo Deleting obj files, $(PRODUCT_EXE) and map files.
# del $(OBJS) # command too long, bummer!
del *.obj
del ..\..\*.obj
del ..\..\demo\handler\*.obj
del ..\..\demo\object\*.obj
del ..\..\ports\win32\*.obj
del $(PRODUCT_EXE)
del *.map
del bcc32.cfg
#
# Generic rules
#
.SUFFIXES: .cpp .c .sbr .obj
#
# cc generic rule
#
.c.obj:
$(CC) -o$@ $<
# Compiler configuration file
bcc32.cfg :
Copy &&|
$(CFLAGS)
-c
-y #include line numbers in OBJ's
-v #include debug info
-w+ #turn on all warnings
-Od #disable all optimizations
#-a4 #32 bit data alignment
#-M # generate link map
#-ls # linker options
#-WM- #not multithread
-WM #multithread
-w-aus # ignore warning assigned a value that is never used
-w-sig # ignore warning conversion may lose sig digits
| $@
# EOF: makefile
+228
View File
@@ -0,0 +1,228 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2006 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdint.h>
#include "bacenum.h"
#include "bacdcode.h"
#include "bacdef.h"
#include "ihave.h"
int ihave_encode_apdu(
uint8_t *apdu,
BACNET_I_HAVE_DATA *data)
{
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (apdu && data) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_I_HAVE;
apdu_len = 2;
/* deviceIdentifier */
len = encode_tagged_object_id(
&apdu[apdu_len],
data->device_id.type,
data->device_id.instance);
apdu_len += len;
/* objectIdentifier */
len = encode_tagged_object_id(
&apdu[apdu_len],
data->object_id.type,
data->object_id.instance);
apdu_len += len;
/* objectName */
len = encode_tagged_character_string(
&apdu[apdu_len],
&data->object_name);
apdu_len += len;
}
return apdu_len;
}
/* decode the service request only */
int ihave_decode_service_request(
uint8_t *apdu,
unsigned apdu_len,
BACNET_I_HAVE_DATA *data)
{
int len = 0;
uint8_t tag_number = 0;
uint32_t len_value = 0;
uint32_t decoded_value = 0; /* for decoding */
int decoded_type = 0; /* for decoding */
if (apdu_len && data)
{
/* deviceIdentifier */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID)
{
len += decode_object_id(&apdu[len], &decoded_type,
&data->device_id.instance);
data->device_id.type = decoded_type;
}
else
return -1;
/* objectIdentifier */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID)
{
len += decode_object_id(&apdu[len], &decoded_type,
&data->object_id.instance);
data->object_id.type = decoded_type;
}
else
return -1;
/* objectName */
len += decode_tag_number_and_value(&apdu[len], &tag_number, &len_value);
if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING)
{
len += decode_character_string(&apdu[len], len_value,
&data->object_name);
}
else
return -1;
}
else
return -1;
return len;
}
int ihave_decode_apdu(
uint8_t *apdu,
unsigned apdu_len,
BACNET_I_HAVE_DATA *data)
{
int len = 0;
if (!apdu)
return -1;
/* optional checking - most likely was already done prior to this call */
if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST)
return -1;
if (apdu[1] != SERVICE_UNCONFIRMED_I_HAVE)
return -1;
len = ihave_decode_service_request(
&apdu[2],
apdu_len - 2,
data);
return len;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
void testIHaveData(Test * pTest, BACNET_I_HAVE_DATA *data)
{
uint8_t apdu[480] = {0};
int len = 0;
int apdu_len = 0;
BACNET_I_HAVE_DATA test_data;
len = ihave_encode_apdu(
&apdu[0],
data);
ct_test(pTest, len != 0);
apdu_len = len;
len = ihave_decode_apdu(
&apdu[0],
apdu_len,
&test_data);
ct_test(pTest, len != -1);
ct_test(pTest, test_data.device_id.type ==
data->device_id.type);
ct_test(pTest, test_data.device_id.instance ==
data->device_id.instance);
ct_test(pTest, test_data.object_id.type ==
data->object_id.type);
ct_test(pTest, test_data.object_id.instance ==
data->object_id.instance);
ct_test(pTest, characterstring_same(
&test_data.object_name,&data->object_name));
}
}
void testIHave(Test * pTest)
{
BACNET_I_HAVE_DATA data;
characterstring_init_ansi(
&data.object_name,"patricia");
data.device_id.type = OBJECT_DEVICE;
for (
data.device_id.instance = 1;
data.device_id.instance <= BACNET_MAX_INSTANCE;
data.device_id.instance <<= 1)
{
for (
data.object_id.type = OBJECT_ANALOG_INPUT;
data.object_id.type <= MAX_BACNET_OBJECT_TYPE;
data.object_id.type++)
{
for (
data.object_id.instance = 1;
data.object_id.instance <= BACNET_MAX_INSTANCE;
data.object_id.instance <<= 1)
{
testIHaveData(pTest,&data);
}
}
}
}
#ifdef TEST_I_HAVE
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("BACnet I-Have", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testIHave);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif /* TEST_WHOIS */
#endif /* TEST */
+76
View File
@@ -0,0 +1,76 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2006 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#ifndef IHAVE_H
#define IHAVE_H
#include <stdint.h>
#include <stdbool.h>
#include "bacstr.h"
typedef struct BACnet_I_Have_Data
{
BACNET_OBJECT_ID device_id;
BACNET_OBJECT_ID object_id;
BACNET_CHARACTER_STRING object_name;
} BACNET_I_HAVE_DATA;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int ihave_encode_apdu(
uint8_t *apdu,
BACNET_I_HAVE_DATA *data);
int ihave_decode_service_request(
uint8_t *apdu,
unsigned apdu_len,
BACNET_I_HAVE_DATA *data);
int ihave_decode_apdu(
uint8_t *apdu,
unsigned apdu_len,
BACNET_I_HAVE_DATA *data);
#ifdef TEST
#include "ctest.h"
void testIHave(Test * pTest);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+34
View File
@@ -0,0 +1,34 @@
#Makefile to build test case
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_I_HAVE -g
SRCS = bacdcode.c \
bacstr.c \
bigend.c \
ihave.c \
test/ctest.c
OBJS = ${SRCS:.c=.o}
TARGET = ihave
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
include: .depend
Binary file not shown.
+1 -1
View File
@@ -48,7 +48,7 @@ int whohas_encode_apdu(
if (apdu && data) {
apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST;
apdu[1] = SERVICE_UNCONFIRMED_WHO_IS; // service choice
apdu[1] = SERVICE_UNCONFIRMED_WHO_HAS; // service choice
apdu_len = 2;
// optional limits - must be used as a pair
if ((data->low_limit >= 0) && (data->low_limit <= BACNET_MAX_INSTANCE) &&
+1 -5
View File
@@ -45,11 +45,7 @@ typedef struct BACnet_Who_Has_Data
bool object_name; /* true if a string */
union
{
struct
{
BACNET_OBJECT_TYPE type;
uint32_t instance;
} identifier;
BACNET_OBJECT_ID identifier;
BACNET_CHARACTER_STRING name;
} object;
} BACNET_WHO_HAS_DATA;