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:
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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.
@@ -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) &&
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user