From 397ef31d419f33f3b61c4d83d8a7c229ab7023d6 Mon Sep 17 00:00:00 2001 From: skarg Date: Fri, 20 May 2016 20:43:05 +0000 Subject: [PATCH] Added BACnet Error and Abort demos to send messages for Wireshark capture validation. --- bacnet-stack/Makefile | 6 + bacnet-stack/bin/abort-reason.sh | 11 ++ bacnet-stack/bin/error-code.sh | 12 ++ bacnet-stack/demo/Makefile | 8 +- bacnet-stack/demo/abort/Makefile | 38 +++++ bacnet-stack/demo/abort/main.c | 248 +++++++++++++++++++++++++++ bacnet-stack/demo/error/Makefile | 38 +++++ bacnet-stack/demo/error/main.c | 255 ++++++++++++++++++++++++++++ bacnet-stack/demo/handler/s_abort.c | 108 ++++++++++++ bacnet-stack/demo/handler/s_error.c | 110 ++++++++++++ bacnet-stack/include/client.h | 34 ++++ bacnet-stack/lib/Makefile | 2 + 12 files changed, 869 insertions(+), 1 deletion(-) create mode 100755 bacnet-stack/bin/abort-reason.sh create mode 100755 bacnet-stack/bin/error-code.sh create mode 100644 bacnet-stack/demo/abort/Makefile create mode 100644 bacnet-stack/demo/abort/main.c create mode 100644 bacnet-stack/demo/error/Makefile create mode 100644 bacnet-stack/demo/error/main.c create mode 100644 bacnet-stack/demo/handler/s_abort.c create mode 100644 bacnet-stack/demo/handler/s_error.c diff --git a/bacnet-stack/Makefile b/bacnet-stack/Makefile index 23a23d99..b3db5ef4 100644 --- a/bacnet-stack/Makefile +++ b/bacnet-stack/Makefile @@ -80,6 +80,12 @@ iam: uevent: $(MAKE) -B -C demo uevent +abort: + $(MAKE) -B -C demo abort + +error: + $(MAKE) -B -C demo error + router: $(MAKE) -s -C demo router diff --git a/bacnet-stack/bin/abort-reason.sh b/bacnet-stack/bin/abort-reason.sh new file mode 100755 index 00000000..09bba2f9 --- /dev/null +++ b/bacnet-stack/bin/abort-reason.sh @@ -0,0 +1,11 @@ +#!/bin/bash +export BACNET_APDU_RETRIES=0 +export BACNET_APDU_TIMEOUT=0 + +# bacabort [abort-reason invoke-id server] + +# BACnetAbortReason +for reason in {0..64} +do + ./bin/bacabort ${reason} +done diff --git a/bacnet-stack/bin/error-code.sh b/bacnet-stack/bin/error-code.sh new file mode 100755 index 00000000..20baf8cb --- /dev/null +++ b/bacnet-stack/bin/error-code.sh @@ -0,0 +1,12 @@ +#!/bin/bash +export BACNET_APDU_RETRIES=0 +export BACNET_APDU_TIMEOUT=0 + +# bacabort [invoke-id abort-reason server] + +# BACnetErrorCode +export error_class=0 +for error_code in {0..256} +do + ./bin/bacerror ${error_class} ${error_code} +done diff --git a/bacnet-stack/demo/Makefile b/bacnet-stack/demo/Makefile index 91f56140..d5702470 100644 --- a/bacnet-stack/demo/Makefile +++ b/bacnet-stack/demo/Makefile @@ -57,7 +57,7 @@ LFLAGS := -Wl,$(BACNET_LIB),$(SYSTEM_LIB) SUBDIRS = readprop writeprop readfile writefile reinit server dcc \ whohas whois iam ucov scov timesync epics readpropm readrange \ - uptransfer getevent + uptransfer getevent uevent abort error ifeq (${BACDL_DEFINE},-DBACDL_BIP=1) SUBDIRS += whoisrouter iamrouter initrouter readbdt @@ -95,5 +95,11 @@ iam: uevent: $(MAKE) -b -C uevent +abort: + $(MAKE) -b -C abort + +error: + $(MAKE) -b -C error + router: $(MAKE) -s -b -C router diff --git a/bacnet-stack/demo/abort/Makefile b/bacnet-stack/demo/abort/Makefile new file mode 100644 index 00000000..2cce0f74 --- /dev/null +++ b/bacnet-stack/demo/abort/Makefile @@ -0,0 +1,38 @@ +#Makefile to build BACnet Application for the Linux Port + +# tools - only if you need them. +# Most platforms have this already defined +# CC = gcc + +TARGET = bacabort + +TARGET_BIN = ${TARGET}$(TARGET_EXT) + +SRCS = main.c \ + ../object/device-client.c + +OBJS = ${SRCS:.c=.o} + +all: ${BACNET_LIB_TARGET} Makefile ${TARGET_BIN} + +${TARGET_BIN}: ${OBJS} Makefile ${BACNET_LIB_TARGET} + ${CC} ${PFLAGS} ${OBJS} ${LFLAGS} -o $@ + size $@ + cp $@ ../../bin + +lib: ${BACNET_LIB_TARGET} + +${BACNET_LIB_TARGET}: + ( cd ${BACNET_LIB_DIR} ; $(MAKE) clean ; $(MAKE) ) + +.c.o: + ${CC} -c ${CFLAGS} $*.c -o $@ + +depend: + rm -f .depend + ${CC} -MM ${CFLAGS} *.c >> .depend + +clean: + rm -f core ${TARGET_BIN} ${OBJS} ${BACNET_LIB_TARGET} $(TARGET).map + +include: .depend diff --git a/bacnet-stack/demo/abort/main.c b/bacnet-stack/demo/abort/main.c new file mode 100644 index 00000000..c3260a7e --- /dev/null +++ b/bacnet-stack/demo/abort/main.c @@ -0,0 +1,248 @@ +/************************************************************************** +* +* Copyright (C) 2016 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. +* +*********************************************************************/ + +/* command line tool that sends a BACnet service */ +#include +#include +#include +#include +#include /* for time */ +#include +#include "bactext.h" +#include "iam.h" +#include "address.h" +#include "config.h" +#include "bacdef.h" +#include "npdu.h" +#include "apdu.h" +#include "device.h" +#include "datalink.h" +#include "version.h" +/* some demo stuff needed */ +#include "filename.h" +#include "handlers.h" +#include "client.h" +#include "txbuf.h" +#include "dlenv.h" + +/* parsed command line parameters */ +static uint8_t Target_Invoke_ID = 1; +static uint16_t Target_Abort_Reason; +static bool Target_Server = true; +/* flag for signalling errors */ +static bool Error_Detected = false; + +void MyAbortHandler( + BACNET_ADDRESS * src, + uint8_t invoke_id, + uint8_t abort_reason, + bool server) +{ + (void) src; + (void) invoke_id; + (void) server; + printf("BACnet Abort: %s\n", bactext_abort_reason_name(abort_reason)); + Error_Detected = true; +} + +void MyRejectHandler( + BACNET_ADDRESS * src, + uint8_t invoke_id, + uint8_t reject_reason) +{ + (void) src; + (void) invoke_id; + printf("BACnet Reject: %s\n", bactext_reject_reason_name(reject_reason)); + Error_Detected = true; +} + +static void Init_Service_Handlers( + void) +{ + Device_Init(NULL); + /* 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_AM, handler_i_am_add); + /* handle any errors coming back */ + apdu_set_abort_handler(MyAbortHandler); + apdu_set_reject_handler(MyRejectHandler); +} + +static void print_usage(char *filename) +{ + printf("Usage: %s [abort-reason [invoke-id [server]]]\n", + filename); + printf(" [--version][--help]\n"); +} + +static void print_help(char *filename) +{ + printf("Send BACnet Abort message to the network.\n"); + printf("--mac A\n" + "Optional destination BACnet mac address." + "Valid ranges are from 00 to FF (hex) for MS/TP or ARCNET,\n" + "or an IP string with optional port number like 10.1.2.3:47808\n" + "or an Ethernet MAC in hex like 00:21:70:7e:32:bb\n" + "\n" + "--dnet N\n" + "Optional destination BACnet network number N for directed requests.\n" + "Valid range is from 0 to 65535 where 0 is the local connection\n" + "and 65535 is network broadcast.\n" + "\n" + "--dadr A\n" + "Optional BACnet mac address on the destination BACnet network number.\n" + "Valid ranges are from 00 to FF (hex) for MS/TP or ARCNET,\n" + "or an IP string with optional port number like 10.1.2.3:47808\n" + "or an Ethernet MAC in hex like 00:21:70:7e:32:bb\n" + "\n"); + printf("abort-reason:\n" + " number from 0 to 65535\n" + "invoke-id:\n" + " number from 1 to 255\n" + "server:\n" + " 0=false, 1=true\n" + "Example:\n" + "%s 3 2 1\n", + filename); +} + +int main( + int argc, + char *argv[]) +{ + long dnet = -1; + BACNET_MAC_ADDRESS mac = { 0 }; + BACNET_MAC_ADDRESS adr = { 0 }; + BACNET_ADDRESS dest = { 0 }; + bool specific_address = false; + int argi = 0; + unsigned int target_args = 0; + char *filename = NULL; + + filename = filename_remove_path(argv[0]); + for (argi = 1; argi < argc; argi++) { + if (strcmp(argv[argi], "--help") == 0) { + print_usage(filename); + print_help(filename); + return 0; + } + if (strcmp(argv[argi], "--version") == 0) { + printf("%s %s\n", filename, BACNET_VERSION_TEXT); + printf("Copyright (C) 2016 by Steve Karg and others.\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or\n" + "FITNESS FOR A PARTICULAR PURPOSE.\n"); + return 0; + } + if (strcmp(argv[argi], "--mac") == 0) { + if (++argi < argc) { + if (address_mac_from_ascii(&mac, argv[argi])) { + specific_address = true; + } + } + } else if (strcmp(argv[argi], "--dnet") == 0) { + if (++argi < argc) { + dnet = strtol(argv[argi], NULL, 0); + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + specific_address = true; + } + } + } else if (strcmp(argv[argi], "--dadr") == 0) { + if (++argi < argc) { + if (address_mac_from_ascii(&adr, argv[argi])) { + specific_address = true; + } + } + } else { + if (target_args == 0) { + Target_Abort_Reason = strtol(argv[argi], NULL, 0); + target_args++; + } else if (target_args == 1) { + Target_Invoke_ID = strtol(argv[argi], NULL, 0); + target_args++; + } else if (target_args == 2) { + Target_Server = strtol(argv[argi], NULL, 0); + target_args++; + } else { + print_usage(filename); + return 1; + } + } + } + address_init(); + if (specific_address) { + if (adr.len && mac.len) { + memcpy(&dest.mac[0], &mac.adr[0], mac.len); + dest.mac_len = mac.len; + memcpy(&dest.adr[0], &adr.adr[0], adr.len); + dest.len = adr.len; + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + dest.net = dnet; + } else { + dest.net = BACNET_BROADCAST_NETWORK; + } + } else if (mac.len) { + memcpy(&dest.mac[0], &mac.adr[0], mac.len); + dest.mac_len = mac.len; + dest.len = 0; + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + dest.net = dnet; + } else { + dest.net = 0; + } + } else { + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + dest.net = dnet; + } else { + dest.net = BACNET_BROADCAST_NETWORK; + } + dest.mac_len = 0; + dest.len = 0; + } + } + /* setup my info */ + Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); + Init_Service_Handlers(); + address_init(); + dlenv_init(); + atexit(datalink_cleanup); + /* send the request */ + Send_Abort_To_Network(&Handler_Transmit_Buffer[0], + &dest, + Target_Invoke_ID, + Target_Abort_Reason, + Target_Server); + + return 0; +} diff --git a/bacnet-stack/demo/error/Makefile b/bacnet-stack/demo/error/Makefile new file mode 100644 index 00000000..3ca05df8 --- /dev/null +++ b/bacnet-stack/demo/error/Makefile @@ -0,0 +1,38 @@ +#Makefile to build BACnet Application for the Linux Port + +# tools - only if you need them. +# Most platforms have this already defined +# CC = gcc + +TARGET = bacerror + +TARGET_BIN = ${TARGET}$(TARGET_EXT) + +SRCS = main.c \ + ../object/device-client.c + +OBJS = ${SRCS:.c=.o} + +all: ${BACNET_LIB_TARGET} Makefile ${TARGET_BIN} + +${TARGET_BIN}: ${OBJS} Makefile ${BACNET_LIB_TARGET} + ${CC} ${PFLAGS} ${OBJS} ${LFLAGS} -o $@ + size $@ + cp $@ ../../bin + +lib: ${BACNET_LIB_TARGET} + +${BACNET_LIB_TARGET}: + ( cd ${BACNET_LIB_DIR} ; $(MAKE) clean ; $(MAKE) ) + +.c.o: + ${CC} -c ${CFLAGS} $*.c -o $@ + +depend: + rm -f .depend + ${CC} -MM ${CFLAGS} *.c >> .depend + +clean: + rm -f core ${TARGET_BIN} ${OBJS} ${BACNET_LIB_TARGET} $(TARGET).map + +include: .depend diff --git a/bacnet-stack/demo/error/main.c b/bacnet-stack/demo/error/main.c new file mode 100644 index 00000000..72db6fcf --- /dev/null +++ b/bacnet-stack/demo/error/main.c @@ -0,0 +1,255 @@ +/************************************************************************** +* +* Copyright (C) 2016 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. +* +*********************************************************************/ + +/* command line tool that sends a BACnet service */ +#include +#include +#include +#include +#include /* for time */ +#include +#include "bactext.h" +#include "iam.h" +#include "address.h" +#include "config.h" +#include "bacdef.h" +#include "npdu.h" +#include "apdu.h" +#include "device.h" +#include "datalink.h" +#include "version.h" +/* some demo stuff needed */ +#include "filename.h" +#include "handlers.h" +#include "client.h" +#include "txbuf.h" +#include "dlenv.h" + +/* parsed command line parameters */ +static uint16_t Target_Error_Class; +static uint16_t Target_Error_Code; +static uint8_t Target_Invoke_ID = 1; +static uint16_t Target_Service = SERVICE_CONFIRMED_READ_PROPERTY; +/* flag for signalling errors */ +static bool Error_Detected = false; + +void MyAbortHandler( + BACNET_ADDRESS * src, + uint8_t invoke_id, + uint8_t abort_reason, + bool server) +{ + (void) src; + (void) invoke_id; + (void) server; + printf("BACnet Abort: %s\n", bactext_abort_reason_name(abort_reason)); + Error_Detected = true; +} + +void MyRejectHandler( + BACNET_ADDRESS * src, + uint8_t invoke_id, + uint8_t reject_reason) +{ + (void) src; + (void) invoke_id; + printf("BACnet Reject: %s\n", bactext_reject_reason_name(reject_reason)); + Error_Detected = true; +} + +static void Init_Service_Handlers( + void) +{ + Device_Init(NULL); + /* 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_AM, handler_i_am_add); + /* handle any errors coming back */ + apdu_set_abort_handler(MyAbortHandler); + apdu_set_reject_handler(MyRejectHandler); +} + +static void print_usage(char *filename) +{ + printf("Usage: %s [error-class error-code service-number invoke-id]\n", + filename); + printf(" [--version][--help]\n"); +} + +static void print_help(char *filename) +{ + printf("Send BACnet Error message to the network.\n"); + printf("--mac A\n" + "Optional destination BACnet mac address." + "Valid ranges are from 00 to FF (hex) for MS/TP or ARCNET,\n" + "or an IP string with optional port number like 10.1.2.3:47808\n" + "or an Ethernet MAC in hex like 00:21:70:7e:32:bb\n" + "\n" + "--dnet N\n" + "Optional destination BACnet network number N for directed requests.\n" + "Valid range is from 0 to 65535 where 0 is the local connection\n" + "and 65535 is network broadcast.\n" + "\n" + "--dadr A\n" + "Optional BACnet mac address on the destination BACnet network number.\n" + "Valid ranges are from 00 to FF (hex) for MS/TP or ARCNET,\n" + "or an IP string with optional port number like 10.1.2.3:47808\n" + "or an Ethernet MAC in hex like 00:21:70:7e:32:bb\n" + "\n"); + printf("error-class:\n" + " number from 0 to 65535\n" + "error-code:\n" + " number from 0 to 65535\n" + "service-number:\n" + " number from 0 to 65535 for BACnet Services\n" + "invoke-id:\n" + " number from 1 to 255\n" + "Example:\n" + "%s 3 2 1\n", + filename); +} + +int main( + int argc, + char *argv[]) +{ + long dnet = -1; + BACNET_MAC_ADDRESS mac = { 0 }; + BACNET_MAC_ADDRESS adr = { 0 }; + BACNET_ADDRESS dest = { 0 }; + bool specific_address = false; + int argi = 0; + unsigned int target_args = 0; + char *filename = NULL; + + filename = filename_remove_path(argv[0]); + for (argi = 1; argi < argc; argi++) { + if (strcmp(argv[argi], "--help") == 0) { + print_usage(filename); + print_help(filename); + return 0; + } + if (strcmp(argv[argi], "--version") == 0) { + printf("%s %s\n", filename, BACNET_VERSION_TEXT); + printf("Copyright (C) 2016 by Steve Karg and others.\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or\n" + "FITNESS FOR A PARTICULAR PURPOSE.\n"); + return 0; + } + if (strcmp(argv[argi], "--mac") == 0) { + if (++argi < argc) { + if (address_mac_from_ascii(&mac, argv[argi])) { + specific_address = true; + } + } + } else if (strcmp(argv[argi], "--dnet") == 0) { + if (++argi < argc) { + dnet = strtol(argv[argi], NULL, 0); + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + specific_address = true; + } + } + } else if (strcmp(argv[argi], "--dadr") == 0) { + if (++argi < argc) { + if (address_mac_from_ascii(&adr, argv[argi])) { + specific_address = true; + } + } + } else { + if (target_args == 0) { + Target_Error_Class = strtol(argv[argi], NULL, 0); + target_args++; + } else if (target_args == 1) { + Target_Error_Code = strtol(argv[argi], NULL, 0); + target_args++; + } else if (target_args == 2) { + Target_Service = strtol(argv[argi], NULL, 0); + target_args++; + } else if (target_args == 2) { + Target_Invoke_ID = strtol(argv[argi], NULL, 0); + target_args++; + } else { + print_usage(filename); + return 1; + } + } + } + address_init(); + if (specific_address) { + if (adr.len && mac.len) { + memcpy(&dest.mac[0], &mac.adr[0], mac.len); + dest.mac_len = mac.len; + memcpy(&dest.adr[0], &adr.adr[0], adr.len); + dest.len = adr.len; + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + dest.net = dnet; + } else { + dest.net = BACNET_BROADCAST_NETWORK; + } + } else if (mac.len) { + memcpy(&dest.mac[0], &mac.adr[0], mac.len); + dest.mac_len = mac.len; + dest.len = 0; + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + dest.net = dnet; + } else { + dest.net = 0; + } + } else { + if ((dnet >= 0) && (dnet <= BACNET_BROADCAST_NETWORK)) { + dest.net = dnet; + } else { + dest.net = BACNET_BROADCAST_NETWORK; + } + dest.mac_len = 0; + dest.len = 0; + } + } + /* setup my info */ + Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); + Init_Service_Handlers(); + address_init(); + dlenv_init(); + atexit(datalink_cleanup); + /* send the request */ + Send_Error_To_Network(&Handler_Transmit_Buffer[0], + &dest, + Target_Invoke_ID, + Target_Service, + Target_Error_Class, + Target_Error_Code); + + return 0; +} diff --git a/bacnet-stack/demo/handler/s_abort.c b/bacnet-stack/demo/handler/s_abort.c new file mode 100644 index 00000000..71d54cf9 --- /dev/null +++ b/bacnet-stack/demo/handler/s_abort.c @@ -0,0 +1,108 @@ +/************************************************************************** +* +* Copyright (C) 2016 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 "config.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "abort.h" +#include "address.h" +#include "tsm.h" +#include "dcc.h" +#include "npdu.h" +#include "apdu.h" +#include "device.h" +#include "datalink.h" +#include "iam.h" +#include "txbuf.h" +/* some demo stuff needed */ +#include "handlers.h" +#include "client.h" + + +/** Encodes an Abort message + * @param buffer The buffer to build the message for sending. + * @param dest - Destination address to send the message + * @param src - Source address from which the message originates + * @param npdu_data - buffer to hold NPDU data encoded + * @param invoke_id - use to match up a reply + * @param reason - #BACNET_ABORT_REASON enumeration + * @param server - true or false + * + * @return Size of the message sent (bytes), or a negative value on error. + */ +int abort_encode_pdu( + uint8_t * buffer, + BACNET_ADDRESS * dest, + BACNET_ADDRESS * src, + BACNET_NPDU_DATA * npdu_data, + uint8_t invoke_id, + BACNET_ABORT_REASON reason, + bool server) +{ + int len = 0; + int pdu_len = 0; + + /* encode the NPDU portion of the packet */ + npdu_encode_npdu_data(npdu_data, false, MESSAGE_PRIORITY_NORMAL); + pdu_len = npdu_encode_pdu(&buffer[0], dest, src, npdu_data); + + /* encode the APDU portion of the packet */ + len = abort_encode_apdu(&buffer[pdu_len], invoke_id, reason, server); + pdu_len += len; + + return pdu_len; +} + +/** Sends an Abort message + * @param buffer The buffer to build the message for sending. + * @param dest - Destination address to send the message + * @param invoke_id - use to match up a reply + * @param reason - #BACNET_ABORT_REASON enumeration + * @param server - true or false + * + * @return Size of the message sent (bytes), or a negative value on error. + */ +int Send_Abort_To_Network( + uint8_t * buffer, + BACNET_ADDRESS *dest, + uint8_t invoke_id, + BACNET_ABORT_REASON reason, + bool server) +{ + int pdu_len = 0; + BACNET_ADDRESS src; + int bytes_sent = 0; + BACNET_NPDU_DATA npdu_data; + + datalink_get_my_address(&src); + pdu_len = abort_encode_pdu(buffer, dest, &src, &npdu_data, + invoke_id, reason, server); + bytes_sent = datalink_send_pdu(dest, &npdu_data, &buffer[0], pdu_len); + + return bytes_sent; +} diff --git a/bacnet-stack/demo/handler/s_error.c b/bacnet-stack/demo/handler/s_error.c new file mode 100644 index 00000000..091b98de --- /dev/null +++ b/bacnet-stack/demo/handler/s_error.c @@ -0,0 +1,110 @@ +/************************************************************************** +* +* Copyright (C) 2016 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 "config.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "bacerror.h" +#include "address.h" +#include "tsm.h" +#include "dcc.h" +#include "npdu.h" +#include "apdu.h" +#include "device.h" +#include "datalink.h" +/* some demo stuff needed */ +#include "handlers.h" +#include "client.h" + + +/** Encodes an Error message + * @param buffer The buffer to build the message for sending. + * @param dest - Destination address to send the message + * @param src - Source address from which the message originates + * @param npdu_data - buffer to hold NPDU data encoded + * @param invoke_id - use to match up a reply + * @param reason - #BACNET_ABORT_REASON enumeration + * @param server - true or false + * + * @return Size of the message sent (bytes), or a negative value on error. + */ +int error_encode_pdu( + uint8_t * buffer, + BACNET_ADDRESS * dest, + BACNET_ADDRESS * src, + BACNET_NPDU_DATA * npdu_data, + uint8_t invoke_id, + BACNET_CONFIRMED_SERVICE service, + BACNET_ERROR_CLASS error_class, + BACNET_ERROR_CODE error_code) +{ + int len = 0; + int pdu_len = 0; + + /* encode the NPDU portion of the packet */ + npdu_encode_npdu_data(npdu_data, false, MESSAGE_PRIORITY_NORMAL); + pdu_len = npdu_encode_pdu(&buffer[0], dest, src, npdu_data); + + /* encode the APDU portion of the packet */ + len = bacerror_encode_apdu(&buffer[pdu_len], invoke_id, + service, error_class, error_code); + pdu_len += len; + + return pdu_len; +} + +/** Sends an Abort message + * @param buffer The buffer to build the message for sending. + * @param dest - Destination address to send the message + * @param invoke_id - use to match up a reply + * @param reason - #BACNET_ABORT_REASON enumeration + * @param server - true or false + * + * @return Size of the message sent (bytes), or a negative value on error. + */ +int Send_Error_To_Network( + uint8_t * buffer, + BACNET_ADDRESS *dest, + uint8_t invoke_id, + BACNET_CONFIRMED_SERVICE service, + BACNET_ERROR_CLASS error_class, + BACNET_ERROR_CODE error_code) +{ + int pdu_len = 0; + BACNET_ADDRESS src; + int bytes_sent = 0; + BACNET_NPDU_DATA npdu_data; + + datalink_get_my_address(&src); + pdu_len = error_encode_pdu(buffer, dest, &src, &npdu_data, + invoke_id, service, error_class, error_code); + bytes_sent = datalink_send_pdu(dest, &npdu_data, &buffer[0], pdu_len); + + return bytes_sent; +} diff --git a/bacnet-stack/include/client.h b/bacnet-stack/include/client.h index 10acdb7a..0dcaf3e5 100644 --- a/bacnet-stack/include/client.h +++ b/bacnet-stack/include/client.h @@ -263,6 +263,40 @@ extern "C" { uint32_t device_id, BACNET_OBJECT_ID * lastReceivedObjectIdentifier); + int Send_Abort_To_Network( + uint8_t * buffer, + BACNET_ADDRESS *dest, + uint8_t invoke_id, + BACNET_ABORT_REASON reason, + bool server); + + int abort_encode_pdu( + uint8_t * buffer, + BACNET_ADDRESS * dest, + BACNET_ADDRESS * src, + BACNET_NPDU_DATA * npdu_data, + uint8_t invoke_id, + BACNET_ABORT_REASON reason, + bool server); + + int Send_Error_To_Network( + uint8_t * buffer, + BACNET_ADDRESS *dest, + uint8_t invoke_id, + BACNET_CONFIRMED_SERVICE service, + BACNET_ERROR_CLASS error_class, + BACNET_ERROR_CODE error_code); + + int error_encode_pdu( + uint8_t * buffer, + BACNET_ADDRESS * dest, + BACNET_ADDRESS * src, + BACNET_NPDU_DATA * npdu_data, + uint8_t invoke_id, + BACNET_CONFIRMED_SERVICE service, + BACNET_ERROR_CLASS error_class, + BACNET_ERROR_CODE error_code); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/lib/Makefile b/bacnet-stack/lib/Makefile index 35d84d53..020fc40d 100644 --- a/bacnet-stack/lib/Makefile +++ b/bacnet-stack/lib/Makefile @@ -111,9 +111,11 @@ HANDLER_SRC = \ $(BACNET_HANDLER)/h_pt.c \ $(BACNET_HANDLER)/h_pt_a.c \ $(BACNET_HANDLER)/h_upt.c \ + $(BACNET_HANDLER)/s_abort.c \ $(BACNET_HANDLER)/s_arfs.c \ $(BACNET_HANDLER)/s_awfs.c \ $(BACNET_HANDLER)/s_dcc.c \ + $(BACNET_HANDLER)/s_error.c \ $(BACNET_HANDLER)/s_ihave.c \ $(BACNET_HANDLER)/s_get_alarm_sum.c \ $(BACNET_HANDLER)/s_get_event.c \