diff --git a/bacnet-stack/demo/handler/h_lso.c b/bacnet-stack/demo/handler/h_lso.c new file mode 100644 index 00000000..57c52454 --- /dev/null +++ b/bacnet-stack/demo/handler/h_lso.c @@ -0,0 +1,121 @@ +/************************************************************************** +* +* 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 "lso.h" +#include "handlers.h" + +bool handler_lso( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src, + BACNET_CONFIRMED_SERVICE_DATA * service_data) +{ + BACNET_LSO_DATA data; + int len = 0; + int pdu_len = 0; + BACNET_NPDU_DATA npdu_data; + int bytes_sent = 0; + BACNET_ADDRESS my_address; + + /* encode the NPDU portion of the packet */ + datalink_get_my_address(&my_address); + npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); + pdu_len = + npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, + &npdu_data); + if (service_data->segmented_message) { + /* we don't support segmentation - send an abort */ + len = + abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, + true); +#if PRINT_ENABLED + fprintf(stderr, "LSO: Segmented message. Sending Abort!\n"); +#endif + goto LSO_ABORT; + } + + len = lso_decode_service_request(service_request, service_len, &data); +#if PRINT_ENABLED + if (len <= 0) + fprintf(stderr, "LSO: Unable to decode Request!\n"); +#endif + if (len < 0) { + /* bad decoding - send an abort */ + len = + abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, ABORT_REASON_OTHER, true); +#if PRINT_ENABLED + fprintf(stderr, "LSO: Bad Encoding. Sending Abort!\n"); +#endif + goto LSO_ABORT; + } + + /* + ** Process Life Safety Operation Here + */ +#if PRINT_ENABLED + fprintf(stderr, + "Life Safety Operation: Received operation %d from process id %d for object %id\n", + data.operation, + data.processId, + data.targetObject.instance); +#endif + + len = + encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION); +#if PRINT_ENABLED + fprintf(stderr, + "Life Safety Operation: " "Sending Simple Ack!\n"); +#endif + + LSO_ABORT: + pdu_len += len; + bytes_sent = + datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], + pdu_len); +#if PRINT_ENABLED + if (bytes_sent <= 0) + fprintf(stderr, + "Life Safety Operation: " "Failed to send PDU (%s)!\n", + strerror(errno)); +#endif + + return; +} + diff --git a/bacnet-stack/include/bacnet.h b/bacnet-stack/include/bacnet.h index a773db0b..c2ec7f35 100644 --- a/bacnet-stack/include/bacnet.h +++ b/bacnet-stack/include/bacnet.h @@ -70,6 +70,8 @@ #include "whohas.h" #include "whois.h" #include "wp.h" +#include "event.h" +#include "lso.h" /* required object - note: developer must supply the device.c file since it is not included in the library. However, the library diff --git a/bacnet-stack/include/handlers.h b/bacnet-stack/include/handlers.h index 4bc6474a..3aad1f81 100644 --- a/bacnet-stack/include/handlers.h +++ b/bacnet-stack/include/handlers.h @@ -169,6 +169,13 @@ extern "C" { uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src); + + bool handler_lso( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src, + BACNET_CONFIRMED_SERVICE_DATA * service_data); + #ifdef __cplusplus } diff --git a/bacnet-stack/include/lso.h b/bacnet-stack/include/lso.h new file mode 100644 index 00000000..760f9024 --- /dev/null +++ b/bacnet-stack/include/lso.h @@ -0,0 +1,78 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2006 John Minack + + 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 LSO_H +#define LSO_H + +#include +#include +#include "bacenum.h" +#include "bacdef.h" +#include "bacstr.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Life Safety Operation Service */ + +typedef struct +{ + uint32_t processId; + BACNET_CHARACTER_STRING requestingSrc; + BACNET_LIFE_SAFETY_OPERATION operation; + BACNET_OBJECT_ID targetObject; +} BACNET_LSO_DATA; + + +int lso_encode_adpu( + uint8_t *apdu, + uint8_t invoke_id, + BACNET_LSO_DATA *data); +/* decode the service request only */ +int lso_decode_service_request( + uint8_t *apdu, + unsigned apdu_len, + BACNET_LSO_DATA *data); + + +#ifdef TEST +#include "ctest.h" + void testLSO( + Test * pTest); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/src/event.c b/bacnet-stack/src/event.c index 60be9b4a..c90f9500 100644 --- a/bacnet-stack/src/event.c +++ b/bacnet-stack/src/event.c @@ -505,7 +505,7 @@ int event_notify_decode_service_request( /* tag 6 - eventType */ if ((section_length = decode_context_enumerated(&apdu[len], 6, - &data->eventType)) == -1) { + (int*)&data->eventType)) == -1) { return -1; } else { len += section_length; @@ -534,7 +534,7 @@ int event_notify_decode_service_request( /* tag 8 - notifyType */ if ((section_length = decode_context_enumerated(&apdu[len], 8, - &data->notifyType)) == -1) { + (int*)&data->notifyType)) == -1) { return -1; } else { len += section_length; @@ -553,7 +553,7 @@ int event_notify_decode_service_request( /* tag 10 - fromState */ if ((section_length = decode_context_enumerated(&apdu[len], 10, - &data->fromState)) == -1) { + (int*)&data->fromState)) == -1) { return -1; } else { len += section_length; @@ -564,7 +564,7 @@ int event_notify_decode_service_request( /* tag 11 - toState */ if ((section_length = decode_context_enumerated(&apdu[len], 11, - &data->toState)) == -1) { + (int*)&data->toState)) == -1) { return -1; } else { len += section_length; @@ -744,7 +744,7 @@ int event_notify_decode_service_request( case EVENT_CHANGE_OF_LIFE_SAFETY: if (-1 == (section_length = decode_context_enumerated(&apdu[len], 0, - &data->notificationParams. + (int*)&data->notificationParams. changeOfLifeSafety.newState))) { return -1; } @@ -752,7 +752,7 @@ int event_notify_decode_service_request( if (-1 == (section_length = decode_context_enumerated(&apdu[len], 1, - &data->notificationParams. + (int*)&data->notificationParams. changeOfLifeSafety.newMode))) { return -1; } @@ -768,7 +768,7 @@ int event_notify_decode_service_request( if (-1 == (section_length = decode_context_enumerated(&apdu[len], 3, - &data->notificationParams. + (int*)&data->notificationParams. changeOfLifeSafety.operationExpected))) { return -1; } diff --git a/bacnet-stack/src/lso.c b/bacnet-stack/src/lso.c new file mode 100644 index 00000000..2d24ed62 --- /dev/null +++ b/bacnet-stack/src/lso.c @@ -0,0 +1,165 @@ +#include "lso.h" +#include "bacdcode.h" +#include "apdu.h" + +int lso_encode_adpu( + uint8_t * apdu, + uint8_t invoke_id, + BACNET_LSO_DATA * data) +{ + int len = 0; /* length of each encoding */ + int apdu_len = 0; /* total length of the apdu, return value */ + uint16_t max_apdu = Device_Max_APDU_Length_Accepted(); + + + if (apdu && data) { + 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_LIFE_SAFETY_OPERATION; + apdu_len = 4; + /* tag 0 - requestingProcessId */ + len = + encode_context_unsigned(&apdu[apdu_len], 0, + data->processId); + apdu_len += len; + /* tag 1 - requestingSource */ + len = + encode_context_character_string(&apdu[apdu_len], 1, + &data->requestingSrc); + apdu_len += len; + /* + Operation + */ + len = encode_context_enumerated(&apdu[apdu_len], 2, data->operation); + apdu_len += len; + /* + Object ID + */ + + len = encode_context_object_id(&apdu[apdu_len], 3, + data->targetObject.type, + data->targetObject.instance); + + apdu_len += len; + } + + return apdu_len; +} + +int lso_decode_service_request( + uint8_t *apdu, + unsigned apdu_len, + BACNET_LSO_DATA *data) +{ + int len = 0; /* return value */ + int section_length; + uint8_t tag_number = 0; + uint32_t len_value_type = 0; + int type = 0; /* for decoding */ + int property = 0; /* for decoding */ + + /* check for value pointers */ + if (apdu_len && data) { + /* Tag 0: Object ID */ + + if ( (section_length = decode_context_unsigned(&apdu[len], 0, &data->processId)) == -1) + { + return -1; + } + len += section_length; + + if ( (section_length = decode_context_character_string(&apdu[len], 1, &data->requestingSrc)) == -1) + { + return -1; + } + len += section_length; + + if ( (section_length = decode_context_enumerated(&apdu[len], 2, (int*)&data->operation)) == -1) + { + return -1; + } + len += section_length; + + /* + ** This is an optional parameter, so dont fail if it doesnt exist + */ + if ( decode_is_context_tag(&apdu[len], 3) ) + { + if ( (section_length = decode_context_object_id(&apdu[len], 3, + &data->targetObject.type, + &data->targetObject.instance)) == -1 ) + { + return -1; + } + len += section_length; + } + else + { + data->targetObject.type = 0; + data->targetObject.instance = 0; + } + return len; + + } + + return 0; +} + +#ifdef TEST +#include +#include +#include "ctest.h" +#include "bacapp.h" + +void testLSO( + Test * pTest) +{ + uint8_t apdu[1000]; + int len; + + BACNET_LSO_DATA data; + BACNET_LSO_DATA rxdata; + + memset(&rxdata, 0, sizeof(rxdata)); + + + characterstring_init_ansi(&data.requestingSrc, "foobar"); + data.operation = LIFE_SAFETY_OP_RESET; + data.processId = 0x1234; + data.targetObject.instance = 0x1000; + data.targetObject.type = OBJECT_BINARY_INPUT; + + len = lso_encode_adpu(apdu, 100, &data); + + lso_decode_service_request(&apdu[4], len, &rxdata); + + ct_test(pTest, data.operation == rxdata.operation); + ct_test(pTest, data.processId == rxdata.processId); + ct_test(pTest, data.targetObject.instance == rxdata.targetObject.instance); + ct_test(pTest, data.targetObject.type == rxdata.targetObject.type); + ct_test(pTest, memcmp(data.requestingSrc.value, rxdata.requestingSrc.value, rxdata.requestingSrc.length) == 0); +} + +#ifdef TEST_LSO +int main( + int argc, + char *argv[]) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet Life Safety Operation", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testLSO); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_COV */ +#endif /* TEST */