From 0ea1bf30bf67f67fbc627617d2b93adfeb1d05ee Mon Sep 17 00:00:00 2001 From: skarg Date: Sat, 14 Jan 2006 23:48:03 +0000 Subject: [PATCH] refactored handlers.c into a bunch of little individual files in the demo/handler/ directory. Handlers begin with h_, and Send files begin with s_. The Send files are prototyped in client.h. --- bacnet-stack/Makefile | 15 ++- bacnet-stack/bacdcode.h | 16 +-- bacnet-stack/demo/handler/client.h | 65 ++++++++++ bacnet-stack/demo/handler/h_arf.c | 158 +++++++++++++++++++++++ bacnet-stack/demo/handler/h_arf_a.c | 100 +++++++++++++++ bacnet-stack/demo/handler/h_iam.c | 2 + bacnet-stack/demo/handler/h_rp_a.c | 81 ++++++++++++ bacnet-stack/demo/handler/h_wp.c | 176 ++++++++++++++++++++++++++ bacnet-stack/demo/handler/handlers.h | 25 ++++ bacnet-stack/demo/handler/s_rp.c | 113 +++++++++++++++++ bacnet-stack/demo/handler/s_whois.c | 77 +++++++++++ bacnet-stack/demo/handler/s_wp.c | 118 +++++++++++++++++ bacnet-stack/demo/handler/txbuf.h | 2 +- bacnet-stack/demo/readfile/readfile.c | 15 ++- bacnet-stack/ports/linux/main.c | 21 +-- bacnet-stack/readfile.mak | 71 +++++++++++ 16 files changed, 1028 insertions(+), 27 deletions(-) create mode 100644 bacnet-stack/demo/handler/client.h create mode 100644 bacnet-stack/demo/handler/h_arf.c create mode 100644 bacnet-stack/demo/handler/h_arf_a.c create mode 100644 bacnet-stack/demo/handler/h_rp_a.c create mode 100644 bacnet-stack/demo/handler/h_wp.c create mode 100644 bacnet-stack/demo/handler/s_rp.c create mode 100644 bacnet-stack/demo/handler/s_whois.c create mode 100644 bacnet-stack/demo/handler/s_wp.c create mode 100644 bacnet-stack/readfile.mak diff --git a/bacnet-stack/Makefile b/bacnet-stack/Makefile index 1b1403dc..55544b94 100644 --- a/bacnet-stack/Makefile +++ b/bacnet-stack/Makefile @@ -10,7 +10,7 @@ BASEDIR = . #DEFINES = -DBACFILE=1 -DBACDL_ARCNET=1 #DEFINES = -DBACFILE=1 -DBACDL_MSTP=1 DEFINES = -DBACFILE=1 -DBACDL_BIP=1 -INCLUDES = -I. -Iports/linux -Idemo/object +INCLUDES = -I. -Iports/linux -Idemo/object -Idemo/handler CFLAGS = -Wall -g $(INCLUDES) $(DEFINES) @@ -20,7 +20,18 @@ SRCS = ports/linux/main.c \ ports/linux/bip-init.c \ bip.c \ dlmstp.c \ - handlers.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_iam.c \ + demo/handler/h_rp_a.c \ + demo/handler/h_arf.c \ + demo/handler/h_arf_a.c \ + demo/handler/s_rp.c \ + demo/handler/s_whois.c \ + demo/handler/s_wp.c \ bacdcode.c \ bacapp.c \ bacprop.c \ diff --git a/bacnet-stack/bacdcode.h b/bacnet-stack/bacdcode.h index 1b1082bc..8071261a 100644 --- a/bacnet-stack/bacdcode.h +++ b/bacnet-stack/bacdcode.h @@ -121,18 +121,18 @@ int decode_character_string(uint8_t * apdu, uint32_t len_value, // from clause 20.2.4 Encoding of an Unsigned Integer Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed -int encode_bacnet_unsigned(uint8_t * apdu, unsigned int value); -int encode_context_unsigned(uint8_t * apdu, int tag_number, int value); -int encode_tagged_unsigned(uint8_t * apdu, unsigned int value); -int decode_unsigned(uint8_t * apdu, uint32_t len_value, unsigned int *value); +int encode_bacnet_unsigned(uint8_t * apdu, uint32_t value); +int encode_context_unsigned(uint8_t * apdu, int tag_number, uint32_t value); +int encode_tagged_unsigned(uint8_t * apdu, uint32_t value); +int decode_unsigned(uint8_t * apdu, uint32_t len_value, uint32_t *value); // from clause 20.2.5 Encoding of a Signed Integer Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed -int encode_bacnet_signed(uint8_t * apdu, int value); -int encode_tagged_signed(uint8_t * apdu, int value); -int encode_context_signed(uint8_t * apdu, int tag_number, int value); -int decode_signed(uint8_t * apdu, uint32_t len_value, int *value); +int encode_bacnet_signed(uint8_t * apdu, int32_t value); +int encode_tagged_signed(uint8_t * apdu, int32_t value); +int encode_context_signed(uint8_t * apdu, int tag_number, int32_t value); +int decode_signed(uint8_t * apdu, uint32_t len_value, int32_t *value); // from clause 20.2.11 Encoding of an Enumerated Value // and 20.2.1 General Rules for Encoding BACnet Tags diff --git a/bacnet-stack/demo/handler/client.h b/bacnet-stack/demo/handler/client.h new file mode 100644 index 00000000..b3b6d58e --- /dev/null +++ b/bacnet-stack/demo/handler/client.h @@ -0,0 +1,65 @@ +/************************************************************************** +* +* Copyright (C) 2005 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. +* +*********************************************************************/ +#ifndef CLIENT_H +#define CLIENT_H + +#include +#include +#include +#include "bacdef.h" +#include "apdu.h" +#include "bacapp.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* FIXME: probably should return the invoke ID for confirmed request */ +bool Send_Read_Property_Request( + uint32_t device_id, /* destination device */ + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property, + int32_t array_index); + +void Send_WhoIs( + int32_t low_limit, + int32_t high_limit); + +/* FIXME: probably should return the invoke ID for confirmed request */ +bool 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); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/bacnet-stack/demo/handler/h_arf.c b/bacnet-stack/demo/handler/h_arf.c new file mode 100644 index 00000000..c71feb2b --- /dev/null +++ b/bacnet-stack/demo/handler/h_arf.c @@ -0,0 +1,158 @@ +/************************************************************************** +* +* Copyright (C) 2005 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 "config.h" +#include "txbuf.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "apdu.h" +#include "npdu.h" +#include "abort.h" +#include "rp.h" +/* demo objects */ +#include "device.h" +#include "ai.h" +#include "ao.h" +#if BACFILE +#include "bacfile.h" +#endif + +void handler_atomic_read_file( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_DATA *service_data) +{ + BACNET_ATOMIC_READ_FILE_DATA data; + int len = 0; + int pdu_len = 0; + BACNET_ADDRESS my_address; + bool send = false; + bool error = false; + int bytes_sent = 0; + BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; + BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; + + fprintf(stderr,"Received Atomic-Read-File Request!\n"); + len = arf_decode_service_request( + service_request, + service_len, + &data); + if (len < 0) + fprintf(stderr,"Unable to decode Atomic-Read-File Request!\n"); + // prepare a reply + datalink_get_my_address(&my_address); + // encode the NPDU portion of the packet + pdu_len = npdu_encode_apdu( + &Handler_Transmit_Buffer[0], + src, + &my_address, + false, // true for confirmed messages + MESSAGE_PRIORITY_NORMAL); + // bad decoding - send an abort + if (len < 0) + { + pdu_len += abort_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + ABORT_REASON_OTHER); + fprintf(stderr,"Sending Abort!\n"); + send = true; + } + else if (service_data->segmented_message) + { + pdu_len += abort_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + ABORT_REASON_SEGMENTATION_NOT_SUPPORTED); + fprintf(stderr,"Sending Abort!\n"); + send = true; + } + else + { + if (data.access == FILE_STREAM_ACCESS) + { + if (data.type.stream.requestedOctetCount < + octetstring_capacity(&data.fileData)) + { + if (bacfile_read_data(&data)) + { + pdu_len += arf_ack_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + &data); + send = true; + } + else + { + send = true; + error = true; + } + } + else + { + pdu_len += abort_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + ABORT_REASON_SEGMENTATION_NOT_SUPPORTED); + fprintf(stderr,"Sending Abort!\n"); + send = true; + } + } + else + { + error_class = ERROR_CLASS_SERVICES; + error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD; + send = true; + error = true; + } + } + if (error) + { + pdu_len += bacerror_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_ATOMIC_READ_FILE, + error_class, + error_code); + fprintf(stderr,"Sending Error!\n"); + send = true; + } + if (send) + { + bytes_sent = datalink_send_pdu( + src, // destination address + &Handler_Transmit_Buffer[0], + pdu_len); // number of bytes of data + if (bytes_sent <= 0) + fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno)); + } + + return; +} diff --git a/bacnet-stack/demo/handler/h_arf_a.c b/bacnet-stack/demo/handler/h_arf_a.c new file mode 100644 index 00000000..ccff7a59 --- /dev/null +++ b/bacnet-stack/demo/handler/h_arf_a.c @@ -0,0 +1,100 @@ +/************************************************************************** +* +* Copyright (C) 2005 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 "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 "arf.h" +#include "bacfile.h" +/* some demo stuff needed */ +#include "handlers.h" +#include "txbuf.h" + +// We performed an AtomicReadFile Request, +// and here is the data from the server +// Note: it does not have to be the same file=instance +// that someone can read from us. It is common to +// use the description as the file name. +#if BACFILE +void handler_atomic_read_file_ack( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data) +{ + int len = 0; + BACNET_ATOMIC_READ_FILE_DATA data; + FILE *pFile = NULL; + char *pFilename = NULL; + uint32_t instance = 0; + + (void)src; + // get the file instance from the tsm data before freeing it + instance = bacfile_instance_from_tsm(service_data->invoke_id); + len = arf_ack_decode_service_request( + service_request, + service_len, + &data); + fprintf(stderr,"Received Read-File Ack!\n"); + if ((len > 0) && (instance <= BACNET_MAX_INSTANCE)) + { + // write the data received to the file specified + if (data.access == FILE_STREAM_ACCESS) + { + pFilename = bacfile_name(instance); + if (pFilename) + { + pFile = fopen(pFilename, "rb"); + if (pFile) + { + (void)fseek(pFile, + data.type.stream.fileStartPosition, + SEEK_SET); + if (fwrite(octetstring_value(&data.fileData), + octetstring_length(&data.fileData),1,pFile) != 1) + fprintf(stderr,"Failed to write to %s (%u)!\n", + pFilename, instance); + fclose(pFile); + } + } + } + else if (data.access == FILE_RECORD_ACCESS) + { + // FIXME: add handling for Record Access + } + } +} +#endif + + diff --git a/bacnet-stack/demo/handler/h_iam.c b/bacnet-stack/demo/handler/h_iam.c index 0556bb7f..559d5208 100644 --- a/bacnet-stack/demo/handler/h_iam.c +++ b/bacnet-stack/demo/handler/h_iam.c @@ -28,6 +28,8 @@ #include "txbuf.h" #include "bacdef.h" #include "bacdcode.h" +#include "iam.h" +#include "address.h" void handler_i_am( uint8_t *service_request, diff --git a/bacnet-stack/demo/handler/h_rp_a.c b/bacnet-stack/demo/handler/h_rp_a.c new file mode 100644 index 00000000..35f97331 --- /dev/null +++ b/bacnet-stack/demo/handler/h_rp_a.c @@ -0,0 +1,81 @@ +/************************************************************************** +* +* Copyright (C) 2005 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 "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 "bactext.h" +#include "rp.h" +/* some demo stuff needed */ +#include "handlers.h" +#include "txbuf.h" + +/* for debugging... */ +static void PrintReadPropertyData(BACNET_READ_PROPERTY_DATA *data) +{ + if (data) + { + if (data->array_index == BACNET_ARRAY_ALL) + fprintf(stderr,"%s #%u %s\n", + bactext_object_type_name(data->object_type), + data->object_instance, + bactext_property_name(data->object_property)); + else + fprintf(stderr,"%s #%u %s[%d]\n", + bactext_object_type_name(data->object_type), + data->object_instance, + bactext_property_name(data->object_property), + data->array_index); + } +} + +void handler_read_property_ack( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data) +{ + int len = 0; + BACNET_READ_PROPERTY_DATA data; + + (void)src; + (void)service_data; /* we could use these... */ + len = rp_ack_decode_service_request( + service_request, + service_len, + &data); + fprintf(stderr,"Received Read-Property Ack!\n"); + if (len > 0) + PrintReadPropertyData(&data); +} diff --git a/bacnet-stack/demo/handler/h_wp.c b/bacnet-stack/demo/handler/h_wp.c new file mode 100644 index 00000000..ef4103ec --- /dev/null +++ b/bacnet-stack/demo/handler/h_wp.c @@ -0,0 +1,176 @@ +/************************************************************************** +* +* Copyright (C) 2005 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 "config.h" +#include "txbuf.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "apdu.h" +#include "npdu.h" +#include "abort.h" +#include "wp.h" +/* demo objects */ +#include "device.h" +#include "ai.h" +#include "ao.h" +#if BACFILE +#include "bacfile.h" +#endif + +static uint8_t Temp_Buf[MAX_APDU] = {0}; + +void handler_write_property( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_DATA *service_data) +{ + BACNET_WRITE_PROPERTY_DATA wp_data; + int len = 0; + int pdu_len = 0; + BACNET_ADDRESS my_address; + BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; + BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; + int bytes_sent = 0; + + // decode the service request only + len = wp_decode_service_request( + service_request, + service_len, + &wp_data); + fprintf(stderr,"Received Write-Property Request!\n"); + if (len > 0) + fprintf(stderr,"type=%u instance=%u property=%u index=%d\n", + wp_data.object_type, + wp_data.object_instance, + wp_data.object_property, + wp_data.array_index); + else + fprintf(stderr,"Unable to decode Write-Property Request!\n"); + // prepare a reply + datalink_get_my_address(&my_address); + // encode the NPDU portion of the packet + pdu_len = npdu_encode_apdu( + &Handler_Transmit_Buffer[0], + src, + &my_address, + false, // true for confirmed messages + MESSAGE_PRIORITY_NORMAL); + // bad decoding or something we didn't understand - send an abort + if (len == -1) + { + pdu_len += abort_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + ABORT_REASON_OTHER); + fprintf(stderr,"Sending Abort!\n"); + } + else if (service_data->segmented_message) + { + pdu_len += abort_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + ABORT_REASON_SEGMENTATION_NOT_SUPPORTED); + fprintf(stderr,"Sending Abort!\n"); + } + else + { + switch (wp_data.object_type) + { + case OBJECT_DEVICE: + if (Device_Write_Property(&wp_data,&error_class,&error_code)) + { + pdu_len += encode_simple_ack( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY); + fprintf(stderr,"Sending Write Property Simple Ack!\n"); + } + else + { + pdu_len += bacerror_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY, + error_class, + error_code); + fprintf(stderr,"Sending Write Property Error!\n"); + } + break; + case OBJECT_ANALOG_INPUT: + error_class = ERROR_CLASS_PROPERTY; + error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + pdu_len += bacerror_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY, + error_class, + error_code); + fprintf(stderr,"Sending Write Access Error!\n"); + break; + case OBJECT_ANALOG_OUTPUT: + if (Analog_Output_Write_Property(&wp_data,&error_class,&error_code)) + { + pdu_len += encode_simple_ack( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY); + fprintf(stderr,"Sending Write Property Simple Ack!\n"); + } + else + { + pdu_len += bacerror_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY, + error_class, + error_code); + fprintf(stderr,"Sending Write Access Error!\n"); + } + break; + default: + pdu_len += bacerror_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY, + error_class, + error_code); + fprintf(stderr,"Sending Unknown Object Error!\n"); + break; + } + } + bytes_sent = datalink_send_pdu( + src, // destination address + &Handler_Transmit_Buffer[0], + pdu_len); // number of bytes of data + if (bytes_sent <= 0) + fprintf(stderr,"Failed to send PDU (%s)!\n", strerror(errno)); + + return; +} diff --git a/bacnet-stack/demo/handler/handlers.h b/bacnet-stack/demo/handler/handlers.h index 3f60e9a6..c10080b7 100644 --- a/bacnet-stack/demo/handler/handlers.h +++ b/bacnet-stack/demo/handler/handlers.h @@ -56,6 +56,31 @@ void handler_read_property( BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA *service_data); +void handler_read_property_ack( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data); + +void handler_write_property( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_DATA *service_data); + +void handler_atomic_read_file( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_DATA *service_data); + +void handler_atomic_read_file_ack( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/demo/handler/s_rp.c b/bacnet-stack/demo/handler/s_rp.c new file mode 100644 index 00000000..d15224ef --- /dev/null +++ b/bacnet-stack/demo/handler/s_rp.c @@ -0,0 +1,113 @@ +/************************************************************************** +* +* Copyright (C) 2005 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 "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 "rp.h" +/* some demo stuff needed */ +#include "handlers.h" +#include "txbuf.h" + +/* returns false if device is not bound or no tsm available */ +bool Send_Read_Property_Request( + uint32_t device_id, /* destination device */ + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property, + int32_t array_index) +{ + BACNET_ADDRESS dest; + BACNET_ADDRESS my_address; + unsigned max_apdu = 0; + uint8_t invoke_id = 0; + bool status = false; + int pdu_len = 0; + int bytes_sent = 0; + BACNET_READ_PROPERTY_DATA data; + + /* is the device bound? */ + status = address_get_by_device(device_id, &max_apdu, &dest); + /* is there a tsm available? */ + if (status) + status = tsm_transaction_available(); + if (status) + { + datalink_get_my_address(&my_address); + pdu_len = npdu_encode_apdu( + &Handler_Transmit_Buffer[0], + &dest, + &my_address, + true, // true for confirmed messages + MESSAGE_PRIORITY_NORMAL); + + invoke_id = tsm_next_free_invokeID(); + // load the data for the encoding + data.object_type = object_type; + data.object_instance = object_instance; + data.object_property = object_property; + data.array_index = array_index; + pdu_len += rp_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + invoke_id, + &data); + /* will it fit in the sender? + note: if there is a bottleneck router in between + us and the destination, we won't know unless + we have a way to check for that and update the + max_apdu in the address binding table. */ + if ((unsigned)pdu_len < max_apdu) + { + tsm_set_confirmed_unsegmented_transaction( + invoke_id, + &dest, + &Handler_Transmit_Buffer[0], + pdu_len); + 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,"Sent ReadProperty Request!\n"); + else + fprintf(stderr,"Failed to Send ReadProperty Request (%s)!\n", + strerror(errno)); + } + else + fprintf(stderr,"Failed to Send ReadProperty Request " + "(exceeds destination maximum APDU)!\n"); + } + + return status; +} diff --git a/bacnet-stack/demo/handler/s_whois.c b/bacnet-stack/demo/handler/s_whois.c new file mode 100644 index 00000000..00c7102a --- /dev/null +++ b/bacnet-stack/demo/handler/s_whois.c @@ -0,0 +1,77 @@ +/************************************************************************** +* +* Copyright (C) 2005 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 "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 "whois.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_WhoIs( + int32_t low_limit, + int32_t high_limit) +{ + int pdu_len = 0; + BACNET_ADDRESS dest; + int bytes_sent = 0; + + // Who-Is 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 + pdu_len += whois_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + low_limit, + high_limit); + + 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,"Sent Who-Is Request!\n"); + else + 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 new file mode 100644 index 00000000..7316b161 --- /dev/null +++ b/bacnet-stack/demo/handler/s_wp.c @@ -0,0 +1,118 @@ +/************************************************************************** +* +* Copyright (C) 2005 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 "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 "whois.h" +/* some demo stuff needed */ +#include "handlers.h" +#include "txbuf.h" + +/* FIXME: probably should return the invoke ID for confirmed request */ +bool 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) +{ + BACNET_ADDRESS dest; + BACNET_ADDRESS my_address; + unsigned max_apdu = 0; + uint8_t invoke_id = 0; + bool status = false; + int pdu_len = 0; + int bytes_sent = 0; + BACNET_WRITE_PROPERTY_DATA data; + + /* is the device bound? */ + status = address_get_by_device(device_id, &max_apdu, &dest); + /* is there a tsm available? */ + if (status) + status = tsm_transaction_available(); + if (status) + { + datalink_get_my_address(&my_address); + pdu_len = npdu_encode_apdu( + &Handler_Transmit_Buffer[0], + &dest, + &my_address, + true, // true for confirmed messages + MESSAGE_PRIORITY_NORMAL); + + invoke_id = tsm_next_free_invokeID(); + // load the data for the encoding + data.object_type = object_type; + data.object_instance = object_instance; + data.object_property = object_property; + data.array_index = array_index; + data.value = object_value; + data.priority = priority; + pdu_len += wp_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + invoke_id, + &data); + /* will it fit in the sender? + note: if there is a bottleneck router in between + us and the destination, we won't know unless + we have a way to check for that and update the + max_apdu in the address binding table. */ + if ((unsigned)pdu_len < max_apdu) + { + tsm_set_confirmed_unsegmented_transaction( + invoke_id, + &dest, + &Handler_Transmit_Buffer[0], + pdu_len); + 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,"Sent ReadProperty Request!\n"); + else + fprintf(stderr,"Failed to Send WriteProperty Request (%s)!\n", + strerror(errno)); + } + else + fprintf(stderr,"Failed to Send WriteProperty Request " + "(exceeds destination maximum APDU)!\n"); + } + + return status; +} + diff --git a/bacnet-stack/demo/handler/txbuf.h b/bacnet-stack/demo/handler/txbuf.h index cdfe942a..4b12ea63 100644 --- a/bacnet-stack/demo/handler/txbuf.h +++ b/bacnet-stack/demo/handler/txbuf.h @@ -32,4 +32,4 @@ extern uint8_t Handler_Transmit_Buffer[MAX_MPDU]; -#endif \ No newline at end of file +#endif diff --git a/bacnet-stack/demo/readfile/readfile.c b/bacnet-stack/demo/readfile/readfile.c index 52991f10..3ef48e98 100644 --- a/bacnet-stack/demo/readfile/readfile.c +++ b/bacnet-stack/demo/readfile/readfile.c @@ -24,11 +24,9 @@ *********************************************************************/ /* READFILE: command line tool that reads a file from a BACnet device. */ -#include #include #include #include -#include /* for kbhit and getch */ #include /* for time */ #include "bactext.h" #include "iam.h" @@ -58,6 +56,8 @@ static bool End_Of_File_Detected = false; static bool Error_Detected = false; static uint8_t Current_Invoke_ID = 0; +#define MIN(X,Y) ((X) < (Y) ? : (X) : (Y)) + static void Atomic_Read_File_Error_Handler( BACNET_ADDRESS *src, uint8_t invoke_id, @@ -325,7 +325,6 @@ int main(int argc, char *argv[]) uint16_t pdu_len = 0; unsigned timeout = 100; // milliseconds unsigned max_apdu = 0; - bool status = false; time_t elapsed_seconds = 0; time_t last_seconds = 0; time_t current_seconds = 0; @@ -334,6 +333,7 @@ int main(int argc, char *argv[]) unsigned requestedOctetCount = 0; uint8_t invoke_id = 0; bool found = false; + uint16_t my_max_apdu = 0; if (argc < 4) { @@ -415,7 +415,11 @@ int main(int argc, char *argv[]) and remove the overhead of the APDU (about 14 octets max). note: we could fail if there is a bottle neck (router) and smaller MPDU in betweeen. */ - requestedOctetCount = min(max_apdu,MAX_APDU) - 14; + if (max_apdu < MAX_APDU) + my_max_apdu = max_apdu; + else + my_max_apdu = MAX_APDU; + requestedOctetCount = my_max_apdu - 14; /* has the previous invoke id expired or returned? note: invoke ID = 0 is invalid, so it will be idle */ if ((invoke_id == 0) || tsm_invoke_id_free(invoke_id)) @@ -440,9 +444,6 @@ int main(int argc, char *argv[]) break; } } - /* wait for ESC from keyboard before quitting */ - if (kbhit() && (getch() == 0x1B)) - break; /* keep track of time for next check */ last_seconds = current_seconds; } diff --git a/bacnet-stack/ports/linux/main.c b/bacnet-stack/ports/linux/main.c index 0d77b688..dfb206f7 100644 --- a/bacnet-stack/ports/linux/main.c +++ b/bacnet-stack/ports/linux/main.c @@ -32,6 +32,7 @@ #include "address.h" #include "bacdef.h" #include "handlers.h" +#include "client.h" #include "bacdcode.h" #include "npdu.h" #include "apdu.h" @@ -41,8 +42,10 @@ #include "bacfile.h" #include "datalink.h" #include "net.h" +#include "txbuf.h" // This is an example application using the BACnet Stack on Linux +bool Who_Is_Request = true; // buffers used for receiving static uint8_t Rx_Buf[MAX_MPDU] = {0}; @@ -175,7 +178,7 @@ 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, - WhoIsHandler); + handler_who_is); apdu_set_unconfirmed_handler( SERVICE_UNCONFIRMED_I_AM, LocalIAmHandler); @@ -183,25 +186,25 @@ static void Init_Service_Handlers(void) // 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( - UnrecognizedServiceHandler); + 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, - ReadPropertyHandler); + handler_read_property); apdu_set_confirmed_handler( SERVICE_CONFIRMED_WRITE_PROPERTY, - WritePropertyHandler); + handler_write_property); apdu_set_confirmed_handler( SERVICE_CONFIRMED_ATOMIC_READ_FILE, - AtomicReadFileHandler); + handler_atomic_read_file); // handle the data coming back from confirmed requests apdu_set_confirmed_ack_handler( SERVICE_CONFIRMED_READ_PROPERTY, - ReadPropertyAckHandler); + handler_read_property_ack); apdu_set_confirmed_ack_handler( SERVICE_CONFIRMED_ATOMIC_READ_FILE, - AtomicReadFileAckHandler); + handler_atomic_read_file_ack); } static void print_address_cache(void) @@ -308,11 +311,11 @@ int main(int argc, char *argv[]) if (I_Am_Request) { I_Am_Request = false; - Send_IAm(); + iam_send(&Handler_Transmit_Buffer[0]); } else if (Who_Is_Request) { Who_Is_Request = false; - Send_WhoIs(); + Send_WhoIs(-1,-1); } // output // some round robin task switching diff --git a/bacnet-stack/readfile.mak b/bacnet-stack/readfile.mak new file mode 100644 index 00000000..5f280618 --- /dev/null +++ b/bacnet-stack/readfile.mak @@ -0,0 +1,71 @@ +#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 -DBACDL_BIP=1 +INCLUDES = -I. -Iports/linux -Idemo/object -Idemo/handler + +CFLAGS = -Wall -g $(INCLUDES) $(DEFINES) + +TARGET = readfile + +SRCS = demo/readfile/readfile.c \ + ports/linux/ethernet.c \ + ports/linux/arcnet.c \ + ports/linux/bip-init.c \ + bip.c \ + dlmstp.c \ + demo/handler/txbuf.c \ + demo/handler/noserv.c \ + demo/handler/h_whois.c \ + demo/handler/h_rp.c \ + rp.c \ + bacdcode.c \ + bacapp.c \ + bacprop.c \ + bacstr.c \ + bactext.c \ + indtext.c \ + bigend.c \ + whois.c \ + iam.c \ + tsm.c \ + datalink.c \ + address.c \ + demo/object/device.c \ + demo/object/ai.c \ + demo/object/ao.c \ + demo/object/bacfile.c \ + arf.c \ + abort.c \ + reject.c \ + bacerror.c \ + apdu.c \ + 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 +