From 7361bb4650eaaff1103cb5d2595bb8ebacadc137 Mon Sep 17 00:00:00 2001 From: skarg Date: Wed, 9 Oct 2013 21:49:15 +0000 Subject: [PATCH] 1. Added new file s_wpm.c (Send_Write_Property_Multiple_Request_Data) 2. Changed file wpm.h (new struct added BACNET_WRITE_ACCESS_DATA, declaration for wpm_encode_apdu added) 3. Changed file wpm.c (definition added for wpm_encode_apdu) 4. client.h file updated with declaration for Send_Write_Property_Multiple_Request_Data Thank you for the contribution, Daniel Blazevic! --- bacnet-stack/demo/handler/s_wpm.c | 119 ++++++++++++++++++++++++++++++ bacnet-stack/include/client.h | 4 + bacnet-stack/include/wpm.h | 13 ++++ bacnet-stack/lib/Makefile | 1 + bacnet-stack/lib/makefile.b32 | 1 + bacnet-stack/src/wpm.c | 54 ++++++++++++++ 6 files changed, 192 insertions(+) create mode 100644 bacnet-stack/demo/handler/s_wpm.c diff --git a/bacnet-stack/demo/handler/s_wpm.c b/bacnet-stack/demo/handler/s_wpm.c new file mode 100644 index 00000000..e08c650e --- /dev/null +++ b/bacnet-stack/demo/handler/s_wpm.c @@ -0,0 +1,119 @@ +/** +* @file +* @author Daniel Blazevic +* @date 2013 +* @brief Send Write Property Multiple request +* +* @section LICENSE +* +* Copyright (C) 2013 Daniel Blazevic +* +* 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 "txbuf.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "address.h" +#include "tsm.h" +#include "npdu.h" +#include "apdu.h" +#include "device.h" +#include "datalink.h" +#include "dcc.h" +#include "wpm.h" +/* some demo stuff needed */ +#include "handlers.h" +#include "sbuf.h" +#include "client.h" + +/** @file s_wpm.c Send Write Property Multiple request. */ + +/** Sends a Write Property Multiple request. + * @param device_id [in] ID of the destination device + * @param write_access_data [in] Ptr to structure with the linked list of + * objects and properties to be written. + * @return invoke id of outgoing message, or 0 if device is not bound or no tsm available + */ +uint8_t Send_Write_Property_Multiple_Request_Data( + uint32_t device_id, + BACNET_WRITE_ACCESS_DATA * write_access_data) +{ + BACNET_ADDRESS dest; + BACNET_ADDRESS my_address; + unsigned max_apdu = 0; + uint8_t invoke_id = 0; + bool status = false; + int len = 0; + int pdu_len = 0; + int bytes_sent = 0; + BACNET_NPDU_DATA npdu_data; + + /* is the device bound? */ + status = address_get_by_device(device_id, &max_apdu, &dest); + /* is there a tsm available? */ + if (status) + invoke_id = tsm_next_free_invokeID(); + if (invoke_id) { + /* encode the NPDU portion of the packet */ + datalink_get_my_address(&my_address); + npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL); + pdu_len = + npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest, &my_address, + &npdu_data); + + len = wpm_encode_apdu(&Handler_Transmit_Buffer[pdu_len], max_apdu, + invoke_id, write_access_data); + + pdu_len += len; + + /* 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, + &npdu_data, &Handler_Transmit_Buffer[0], (uint16_t) pdu_len); + bytes_sent = + datalink_send_pdu(&dest, &npdu_data, + &Handler_Transmit_Buffer[0], pdu_len); +#if PRINT_ENABLED + if (bytes_sent <= 0) + fprintf(stderr, "Failed to Send WriteProperty Request (%s)!\n", + strerror(errno)); +#endif + } else { + tsm_free_invoke_id(invoke_id); + invoke_id = 0; +#if PRINT_ENABLED + fprintf(stderr, + "Failed to Send WriteProperty Request " + "(exceeds destination maximum APDU)!\n"); +#endif + } + } + + return invoke_id; +} diff --git a/bacnet-stack/include/client.h b/bacnet-stack/include/client.h index 0a1a1cac..4eecb530 100644 --- a/bacnet-stack/include/client.h +++ b/bacnet-stack/include/client.h @@ -34,6 +34,7 @@ #include "bacapp.h" #include "bacenum.h" #include "rpm.h" +#include "wpm.h" #include "cov.h" #include "event.h" #include "lso.h" @@ -151,6 +152,9 @@ extern "C" { int application_data_len, uint8_t priority, uint32_t array_index); + uint8_t Send_Write_Property_Multiple_Request_Data( + uint32_t device_id, + BACNET_WRITE_ACCESS_DATA * write_access_data); /* returns the invoke ID for confirmed request, or 0 if failed */ uint8_t Send_Reinitialize_Device_Request( diff --git a/bacnet-stack/include/wpm.h b/bacnet-stack/include/wpm.h index 8a902163..575fe128 100644 --- a/bacnet-stack/include/wpm.h +++ b/bacnet-stack/include/wpm.h @@ -35,6 +35,14 @@ extern "C" { #endif /* __cplusplus */ + struct BACnet_Write_Access_Data; + typedef struct BACnet_Write_Access_Data { + BACNET_OBJECT_TYPE object_type; + uint32_t object_instance; + /* simple linked list of values */ + BACNET_PROPERTY_VALUE *listOfProperties; + struct BACnet_Write_Access_Data *next; + } BACNET_WRITE_ACCESS_DATA; /* decode the service request only */ int wpm_decode_object_id( @@ -61,6 +69,11 @@ extern "C" { int wpm_encode_apdu_object_property( uint8_t * apdu, BACNET_WRITE_PROPERTY_DATA * wpdata); + int wpm_encode_apdu( + uint8_t * apdu, + size_t max_apdu, + uint8_t invoke_id, + BACNET_WRITE_ACCESS_DATA * write_access_data); /* encode service */ int wpm_ack_encode_apdu_init( diff --git a/bacnet-stack/lib/Makefile b/bacnet-stack/lib/Makefile index ff0bffba..5e0ca7f7 100644 --- a/bacnet-stack/lib/Makefile +++ b/bacnet-stack/lib/Makefile @@ -122,6 +122,7 @@ HANDLER_SRC = \ $(BACNET_HANDLER)/s_uevent.c \ $(BACNET_HANDLER)/s_whohas.c \ $(BACNET_HANDLER)/s_whois.c \ + $(BACNET_HANDLER)/s_wpm.c \ $(BACNET_HANDLER)/s_upt.c \ $(BACNET_HANDLER)/s_wp.c diff --git a/bacnet-stack/lib/makefile.b32 b/bacnet-stack/lib/makefile.b32 index e4689db2..71c4d699 100644 --- a/bacnet-stack/lib/makefile.b32 +++ b/bacnet-stack/lib/makefile.b32 @@ -125,6 +125,7 @@ HANDLER_SRC = \ $(BACNET_HANDLER)\s_uevent.c \ $(BACNET_HANDLER)\s_whohas.c \ $(BACNET_HANDLER)\s_whois.c \ + $(BACNET_HANDLER)\s_wpm.c \ $(BACNET_HANDLER)\s_ptransfer.c \ $(BACNET_HANDLER)\h_upt.c \ $(BACNET_HANDLER)\h_pt.c \ diff --git a/bacnet-stack/src/wpm.c b/bacnet-stack/src/wpm.c index 7e3e302b..6713e50d 100644 --- a/bacnet-stack/src/wpm.c +++ b/bacnet-stack/src/wpm.c @@ -30,6 +30,7 @@ #include "bacdef.h" #include "wp.h" #include "wpm.h" +#include "string.h" /** @file wpm.c Encode/Decode BACnet Write Property Multiple APDUs */ @@ -254,6 +255,59 @@ int wpm_encode_apdu_object_property( return apdu_len; } +int wpm_encode_apdu( + uint8_t * apdu, + size_t max_apdu, + uint8_t invoke_id, + BACNET_WRITE_ACCESS_DATA * write_access_data) +{ + int apdu_len = 0; + int len = 0; + BACNET_WRITE_ACCESS_DATA *wpm_object; /* current object */ + uint8_t apdu_temp[MAX_APDU]; /* temp for data before copy */ + BACNET_PROPERTY_VALUE *wpm_property; /* current property */ + BACNET_WRITE_PROPERTY_DATA wpdata; /* for compatibility with wpm_encode_apdu_object_property function */ + + if (apdu) { + len = wpm_encode_apdu_init(&apdu[0], invoke_id); + apdu_len += len; + + wpm_object = write_access_data; + + while(wpm_object){ + + len = wpm_encode_apdu_object_begin(&apdu[apdu_len], + wpm_object->object_type, wpm_object->object_instance); + apdu_len += len; + + wpm_property = wpm_object->listOfProperties; + + while(wpm_property){ + wpdata.object_property = wpm_property->propertyIdentifier; + wpdata.array_index = wpm_property->propertyArrayIndex; + wpdata.priority = wpm_property->priority; + + wpdata.application_data_len = bacapp_encode_data(&apdu_temp[0], + &wpm_property->value); + memcpy(&wpdata.application_data[0], &apdu_temp[0], + wpdata.application_data_len); + + len = wpm_encode_apdu_object_property(&apdu[apdu_len], &wpdata); + apdu_len += len; + + wpm_property = wpm_property->next; + } + + len = wpm_encode_apdu_object_end(&apdu[apdu_len]); + apdu_len += len; + + wpm_object = wpm_object->next; + } + } + + return apdu_len; +} + int wpm_ack_encode_apdu_init( uint8_t * apdu, uint8_t invoke_id)