diff --git a/bacnet-stack/bacapp.ide b/bacnet-stack/bacapp.ide new file mode 100644 index 00000000..6ac399ae Binary files /dev/null and b/bacnet-stack/bacapp.ide differ diff --git a/bacnet-stack/bacdcode.c b/bacnet-stack/bacdcode.c index 8c7c985c..b146da3b 100644 --- a/bacnet-stack/bacdcode.c +++ b/bacnet-stack/bacdcode.c @@ -1678,7 +1678,7 @@ void testBACDCodeSignedValue(Test * pTest, int32_t value) { uint8_t array[5] = { 0 }; uint8_t encoded_array[5] = { 0 }; - int decoded_value = 0; + long decoded_value = 0; int len = 0, apdu_len = 0; uint8_t apdu[MAX_APDU] = { 0 }; uint8_t tag_number = 0; @@ -1692,7 +1692,7 @@ void testBACDCodeSignedValue(Test * pTest, int32_t value) ct_test(pTest, decoded_value == value); if (decoded_value != value) { - printf("value=%d decoded_value=%d\n", value, decoded_value); + printf("value=%d decoded_value=%ld\n", value, decoded_value); print_apdu(&array[0],sizeof(array)); } encode_tagged_signed(&encoded_array[0], decoded_value); diff --git a/bacnet-stack/bacenum.h b/bacnet-stack/bacenum.h index c100ba9c..e9732f1a 100644 --- a/bacnet-stack/bacenum.h +++ b/bacnet-stack/bacenum.h @@ -228,7 +228,7 @@ typedef enum PROP_UPDATE_TIME = 189, PROP_VALUE_BEFORE_CHANGE = 190, PROP_VALUE_SET = 191, - PROP_VALUE_CHANGE_TIME = 192 + PROP_VALUE_CHANGE_TIME = 192, // The special property identifiers all, optional, and required // are reserved for use in the ReadPropertyConditional and @@ -237,6 +237,7 @@ typedef enum // Enumerated values 512-4194303 may be used by others subject to the // procedures and constraints described in Clause 23. // The highest enumeration used in this version is 168. + MAX_BACNET_PROPERTY_ID = 4194303 } BACNET_PROPERTY_ID; typedef enum @@ -701,7 +702,8 @@ typedef enum // Enumerated values 0-127 are reserved for definition by ASHRAE. // Enumerated values 128-1023 may be used by others subject to // the procedures and constraints described in Clause 23. - MAX_BACNET_OBJECT_TYPES = 25 // used for bit string loop + MAX_ASHRAE_OBJECT_TYPE = 25, // used for bit string loop + MAX_BACNET_OBJECT_TYPE = 1023 } BACNET_OBJECT_TYPE; typedef enum @@ -753,7 +755,8 @@ typedef enum { BACNET_APPLICATION_TAG_OBJECT_ID = 12, BACNET_APPLICATION_TAG_RESERVED1 = 13, BACNET_APPLICATION_TAG_RESERVED2 = 14, - BACNET_APPLICATION_TAG_RESERVED3 = 15 + BACNET_APPLICATION_TAG_RESERVED3 = 15, + MAX_BACNET_APPLICATION_TAG = 16 } BACNET_APPLICATION_TAG; // note: these are not the real values, diff --git a/bacnet-stack/bip.c b/bacnet-stack/bip.c index 42837c3e..c0dcb35a 100644 --- a/bacnet-stack/bip.c +++ b/bacnet-stack/bip.c @@ -40,7 +40,7 @@ static int BIP_Socket = -1; /* port to use - stored in host byte order */ -static uint16_t BIP_Port = 0; +static uint16_t BIP_Port = 0xBAC0; /* IP Address - stored in host byte order */ static struct in_addr BIP_Address; /* Broadcast Address - stored in host byte order */ diff --git a/bacnet-stack/demo/handler/client.h b/bacnet-stack/demo/handler/client.h index b3b6d58e..8eb1bdd8 100644 --- a/bacnet-stack/demo/handler/client.h +++ b/bacnet-stack/demo/handler/client.h @@ -54,7 +54,7 @@ bool Send_Write_Property_Request( BACNET_OBJECT_TYPE object_type, uint32_t object_instance, BACNET_PROPERTY_ID object_property, - BACNET_APPLICATION_DATA_VALUE object_value, + BACNET_APPLICATION_DATA_VALUE *object_value, uint8_t priority, int32_t array_index); diff --git a/bacnet-stack/demo/handler/h_iam.c b/bacnet-stack/demo/handler/h_iam.c index d3eedb4e..a002aeb1 100644 --- a/bacnet-stack/demo/handler/h_iam.c +++ b/bacnet-stack/demo/handler/h_iam.c @@ -32,7 +32,7 @@ #include "iam.h" #include "address.h" -void handler_i_am( +void handler_i_am_add( uint8_t *service_request, uint16_t service_len, BACNET_ADDRESS *src) @@ -43,7 +43,6 @@ void handler_i_am( int segmentation = 0; uint16_t vendor_id = 0; - (void)src; (void)service_len; len = iam_decode_service_request( service_request, @@ -64,3 +63,30 @@ void handler_i_am( return; } + +void handler_i_am_bind( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src) +{ + int len = 0; + uint32_t device_id = 0; + unsigned max_apdu = 0; + int segmentation = 0; + uint16_t vendor_id = 0; + + (void)service_len; + len = iam_decode_service_request( + service_request, + &device_id, + &max_apdu, + &segmentation, + &vendor_id); + // only add address if requested to bind + address_add_binding(device_id, + max_apdu, + src); + + return; +} + diff --git a/bacnet-stack/demo/handler/handlers.h b/bacnet-stack/demo/handler/handlers.h index c10080b7..e9852b92 100644 --- a/bacnet-stack/demo/handler/handlers.h +++ b/bacnet-stack/demo/handler/handlers.h @@ -50,6 +50,16 @@ void handler_who_is( uint16_t service_len, BACNET_ADDRESS *src); +void handler_i_am_add( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src); + +void handler_i_am_bind( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src); + void handler_read_property( uint8_t *service_request, uint16_t service_len, diff --git a/bacnet-stack/demo/handler/s_rp.c b/bacnet-stack/demo/handler/s_rp.c index daa63b0f..43f3c01b 100644 --- a/bacnet-stack/demo/handler/s_rp.c +++ b/bacnet-stack/demo/handler/s_rp.c @@ -41,8 +41,8 @@ #include "handlers.h" #include "txbuf.h" -/* returns false if device is not bound or no tsm available */ -bool Send_Read_Property_Request( +/* returns invoke id of 0 if device is not bound or no tsm available */ +uint8_t Send_Read_Property_Request( uint32_t device_id, /* destination device */ BACNET_OBJECT_TYPE object_type, uint32_t object_instance, @@ -99,9 +99,7 @@ bool Send_Read_Property_Request( &dest, // destination address &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data - if (bytes_sent > 0) - fprintf(stderr,"Sent ReadProperty Request!\n"); - else + if (bytes_sent <= 0) fprintf(stderr,"Failed to Send ReadProperty Request (%s)!\n", strerror(errno)); } @@ -110,5 +108,5 @@ bool Send_Read_Property_Request( "(exceeds destination maximum APDU)!\n"); } - return status; + return invoke_id; } diff --git a/bacnet-stack/demo/handler/s_whois.c b/bacnet-stack/demo/handler/s_whois.c index 0f661d26..9ab7a2e0 100644 --- a/bacnet-stack/demo/handler/s_whois.c +++ b/bacnet-stack/demo/handler/s_whois.c @@ -71,8 +71,6 @@ void Send_WhoIs( &dest, // destination address &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data - if (bytes_sent > 0) - fprintf(stderr,"Sent Who-Is Request!\n"); - else + if (bytes_sent <= 0) fprintf(stderr,"Failed to Send Who-Is Request (%s)!\n", strerror(errno)); } diff --git a/bacnet-stack/demo/handler/s_wp.c b/bacnet-stack/demo/handler/s_wp.c index 8327b1b3..4e19e836 100644 --- a/bacnet-stack/demo/handler/s_wp.c +++ b/bacnet-stack/demo/handler/s_wp.c @@ -41,13 +41,13 @@ #include "handlers.h" #include "txbuf.h" -/* FIXME: probably should return the invoke ID for confirmed request */ -bool Send_Write_Property_Request( +/* returns the invoke ID for confirmed request, or zero on failure */ +uint8_t Send_Write_Property_Request( uint32_t device_id, // destination device BACNET_OBJECT_TYPE object_type, uint32_t object_instance, BACNET_PROPERTY_ID object_property, - BACNET_APPLICATION_DATA_VALUE object_value, + BACNET_APPLICATION_DATA_VALUE *object_value, uint8_t priority, int32_t array_index) { @@ -81,7 +81,7 @@ bool Send_Write_Property_Request( data.object_instance = object_instance; data.object_property = object_property; data.array_index = array_index; - data.value = object_value; + bacapp_copy(&data.value,object_value); data.priority = priority; pdu_len += wp_encode_apdu( &Handler_Transmit_Buffer[pdu_len], @@ -103,9 +103,7 @@ bool Send_Write_Property_Request( &dest, // destination address &Handler_Transmit_Buffer[0], pdu_len); // number of bytes of data - if (bytes_sent > 0) - fprintf(stderr,"Sent ReadProperty Request!\n"); - else + if (bytes_sent <= 0) fprintf(stderr,"Failed to Send WriteProperty Request (%s)!\n", strerror(errno)); } @@ -114,6 +112,6 @@ bool Send_Write_Property_Request( "(exceeds destination maximum APDU)!\n"); } - return status; + return invoke_id; } diff --git a/bacnet-stack/demo/object/bacfile.c b/bacnet-stack/demo/object/bacfile.c index 4f316da4..8b8cf6a6 100644 --- a/bacnet-stack/demo/object/bacfile.c +++ b/bacnet-stack/demo/object/bacfile.c @@ -239,6 +239,7 @@ uint32_t bacfile_instance(char *filename) return instance; } +#if TSM_ENABLED // this is one way to match up the invoke ID with // the file ID from the AtomicReadFile request. // Another way would be to store the @@ -300,6 +301,7 @@ uint32_t bacfile_instance_from_tsm( return object_instance; } +#endif bool bacfile_read_data(BACNET_ATOMIC_READ_FILE_DATA *data) { diff --git a/bacnet-stack/demo/object/bacfile.h b/bacnet-stack/demo/object/bacfile.h index 3c83f990..e046caed 100644 --- a/bacnet-stack/demo/object/bacfile.h +++ b/bacnet-stack/demo/object/bacfile.h @@ -50,6 +50,7 @@ bool bacfile_valid_instance(uint32_t object_instance); uint32_t bacfile_count(void); uint32_t bacfile_index_to_instance(unsigned find_index); uint32_t bacfile_instance(char *filename); +#if TSM_ENABLED // this is one way to match up the invoke ID with // the file ID from the AtomicReadFile request. // Another way would be to store the @@ -57,6 +58,7 @@ uint32_t bacfile_instance(char *filename); // when the request was sent uint32_t bacfile_instance_from_tsm( uint8_t invokeID); +#endif // AtomicReadFile ACK helper bool bacfile_read_data(BACNET_ATOMIC_READ_FILE_DATA *data); diff --git a/bacnet-stack/demo/object/device.c b/bacnet-stack/demo/object/device.c index ba5c4a65..e1ee2afd 100644 --- a/bacnet-stack/demo/object/device.c +++ b/bacnet-stack/demo/object/device.c @@ -478,7 +478,7 @@ int Device_Encode_Property_APDU( break; case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: bitstring_init(&bit_string); - for (i = 0; i < MAX_BACNET_OBJECT_TYPES; i++) + for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { // initialize all the object types to not-supported bitstring_set_bit(&bit_string, (uint8_t)i, false); diff --git a/bacnet-stack/demo/readfile/makefile.mak b/bacnet-stack/demo/readfile/makefile.mak index e3994290..d457fbbf 100644 --- a/bacnet-stack/demo/readfile/makefile.mak +++ b/bacnet-stack/demo/readfile/makefile.mak @@ -15,7 +15,7 @@ PRODUCT = bacarf PRODUCT_EXE = $(PRODUCT).exe # Choose the Data Link Layer to Enable -DEFINES = -DBACDL_BIP=1 +DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1 SRCS = readfile.c \ ..\..\ports\win32\bip-init.c \ diff --git a/bacnet-stack/demo/readfile/readfile.c b/bacnet-stack/demo/readfile/readfile.c index b6f83e63..7143fb4f 100644 --- a/bacnet-stack/demo/readfile/readfile.c +++ b/bacnet-stack/demo/readfile/readfile.c @@ -51,8 +51,8 @@ static uint8_t Rx_Buf[MAX_MPDU] = {0}; /* global variables used in this file */ -static uint32_t Target_File_Object_Instance = 4194303; -static uint32_t Target_Device_Object_Instance = 4194303; +static uint32_t Target_File_Object_Instance = BACNET_MAX_INSTANCE; +static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; static BACNET_ADDRESS Target_Address; static char *Local_File_Name = NULL; static bool End_Of_File_Detected = false; diff --git a/bacnet-stack/demo/readprop/makefile.mak b/bacnet-stack/demo/readprop/makefile.mak new file mode 100644 index 00000000..60f006b4 --- /dev/null +++ b/bacnet-stack/demo/readprop/makefile.mak @@ -0,0 +1,146 @@ +# +# 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 = bacrp +PRODUCT_EXE = $(PRODUCT).exe + +# Choose the Data Link Layer to Enable +DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1 + +SRCS = readprop.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_rp.c \ + ..\..\demo\handler\h_rp_a.c \ + ..\..\demo\handler\s_rp.c \ + ..\..\demo\handler\s_whois.c \ + ..\..\bacdcode.c \ + ..\..\bacapp.c \ + ..\..\bacstr.c \ + ..\..\bactext.c \ + ..\..\indtext.c \ + ..\..\bigend.c \ + ..\..\whois.c \ + ..\..\iam.c \ + ..\..\rp.c \ + ..\..\wp.c \ + ..\..\arf.c \ + ..\..\awf.c \ + ..\..\demo\object\bacfile.c \ + ..\..\demo\object\device.c \ + ..\..\demo\object\ai.c \ + ..\..\demo\object\ao.c \ + ..\..\datalink.c \ + ..\..\tsm.c \ + ..\..\address.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 diff --git a/bacnet-stack/demo/readprop/readprop.c b/bacnet-stack/demo/readprop/readprop.c new file mode 100644 index 00000000..d66f67af --- /dev/null +++ b/bacnet-stack/demo/readprop/readprop.c @@ -0,0 +1,275 @@ +/************************************************************************** +* +* Copyright (C) 2006 Steve Karg +* +* 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. +* +*********************************************************************/ + +/* READPROP: command line tool that reads a property from a BACnet device. */ +#include +#include +#include +#include +#include /* for time */ +#include +#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 "whois.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 uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; +static uint32_t Target_Object_Instance = BACNET_MAX_INSTANCE; +static BACNET_OBJECT_TYPE Target_Object_Type = OBJECT_ANALOG_INPUT; +static BACNET_PROPERTY_ID Target_Object_Property = PROP_ACKED_TRANSITIONS; +static int32_t Target_Object_Index = BACNET_ARRAY_ALL; + +static BACNET_ADDRESS Target_Address; +static bool Error_Detected = false; + +static void MyErrorHandler( + BACNET_ADDRESS *src, + uint8_t invoke_id, + BACNET_ERROR_CLASS error_class, + BACNET_ERROR_CODE error_code) +{ + /* FIXME: verify src and invoke id */ + (void)src; + (void)invoke_id; + printf("\r\nBACnet Error!\r\n"); + printf("Error Class: %s\r\n", + bactext_error_class_name(error_class)); + printf("Error Code: %s\r\n", + bactext_error_code_name(error_code)); + Error_Detected = true; +} + +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("\r\nBACnet Abort!\r\n"); + printf("Abort Reason: %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("\r\nBACnet Reject!\r\n"); + printf("Reject Reason: %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); + /* handle i-am to support binding to other devices */ + apdu_set_unconfirmed_handler( + SERVICE_UNCONFIRMED_I_AM, + handler_i_am_bind); + /* 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 data coming back from confirmed requests */ + apdu_set_confirmed_ack_handler( + SERVICE_CONFIRMED_READ_PROPERTY, + handler_read_property_ack); + /* handle any errors coming back */ + apdu_set_error_handler( + SERVICE_CONFIRMED_READ_PROPERTY, + MyErrorHandler); + apdu_set_abort_handler( + MyAbortHandler); + apdu_set_reject_handler( + MyRejectHandler); +} + +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; + int fileStartPosition = 0; + uint8_t invoke_id = 0; + bool found = false; + + if (argc < 5) + { + printf("%s device-instance object-type object-instance property [index]\r\n", + filename_remove_path(argv[0])); + return 0; + } + /* decode the command line parameters */ + Target_Device_Object_Instance = strtol(argv[1],NULL,0); + Target_Object_Type = strtol(argv[2],NULL,0); + Target_Object_Instance = strtol(argv[3],NULL,0); + Target_Object_Property = strtol(argv[4],NULL,0); + if (argc > 5) + Target_Object_Index = strtol(argv[5],NULL,0); + if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) + { + fprintf(stderr,"device-instance=%u - it must be less than %u\r\n", + Target_Device_Object_Instance,BACNET_MAX_INSTANCE); + 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; + } + 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_Property > MAX_BACNET_PROPERTY_ID) + { + fprintf(stderr,"object-type=%u - it must be less than %u\r\n", + Target_Object_Property,MAX_BACNET_PROPERTY_ID+1); + return 1; + } + + /* setup my info */ + Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); + address_init(); + Init_Service_Handlers(); + /* configure standard BACnet/IP port */ + bip_set_interface("eth0"); /* for linux */ + bip_set_port(0xBAC0); + if (!bip_init()) + return 1; + /* configure the timeout values */ + last_seconds = time(NULL); + timeout_seconds = (Device_APDU_Timeout() / 1000) * + Device_Number_Of_APDU_Retries(); + /* try to bind with the device */ + Send_WhoIs(Target_Device_Object_Instance,Target_Device_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); + } + /* at least one second has passed */ + if (current_seconds != last_seconds) + tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); + if (Error_Detected) + break; + if (I_Am_Request) + { + I_Am_Request = false; + iam_send(&Handler_Transmit_Buffer[0]); + } + else + { + /* wait until the device is bound, or timeout and quit */ + found = address_bind_request( + Target_Device_Object_Instance, + &max_apdu, + &Target_Address); + if (found) + { + if (invoke_id == 0) + { + invoke_id = Send_Read_Property_Request( + Target_Device_Object_Instance, + Target_Object_Type, + Target_Object_Instance, + Target_Object_Property, + Target_Object_Index); + } + else if (tsm_invoke_id_free(invoke_id)) + break; + } + 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; +} diff --git a/bacnet-stack/demo/server/makefile.mak b/bacnet-stack/demo/server/makefile.mak new file mode 100644 index 00000000..20a6b982 --- /dev/null +++ b/bacnet-stack/demo/server/makefile.mak @@ -0,0 +1,143 @@ +# +# 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 = bacserv +PRODUCT_EXE = $(PRODUCT).exe + +# Choose the Data Link Layer to Enable +# Note: unless some other drivers are installed, BIP is the only +# datalink layer that Win32 supports +DEFINES = -DBACDL_BIP=1;USE_INADDR=1 + +SRCS = server.c \ + ..\..\ports\win32\bip-init.c \ + ..\..\bip.c \ + ..\..\demo\handler\txbuf.c \ + ..\..\demo\handler\noserv.c \ + ..\..\demo\handler\h_whois.c \ + ..\..\demo\handler\h_rp.c \ + ..\..\demo\handler\h_wp.c \ + ..\..\demo\handler\h_arf.c \ + ..\..\bacdcode.c \ + ..\..\bacapp.c \ + ..\..\bacstr.c \ + ..\..\bactext.c \ + ..\..\indtext.c \ + ..\..\bigend.c \ + ..\..\whois.c \ + ..\..\iam.c \ + ..\..\rp.c \ + ..\..\wp.c \ + ..\..\arf.c \ + ..\..\awf.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 diff --git a/bacnet-stack/demo/server/server.c b/bacnet-stack/demo/server/server.c new file mode 100644 index 00000000..afe8bc3a --- /dev/null +++ b/bacnet-stack/demo/server/server.c @@ -0,0 +1,165 @@ +/************************************************************************** +* +* Copyright (C) 2006 Steve Karg +* +* 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 +#include +#include +#include +#include +#include +#include "config.h" +#include "address.h" +#include "bacdef.h" +#include "handlers.h" +#include "client.h" +#include "bacdcode.h" +#include "npdu.h" +#include "apdu.h" +#include "iam.h" +#include "tsm.h" +#include "device.h" +#include "bacfile.h" +#include "datalink.h" +#include "net.h" +#include "txbuf.h" + +/* This is an example application using the BACnet Stack */ + +/* buffers used for receiving */ +static uint8_t Rx_Buf[MAX_MPDU] = {0}; + +static void Init_Service_Handlers(void) +{ + /* we need to handle who-is to support dynamic device binding */ + 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); + /* Set the handlers for any confirmed services that we support. */ + /* We must implement read property - it's required! */ + apdu_set_confirmed_handler( + SERVICE_CONFIRMED_READ_PROPERTY, + handler_read_property); + apdu_set_confirmed_handler( + SERVICE_CONFIRMED_WRITE_PROPERTY, + handler_write_property); + apdu_set_confirmed_handler( + SERVICE_CONFIRMED_ATOMIC_READ_FILE, + handler_atomic_read_file); +} + +static void cleanup(void) +{ + datalink_cleanup(); +} + +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"); + } +} + +int main(int argc, char *argv[]) +{ + BACNET_ADDRESS src = {0}; // address where message came from + uint16_t pdu_len = 0; + unsigned timeout = 100; // milliseconds + BACNET_ADDRESS my_address, broadcast_address; + + /* allow the device ID to be set */ + if (argc > 1) + Device_Set_Object_Instance_Number(strtol(argv[1],NULL,0)); + if (argc > 2) + bip_set_port(strtol(argv[2],NULL,0)); + printf("BACnet Server Demo - Device #%lu\r\n", + Device_Object_Instance_Number()); + Init_Service_Handlers(); + #ifdef BACDL_ETHERNET + // init the physical layer + if (!ethernet_init("eth0")) + return 1; + #endif + #ifdef BACDL_BIP + bip_set_interface("eth0"); + if (!bip_init()) + return 1; + printf("bip: using port %hu\r\n",bip_get_port()); + #endif + #ifdef BACDL_ARCNET + if (!arcnet_init("arc0")) + return 1; + #endif + datalink_get_broadcast_address(&broadcast_address); + print_address("Broadcast",&broadcast_address); + datalink_get_my_address(&my_address); + print_address("Address",&my_address); + atexit(cleanup); + + /* broadcast an I-Am on startup */ + I_Am_Request = true; + // loop forever + for (;;) + { + // input + + // returns 0 bytes on timeout + pdu_len = datalink_receive( + &src, + &Rx_Buf[0], + MAX_MPDU, + timeout); + + // process + if (pdu_len) + { + npdu_handler( + &src, + &Rx_Buf[0], + pdu_len); + } + if (I_Am_Request) + { + I_Am_Request = false; + iam_send(&Handler_Transmit_Buffer[0]); + } + // output + + // blink LEDs, Turn on or off outputs, etc + } +} diff --git a/bacnet-stack/demo/writeprop/makefile.mak b/bacnet-stack/demo/writeprop/makefile.mak new file mode 100644 index 00000000..3bc492cd --- /dev/null +++ b/bacnet-stack/demo/writeprop/makefile.mak @@ -0,0 +1,145 @@ +# +# 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 = bacwp +PRODUCT_EXE = $(PRODUCT).exe + +# Choose the Data Link Layer to Enable +DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1 + +SRCS = writeprop.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_rp.c \ + ..\..\demo\handler\s_wp.c \ + ..\..\demo\handler\s_whois.c \ + ..\..\bacdcode.c \ + ..\..\bacapp.c \ + ..\..\bacstr.c \ + ..\..\bactext.c \ + ..\..\indtext.c \ + ..\..\bigend.c \ + ..\..\whois.c \ + ..\..\iam.c \ + ..\..\rp.c \ + ..\..\wp.c \ + ..\..\arf.c \ + ..\..\awf.c \ + ..\..\demo\object\bacfile.c \ + ..\..\demo\object\device.c \ + ..\..\demo\object\ai.c \ + ..\..\demo\object\ao.c \ + ..\..\datalink.c \ + ..\..\tsm.c \ + ..\..\address.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 diff --git a/bacnet-stack/demo/writeprop/writeprop.c b/bacnet-stack/demo/writeprop/writeprop.c new file mode 100644 index 00000000..71bfe1bd --- /dev/null +++ b/bacnet-stack/demo/writeprop/writeprop.c @@ -0,0 +1,312 @@ +/************************************************************************** +* +* Copyright (C) 2006 Steve Karg +* +* 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 +#include +#include +#include +#include /* for time */ +#include +#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 "whois.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 uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; +static uint32_t Target_Object_Instance = BACNET_MAX_INSTANCE; +static BACNET_OBJECT_TYPE Target_Object_Type = OBJECT_ANALOG_INPUT; +static BACNET_PROPERTY_ID Target_Object_Property = PROP_ACKED_TRANSITIONS; +static int32_t Target_Object_Property_Index = BACNET_ARRAY_ALL; +static BACNET_APPLICATION_TAG Target_Object_Property_Tag = BACNET_APPLICATION_TAG_NULL; +static BACNET_APPLICATION_DATA_VALUE Target_Object_Property_Value = {0}; + +static BACNET_ADDRESS Target_Address; +static bool Error_Detected = false; + +static void MyErrorHandler( + BACNET_ADDRESS *src, + uint8_t invoke_id, + BACNET_ERROR_CLASS error_class, + BACNET_ERROR_CODE error_code) +{ + /* FIXME: verify src and invoke id */ + (void)src; + (void)invoke_id; + printf("\r\nBACnet Error!\r\n"); + printf("Error Class: %s\r\n", + bactext_error_class_name(error_class)); + printf("Error Code: %s\r\n", + bactext_error_code_name(error_code)); + Error_Detected = true; +} + +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("\r\nBACnet Abort!\r\n"); + printf("Abort Reason: %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("\r\nBACnet Reject!\r\n"); + printf("Reject Reason: %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); + /* handle i-am to support binding to other devices */ + apdu_set_unconfirmed_handler( + SERVICE_UNCONFIRMED_I_AM, + handler_i_am_bind); + /* 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 data coming back from confirmed requests */ + apdu_set_confirmed_ack_handler( + SERVICE_CONFIRMED_READ_PROPERTY, + handler_read_property_ack); + /* handle any errors coming back */ + apdu_set_error_handler( + SERVICE_CONFIRMED_READ_PROPERTY, + MyErrorHandler); + apdu_set_abort_handler( + MyAbortHandler); + apdu_set_reject_handler( + MyRejectHandler); +} + +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; + int fileStartPosition = 0; + uint8_t invoke_id = 0; + bool found = false; + char *value_string = NULL; + + if (argc < 7) + { + printf("%s device-instance object-type object-instance property [index] tag value\r\n", + filename_remove_path(argv[0])); + return 0; + } + /* decode the command line parameters */ + Target_Device_Object_Instance = strtol(argv[1],NULL,0); + Target_Object_Type = strtol(argv[2],NULL,0); + Target_Object_Instance = strtol(argv[3],NULL,0); + Target_Object_Property = strtol(argv[4],NULL,0); + /* optional index */ + if (argc > 7) + { + Target_Object_Property_Index = strtol(argv[5],NULL,0); + Target_Object_Property_Tag = strtol(argv[6],NULL,0); + value_string = argv[7]; + } + else + { + Target_Object_Property_Tag = strtol(argv[5],NULL,0); + value_string = argv[6]; + } + + if (Target_Device_Object_Instance >= BACNET_MAX_INSTANCE) + { + fprintf(stderr,"device-instance=%u - it must be less than %u\r\n", + Target_Device_Object_Instance,BACNET_MAX_INSTANCE); + 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; + } + 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_Property > MAX_BACNET_PROPERTY_ID) + { + fprintf(stderr,"object-type=%u - it must be less than %u\r\n", + Target_Object_Property,MAX_BACNET_PROPERTY_ID+1); + return 1; + } + if (Target_Object_Property_Tag >= MAX_BACNET_APPLICATION_TAG) + { + fprintf(stderr,"tag=%u - it must be less than %u\r\n", + Target_Object_Property_Tag,MAX_BACNET_APPLICATION_TAG); + return 1; + } + status = bacapp_parse_application_data( + Target_Object_Property_Tag, + value_string, + &Target_Object_Property_Value); + if (!status) + { + /* FIXME: show the expected entry format for the tag */ + fprintf(stderr,"unable to parse the tag value\r\n"); + return 1; + } + + /* setup my info */ + Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); + address_init(); + Init_Service_Handlers(); + /* configure standard BACnet/IP port */ + bip_set_interface("eth0"); /* for linux */ + bip_set_port(0xBAC0); + if (!bip_init()) + return 1; + /* configure the timeout values */ + last_seconds = time(NULL); + timeout_seconds = (Device_APDU_Timeout() / 1000) * + Device_Number_Of_APDU_Retries(); + /* try to bind with the device */ + Send_WhoIs(Target_Device_Object_Instance,Target_Device_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); + } + /* at least one second has passed */ + if (current_seconds != last_seconds) + tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); + if (Error_Detected) + break; + if (I_Am_Request) + { + I_Am_Request = false; + iam_send(&Handler_Transmit_Buffer[0]); + } + else + { + /* wait until the device is bound, or timeout and quit */ + found = address_bind_request( + Target_Device_Object_Instance, + &max_apdu, + &Target_Address); + if (found) + { + if (invoke_id == 0) + { + invoke_id = Send_Write_Property_Request( + uint32_t device_id, // destination device + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property, + BACNET_APPLICATION_DATA_VALUE object_value, + uint8_t priority, + int32_t array_index) + Target_Device_Object_Instance, + Target_Object_Type, + Target_Object_Instance, + Target_Object_Property, + Target_Object_Property_Index); + } + else if (tsm_invoke_id_free(invoke_id)) + break; + } + 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; +} diff --git a/bacnet-stack/filename.c b/bacnet-stack/filename.c new file mode 100644 index 00000000..dd9313b8 --- /dev/null +++ b/bacnet-stack/filename.c @@ -0,0 +1,103 @@ +/*####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 +#include + +char *filename_remove_path(const char *filename_in) +{ + char *filename_out = NULL; + + /* allow the device ID to be set */ + if (filename_in) + { + filename_out = strrchr(filename_in,'\\'); + if (!filename_out) + filename_out = strrchr(filename_in,'/'); + /* go beyond the slash */ + if (filename_out) + filename_out++; + } + + return filename_out; +} + +#ifdef TEST +#include +#include + +#include "ctest.h" + +void testFilename(Test* pTest) +{ + char *data1 = "c:\\Joshua\\run"; + char *data2 = "/home/Anna/run"; + char *data3 = "c:\\Program Files\\Christopher\\run.exe"; + char *data4 = "//Mary/data/run"; + char *filename = NULL; + + filename = filename_remove_path(data1); + ct_test(pTest,strcmp("run",filename) == 0); + filename = filename_remove_path(data2); + ct_test(pTest,strcmp("run",filename) == 0); + filename = filename_remove_path(data3); + ct_test(pTest,strcmp("run.exe",filename) == 0); + filename = filename_remove_path(data4); + ct_test(pTest,strcmp("run",filename) == 0); + + return; +} + +#ifdef TEST_FILENAME +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("filename remove path", NULL); + + /* individual tests */ + rc = ct_addTestFunction(pTest, testFilename); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void)ct_report(pTest); + + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_FILENAME */ +#endif /* TEST */ + diff --git a/bacnet-stack/filename.h b/bacnet-stack/filename.h new file mode 100644 index 00000000..8ef78d22 --- /dev/null +++ b/bacnet-stack/filename.h @@ -0,0 +1,47 @@ +/*####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 FILENAME_H +#define FILENAME_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +char *filename_remove_path(const char *filename_in); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/bacnet-stack/filename.ide b/bacnet-stack/filename.ide new file mode 100644 index 00000000..38d3cdf8 Binary files /dev/null and b/bacnet-stack/filename.ide differ diff --git a/bacnet-stack/iam.c b/bacnet-stack/iam.c index cfa0f67b..a070841b 100755 --- a/bacnet-stack/iam.c +++ b/bacnet-stack/iam.c @@ -199,32 +199,6 @@ int iam_send(uint8_t *buffer) return bytes_sent; } -void iam_handler( - uint8_t *service_request, - uint16_t service_len, - BACNET_ADDRESS *src) -{ - int len = 0; - uint32_t device_id = 0; - unsigned max_apdu = 0; - int segmentation = 0; - uint16_t vendor_id = 0; - - (void)service_len; - len = iam_decode_service_request( - service_request, - &device_id, - &max_apdu, - &segmentation, - &vendor_id); - // only add address if requested to bind - address_add_binding(device_id, - max_apdu, - src); - - return; -} - #ifdef TEST #include #include diff --git a/bacnet-stack/iam.h b/bacnet-stack/iam.h index 2691f136..ebce3ea8 100644 --- a/bacnet-stack/iam.h +++ b/bacnet-stack/iam.h @@ -63,11 +63,6 @@ int iam_decode_apdu( int *pSegmentation, uint16_t *pVendor_id); -void iam_handler( - uint8_t *service_request, - uint16_t service_len, - BACNET_ADDRESS *src); - int iam_send(uint8_t *buffer); #ifdef TEST diff --git a/bacnet-stack/ports/win32/MAKEFILE.MAK b/bacnet-stack/ports/win32/MAKEFILE.MAK index 5dc8303d..163f0afb 100644 --- a/bacnet-stack/ports/win32/MAKEFILE.MAK +++ b/bacnet-stack/ports/win32/MAKEFILE.MAK @@ -15,7 +15,7 @@ PRODUCT = bacnet PRODUCT_EXE = $(PRODUCT).exe # Choose the Data Link Layer to Enable -DEFINES = -DBACDL_BIP=1 +DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1 SRCS = main.c bip-init.c \ ..\..\bip.c \ diff --git a/bacnet-stack/ports/win32/bacnet.ide b/bacnet-stack/ports/win32/bacnet.ide index dd35334a..7c541de7 100644 Binary files a/bacnet-stack/ports/win32/bacnet.ide and b/bacnet-stack/ports/win32/bacnet.ide differ diff --git a/bacnet-stack/ports/win32/bip-init.c b/bacnet-stack/ports/win32/bip-init.c index 4a3180a4..2aee7027 100644 --- a/bacnet-stack/ports/win32/bip-init.c +++ b/bacnet-stack/ports/win32/bip-init.c @@ -63,7 +63,8 @@ static void set_broadcast_address(uint32_t net_address) long broadcast_address = 0; long mask = 0; - #if 0 + #if USE_INADDR + (void)net_address; bip_set_broadcast_addr(INADDR_BROADCAST); #else if (IN_CLASSA(ntohl(net_address))) @@ -102,7 +103,8 @@ bool bip_init(void) WSADATA wd; struct in_addr address; - Result = WSAStartup(MAKEWORD(2,2), &wd); + Result = WSAStartup((1 << 8) | 1, &wd); + //Result = WSAStartup(MAKEWORD(2,2), &wd); if (Result != 0) { Code = WSAGetLastError(); @@ -124,11 +126,14 @@ bool bip_init(void) bip_set_addr(address.s_addr); set_broadcast_address(address.s_addr); - // assumes that the driver has already been initialized + /* assumes that the driver has already been initialized */ sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); bip_set_socket(sock_fd); if (sock_fd < 0) + { + fprintf(stderr,"bip: failed to allocate a socket.\n"); return false; + } // Allow us to use the same socket for sending and receiving // This makes sure that the src port is correct when sending @@ -136,6 +141,7 @@ bool bip_init(void) (char *)&value, sizeof(value)); if (rv < 0) { + fprintf(stderr,"bip: failed to set REUSEADDR socket option.\n"); close(sock_fd); bip_set_socket(-1); return false; @@ -145,6 +151,7 @@ bool bip_init(void) (char *)&value, sizeof(value)); if (rv < 0) { + fprintf(stderr,"bip: failed to set BROADCAST socket option.\n"); close(sock_fd); bip_set_socket(-1); return false; @@ -168,11 +175,14 @@ bool bip_init(void) Note: sometimes INADDR_ANY does not let me get any unicast messages. Not sure why... */ - /* sin.sin_addr.s_addr = htonl(INADDR_ANY); */ + #if USE_INADDR + sin.sin_addr.s_addr = htonl(INADDR_ANY); + #else /* or we could use the specific adapter address note: already in network byte order */ - sin.sin_addr.s_addr = address.s_addr; + //sin.sin_addr.s_addr = address.s_addr; sin.sin_port = htons(bip_get_port()); + #endif memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); rv = bind(sock_fd, (const struct sockaddr*)&sin, sizeof(struct sockaddr)); diff --git a/bacnet-stack/ports/win32/main.c b/bacnet-stack/ports/win32/main.c index 6987b210..8ed7c228 100644 --- a/bacnet-stack/ports/win32/main.c +++ b/bacnet-stack/ports/win32/main.c @@ -286,7 +286,7 @@ int main(int argc, char *argv[]) } else { - //Read_Properties(); + Read_Properties(); } // output