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