diff --git a/bacnet-stack/demo/handler/h_upt.c b/bacnet-stack/demo/handler/h_upt.c new file mode 100644 index 00000000..d23fa34c --- /dev/null +++ b/bacnet-stack/demo/handler/h_upt.c @@ -0,0 +1,63 @@ +/************************************************************************** +* +* Copyright (C) 2009 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 "ptransfer.h" + +void handler_unconfirmed_private_transfer( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src) +{ + BACNET_PRIVATE_TRANSFER_DATA data; + int len = 0; + int pdu_len = 0; + +#if PRINT_ENABLED + fprintf(stderr,"Received Unconfirmed Private Transfer Request!\n"); +#endif + (void) src; + len = ptransfer_decode_service_request( + service_request, service_len, &data); + if (len >= 0) { + #if PRINT_ENABLED + fprintf(stderr, + "UnconfirmedPrivateTransfer: " + "vendorID=%u serviceNumber=%u\n", + data.vendorID, data.serviceNumber); + #endif + } +} + diff --git a/bacnet-stack/include/handlers.h b/bacnet-stack/include/handlers.h index 0b15faa5..2cf96d68 100644 --- a/bacnet-stack/include/handlers.h +++ b/bacnet-stack/include/handlers.h @@ -214,6 +214,11 @@ extern "C" { BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data); + void handler_unconfirmed_private_transfer( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src); + void handler_read_range( uint8_t * service_request, uint16_t service_len, diff --git a/bacnet-stack/lib/Makefile b/bacnet-stack/lib/Makefile index 0f678d17..2be18f5a 100644 --- a/bacnet-stack/lib/Makefile +++ b/bacnet-stack/lib/Makefile @@ -95,6 +95,9 @@ HANDLER_SRC = \ $(BACNET_HANDLER)/h_ihave.c \ $(BACNET_HANDLER)/h_cov.c \ $(BACNET_HANDLER)/h_ucov.c \ + $(BACNET_HANDLER)/h_pt.c \ + $(BACNET_HANDLER)/h_pt_a.c \ + $(BACNET_HANDLER)/h_upt.c \ $(BACNET_HANDLER)/s_arfs.c \ $(BACNET_HANDLER)/s_awfs.c \ $(BACNET_HANDLER)/s_dcc.c \ diff --git a/bacnet-stack/lib/makefile.b32 b/bacnet-stack/lib/makefile.b32 index 312af992..19254bc0 100644 --- a/bacnet-stack/lib/makefile.b32 +++ b/bacnet-stack/lib/makefile.b32 @@ -112,6 +112,7 @@ HANDLER_SRC = \ $(BACNET_HANDLER)\s_whohas.c \ $(BACNET_HANDLER)\s_whois.c \ $(BACNET_HANDLER)\s_ptransfer.c \ + $(BACNET_HANDLER)\h_upt.c \ $(BACNET_HANDLER)\h_pt.c \ $(BACNET_HANDLER)\h_pt_a.c \ $(BACNET_HANDLER)\s_wp.c diff --git a/bacnet-stack/src/ptransfer.c b/bacnet-stack/src/ptransfer.c index 4db89f85..80978957 100644 --- a/bacnet-stack/src/ptransfer.c +++ b/bacnet-stack/src/ptransfer.c @@ -38,27 +38,21 @@ #include "ptransfer.h" /* encode service */ -int ptransfer_encode_apdu( +int pt_encode_apdu( uint8_t * apdu, - uint8_t invoke_id, + uint16_t max_apdu, BACNET_PRIVATE_TRANSFER_DATA * private_data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ - - if (apdu) { - apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; - apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); - apdu[2] = invoke_id; - apdu[3] = SERVICE_CONFIRMED_PRIVATE_TRANSFER; - apdu_len = 4; /* - ConfirmedPrivateTransfer-Request ::= SEQUENCE { + Unconfirmed/ConfirmedPrivateTransfer-Request ::= SEQUENCE { vendorID [0] Unsigned, serviceNumber [1] Unsigned, serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL } */ + if (apdu) { len = encode_context_unsigned(&apdu[apdu_len], 0, private_data->vendorID); @@ -80,6 +74,50 @@ int ptransfer_encode_apdu( return apdu_len; } +int ptransfer_encode_apdu( + uint8_t * apdu, + uint8_t invoke_id, + BACNET_PRIVATE_TRANSFER_DATA * private_data) +{ + int apdu_len = 0; /* total length of the apdu, return value */ + + if (apdu) { + apdu[0] = PDU_TYPE_CONFIRMED_SERVICE_REQUEST; + apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); + apdu[2] = invoke_id; + apdu[3] = SERVICE_CONFIRMED_PRIVATE_TRANSFER; + apdu_len = 4; + apdu_len = pt_encode_apdu( + &apdu[apdu_len], + MAX_APDU-apdu_len, + private_data); + } + + return apdu_len; +} + +int uptransfer_encode_apdu( + uint8_t * apdu, + uint8_t invoke_id, + BACNET_PRIVATE_TRANSFER_DATA * private_data) +{ + int apdu_len = 0; /* total length of the apdu, return value */ + + if (apdu) { + apdu[0] = PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST; + apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); + apdu[2] = invoke_id; + apdu[3] = SERVICE_UNCONFIRMED_PRIVATE_TRANSFER; + apdu_len = 4; + apdu_len = pt_encode_apdu( + &apdu[apdu_len], + MAX_APDU-apdu_len, + private_data); + } + + return apdu_len; +} + /* decode the service request only */ int ptransfer_decode_service_request( uint8_t * apdu, @@ -308,6 +346,7 @@ int ptransfer_ack_encode_apdu( /* ptransfer_ack_decode_service_request() is the same as ptransfer_decode_service_request */ + #ifdef TEST #include #include @@ -344,6 +383,36 @@ int ptransfer_decode_apdu( return len; } +int uptransfer_decode_apdu( + uint8_t * apdu, + unsigned apdu_len, + uint8_t * invoke_id, + BACNET_PRIVATE_TRANSFER_DATA * private_data) +{ + int len = 0; + unsigned offset = 0; + + if (!apdu) + return -1; + /* optional checking - most likely was already done prior to this call */ + if (apdu[0] != PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST) + return -1; + /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ + /* invoke id - filled in by net layer */ + *invoke_id = apdu[2]; + if (apdu[3] != SERVICE_UNCONFIRMED_PRIVATE_TRANSFER) + return -1; + offset = 4; + + if (apdu_len > offset) { + len = + ptransfer_decode_service_request(&apdu[offset], apdu_len - offset, + private_data); + } + + return len; +} + int ptransfer_ack_decode_apdu( uint8_t * apdu, int apdu_len, /* total length of the apdu */ @@ -544,6 +613,50 @@ void test_Private_Transfer_Request( return; } +void test_Unconfirmed_Private_Transfer_Request( + Test * pTest) +{ + uint8_t apdu[480] = { 0 }; + uint8_t test_value[480] = { 0 }; + int len = 0; + int apdu_len = 0; + uint8_t invoke_id = 128; + uint8_t test_invoke_id = 0; + int private_data_len = 0; + uint8_t private_data_chunk[32] = { "I Love You, Patricia!" }; + BACNET_APPLICATION_DATA_VALUE data_value; + BACNET_APPLICATION_DATA_VALUE test_data_value; + BACNET_PRIVATE_TRANSFER_DATA private_data; + BACNET_PRIVATE_TRANSFER_DATA test_data; + + private_data.vendorID = BACNET_VENDOR_ID; + private_data.serviceNumber = 1; + + bacapp_parse_application_data(BACNET_APPLICATION_TAG_OCTET_STRING, + &private_data_chunk[0], &data_value); + private_data_len = + bacapp_encode_application_data(&test_value[0], &data_value); + private_data.serviceParameters = &test_value[0]; + private_data.serviceParametersLen = private_data_len; + + len = uptransfer_encode_apdu(&apdu[0], invoke_id, &private_data); + ct_test(pTest, len != 0); + apdu_len = len; + len = + ptransfer_decode_apdu(&apdu[0], apdu_len, &test_invoke_id, &test_data); + ct_test(pTest, len != -1); + ct_test(pTest, test_data.vendorID == private_data.vendorID); + ct_test(pTest, test_data.serviceNumber == private_data.serviceNumber); + ct_test(pTest, + test_data.serviceParametersLen == private_data.serviceParametersLen); + len = + bacapp_decode_application_data(test_data.serviceParameters, + test_data.serviceParametersLen, &test_data_value); + ct_test(pTest, bacapp_same_value(&data_value, &test_data_value) == true); + + return; +} + #ifdef TEST_PRIVATE_TRANSFER int main( void) @@ -559,6 +672,8 @@ int main( assert(rc); rc = ct_addTestFunction(pTest, test_Private_Transfer_Error); assert(rc); + rc = ct_addTestFunction(pTest, test_Unconfirmed_Private_Transfer_Request); + assert(rc); ct_setStream(pTest, stdout); ct_run(pTest);