Issue 2 move folders and use deep path include file names to prevent collisions (#4)
* moving folders and files and adjust server demo build * Fix Makefile for apps/server on Linux * fix unit test source file folders * fix datetime convert UTC functions. Add Code::Blocks project for datetime testing * added some ignore extensions * disable parallel make option * fix build for abort, dcc, and epics apps * fix build for dcc, epics, error, and getevent apps. * Fixed building of all apps * fix the ipv4 to ipv6 router app build * Change indent style from Google to Webkit * make pretty to re-format style * removed common Makefile since we already had one and two was too many * remove scripts from root folder that are no longer maintained or used * remove mercurial EOL and ignore files for git repo * remove .vscodeconfig files from repo * tweak clang-format style * clang-format src and apps with tweaked style * added clang-tidy to fix readability if braces in src * result of make tidy for src and apps * fix clang-tidy mangling * Added code::blocks project for BACnet server simulation * added code::blocks linux project for WhoIs app * update text files for EOL * fix EOL in some files * fixed make win32 apps for older gcc * Removed Borland C++ Makefile in apps. Unable to maintain support for Borland C++ compiler. * created codeblocks project for apps/epics for Windows * fixing ports/xplained to work with new data structure. * fix ports/xplained example for Atmel Studio compile * fix ports/stm32f10x example for gcc Makefile compile * fix ports/stm32f10x example for IAR EWARM compile * fix ports/xplained timer callback * fix ports/bdk_atxx_mspt build with subdirs * fix ports/bdk_atxx_mspt build with subdirs * updated git ignore for IAR build artifacts * updated gitignore for non-tracked files and folders * fixed bdk-atxx4-mstp port for Rowley Crossworks project file * fixed bdk-atxx4-mstp port for GCC AVR Makefile * fixed atmega168 port for IAR AVR and GCC AVR Makefile * fixed at91sam7s port for IAR ARM and GCC ARM Makefile * removed unmaintainable DOS, RTOS32, and atmega8 ports. Updated rx62n (untested). * changed arm7 to uip port
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
#Makefile to build BACnet Application using GCC compiler
|
||||
|
||||
# tools - only if you need them.
|
||||
# Most platforms have this already defined
|
||||
# CC = gcc
|
||||
# AR = ar
|
||||
# MAKE = make
|
||||
# SIZE = size
|
||||
#
|
||||
# Assumes rm and cp are available
|
||||
|
||||
# Executable file name
|
||||
TARGET = ptransfer
|
||||
|
||||
TARGET_BIN = ${TARGET}$(TARGET_EXT)
|
||||
|
||||
SRCS = main.c \
|
||||
../object/netport.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 -rf core ${TARGET_BIN} ${OBJS} ${BACNET_LIB_TARGET}
|
||||
|
||||
include: .depend
|
||||
@@ -0,0 +1,283 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "bacnet/config.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/apdu.h"
|
||||
#include "bacnet/npdu.h"
|
||||
#include "bacnet/abort.h"
|
||||
#include "bacnet/ptransfer.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
|
||||
/** @file h_pt.c Handles Confirmed Private Transfer requests. */
|
||||
|
||||
#define MYMAXSTR 32
|
||||
#define MYMAXBLOCK 8
|
||||
|
||||
DATABLOCK MyData[MYMAXBLOCK];
|
||||
|
||||
uint8_t IOBufferPT[MAX_APDU]; /* Buffer for building response in */
|
||||
|
||||
static void ProcessPT(BACNET_PRIVATE_TRANSFER_DATA *data)
|
||||
{
|
||||
int iLen; /* Index to current location in data */
|
||||
char cBlockNumber;
|
||||
uint32_t ulTemp;
|
||||
int tag_len;
|
||||
uint8_t tag_number;
|
||||
uint32_t len_value_type;
|
||||
BACNET_CHARACTER_STRING bsTemp;
|
||||
|
||||
iLen = 0;
|
||||
|
||||
/* Decode the block number */
|
||||
tag_len = decode_tag_number_and_value(
|
||||
&data->serviceParameters[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
/* Bail out early if wrong type */
|
||||
/* and signal unexpected error */
|
||||
data->serviceParametersLen = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
iLen += decode_unsigned(
|
||||
&data->serviceParameters[iLen], len_value_type, &ulTemp);
|
||||
cBlockNumber = (char)ulTemp;
|
||||
if (cBlockNumber < MY_MAX_BLOCK) {
|
||||
if (data->serviceNumber == MY_SVC_READ) {
|
||||
/* Read Response is an unsigned int with
|
||||
0 for success or a non 0 error code
|
||||
For a successful read the 0 success
|
||||
code is followed by the block number
|
||||
and then the block contents which
|
||||
consist of 2 unsigned ints (in 0 to 255
|
||||
range as they are really chars) a single
|
||||
precision real and a string which
|
||||
will be up to 32 chars + a nul */
|
||||
|
||||
iLen = 0;
|
||||
|
||||
/* Signal success */
|
||||
iLen += encode_application_unsigned(&IOBufferPT[iLen], MY_ERR_OK);
|
||||
/* Followed by the block number */
|
||||
iLen +=
|
||||
encode_application_unsigned(&IOBufferPT[iLen], cBlockNumber);
|
||||
/* And Then the block contents */
|
||||
iLen += encode_application_unsigned(
|
||||
&IOBufferPT[iLen], MyData[(int8_t)cBlockNumber].cMyByte1);
|
||||
iLen += encode_application_unsigned(
|
||||
&IOBufferPT[iLen], MyData[(int8_t)cBlockNumber].cMyByte2);
|
||||
iLen += encode_application_real(
|
||||
&IOBufferPT[iLen], MyData[(int8_t)cBlockNumber].fMyReal);
|
||||
characterstring_init_ansi(
|
||||
&bsTemp, (char *)MyData[(int8_t)cBlockNumber].sMyString);
|
||||
iLen +=
|
||||
encode_application_character_string(&IOBufferPT[iLen], &bsTemp);
|
||||
} else {
|
||||
/* Write operation */
|
||||
/* Write block consists of the block number
|
||||
followed by the block contents as
|
||||
described above for the read operation.
|
||||
The returned result is an unsigned
|
||||
response which is 0 for success and
|
||||
a non 0 error code otherwise. */
|
||||
|
||||
tag_len = decode_tag_number_and_value(
|
||||
&data->serviceParameters[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
data->serviceParametersLen = 0;
|
||||
return;
|
||||
}
|
||||
iLen += decode_unsigned(
|
||||
&data->serviceParameters[iLen], len_value_type, &ulTemp);
|
||||
MyData[(int8_t)cBlockNumber].cMyByte1 = (char)ulTemp;
|
||||
|
||||
tag_len = decode_tag_number_and_value(
|
||||
&data->serviceParameters[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
data->serviceParametersLen = 0;
|
||||
return;
|
||||
}
|
||||
iLen += decode_unsigned(
|
||||
&data->serviceParameters[iLen], len_value_type, &ulTemp);
|
||||
MyData[(int8_t)cBlockNumber].cMyByte2 = (char)ulTemp;
|
||||
|
||||
tag_len = decode_tag_number_and_value(
|
||||
&data->serviceParameters[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_REAL) {
|
||||
data->serviceParametersLen = 0;
|
||||
return;
|
||||
}
|
||||
iLen += decode_real(&data->serviceParameters[iLen],
|
||||
&MyData[(int8_t)cBlockNumber].fMyReal);
|
||||
|
||||
tag_len = decode_tag_number_and_value(
|
||||
&data->serviceParameters[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
data->serviceParametersLen = 0;
|
||||
return;
|
||||
}
|
||||
decode_character_string(
|
||||
&data->serviceParameters[iLen], len_value_type, &bsTemp);
|
||||
/* Only copy as much as we can accept */
|
||||
strncpy((char *)MyData[(int8_t)cBlockNumber].sMyString,
|
||||
characterstring_value(&bsTemp), MY_MAX_STR);
|
||||
/* Make sure it is nul terminated */
|
||||
MyData[(int8_t)cBlockNumber].sMyString[MY_MAX_STR] = '\0';
|
||||
/* Signal success */
|
||||
iLen = encode_application_unsigned(&IOBufferPT[0], MY_ERR_OK);
|
||||
}
|
||||
} else {
|
||||
/* Signal bad index */
|
||||
iLen = encode_application_unsigned(&IOBufferPT[0], MY_ERR_BAD_INDEX);
|
||||
}
|
||||
data->serviceParametersLen = iLen;
|
||||
data->serviceParameters = IOBufferPT;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called when we receive a private transfer packet.
|
||||
* We parse the data, send the private part for processing and then send the
|
||||
* response which the application generates.
|
||||
* If there are any BACnet level errors we send an error response from here.
|
||||
* If there are any application level errors they will be packeged up in the
|
||||
* response block which we send back to the originator of the request.
|
||||
*
|
||||
*/
|
||||
|
||||
void handler_conf_private_trans(uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA *service_data)
|
||||
{
|
||||
BACNET_PRIVATE_TRANSFER_DATA data;
|
||||
int len;
|
||||
int pdu_len;
|
||||
bool error;
|
||||
int bytes_sent;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ADDRESS my_address;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
len = 0;
|
||||
pdu_len = 0;
|
||||
error = false;
|
||||
bytes_sent = 0;
|
||||
error_class = ERROR_CLASS_OBJECT;
|
||||
error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "Received Confirmed Private Transfer Request!\n");
|
||||
#endif
|
||||
/* encode the NPDU portion of the response packet as it will be needed */
|
||||
/* no matter what the outcome. */
|
||||
|
||||
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) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "CPT: Segmented Message. Sending Abort!\n");
|
||||
#endif
|
||||
goto CPT_ABORT;
|
||||
}
|
||||
|
||||
len = ptransfer_decode_service_request(service_request, service_len, &data);
|
||||
/* bad decoding - send an abort */
|
||||
if (len < 0) {
|
||||
len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "CPT: Bad Encoding. Sending Abort!\n");
|
||||
#endif
|
||||
goto CPT_ABORT;
|
||||
}
|
||||
|
||||
/* Simple example with service number of 0 for
|
||||
read block and 1 for write block
|
||||
We also only support our own vendor ID.
|
||||
In theory we could support others
|
||||
for compatability purposes but these
|
||||
interfaces are rarely documented... */
|
||||
if ((data.vendorID == BACNET_VENDOR_ID) &&
|
||||
(data.serviceNumber <= MY_SVC_WRITE)) {
|
||||
/* We only try to understand our own IDs and service numbers */
|
||||
/* Will either return a result block or an app level status block */
|
||||
ProcessPT(&data);
|
||||
if (data.serviceParametersLen == 0) {
|
||||
/* No respopnse means fatal error */
|
||||
error = true;
|
||||
error_class = ERROR_CLASS_SERVICES;
|
||||
error_code = ERROR_CODE_OTHER;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "CPT: Error servicing request!\n");
|
||||
#endif
|
||||
}
|
||||
len = ptransfer_ack_encode_apdu(
|
||||
&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data);
|
||||
} else { /* Not our vendor ID or bad service parameter */
|
||||
|
||||
error = true;
|
||||
error_class = ERROR_CLASS_SERVICES;
|
||||
error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "CPT: Not our Vendor ID or invalid service code!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (error) {
|
||||
len = ptransfer_error_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, error_class, error_code, &data);
|
||||
}
|
||||
CPT_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, "Failed to send PDU (%s)!\n", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Steve Karg
|
||||
* @date October 2019
|
||||
* @brief Header file for a basic ConfirmedPrivateTransfer service handler
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
* 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 HANDLER_CONFIRMED_PRIVATE_TRANSFER_H
|
||||
#define HANDLER_CONFIRMED_PRIVATE_TRANSFER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/bacenum.h"
|
||||
#include "bacnet/apdu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void handler_conf_private_trans(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,221 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "bacnet/config.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/apdu.h"
|
||||
#include "bacnet/npdu.h"
|
||||
#include "bacnet/abort.h"
|
||||
#include "bacnet/ptransfer.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
|
||||
/** @file h_pt_a.c Handles Confirmed Private Transfer Acknowledgment. */
|
||||
|
||||
extern uint8_t IOBufferPT[300]; /* Somewhere to build the encoded result block
|
||||
for Private Transfers */
|
||||
|
||||
static void DecodeBlock(char cBlockNum, uint8_t *pData)
|
||||
{
|
||||
int iLen;
|
||||
uint32_t ulTemp;
|
||||
int tag_len;
|
||||
uint8_t tag_number;
|
||||
uint32_t len_value_type;
|
||||
BACNET_CHARACTER_STRING bsName;
|
||||
DATABLOCK Response;
|
||||
|
||||
iLen = 0;
|
||||
|
||||
if (cBlockNum >= MY_MAX_BLOCK)
|
||||
return;
|
||||
|
||||
tag_len =
|
||||
decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return;
|
||||
|
||||
iLen += decode_unsigned(&pData[iLen], len_value_type, &ulTemp);
|
||||
Response.cMyByte1 = (char)ulTemp;
|
||||
|
||||
tag_len =
|
||||
decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return;
|
||||
|
||||
iLen += decode_unsigned(&pData[iLen], len_value_type, &ulTemp);
|
||||
Response.cMyByte2 = (char)ulTemp;
|
||||
|
||||
tag_len =
|
||||
decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_REAL)
|
||||
return;
|
||||
|
||||
iLen += decode_real(&pData[iLen], &Response.fMyReal);
|
||||
|
||||
tag_len =
|
||||
decode_tag_number_and_value(&pData[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_CHARACTER_STRING)
|
||||
return;
|
||||
|
||||
iLen += decode_character_string(&pData[iLen], len_value_type, &bsName);
|
||||
strncpy(
|
||||
(char *)Response.sMyString, characterstring_value(&bsName), MY_MAX_STR);
|
||||
Response.sMyString[MY_MAX_STR] = '\0'; /* Make sure it is nul terminated */
|
||||
|
||||
printf("Private Transfer Read Block Response\n");
|
||||
printf("Data Block: %d\n", (int)cBlockNum);
|
||||
printf(" First Byte : %d\n", (int)Response.cMyByte1);
|
||||
printf(" Second Byte : %d\n", (int)Response.cMyByte2);
|
||||
printf(" Real : %f\n", Response.fMyReal);
|
||||
printf(" String : %s\n\n", Response.sMyString);
|
||||
}
|
||||
|
||||
static void ProcessPTA(BACNET_PRIVATE_TRANSFER_DATA *data)
|
||||
{
|
||||
int iLen; /* Index to current location in data */
|
||||
uint32_t uiErrorCode;
|
||||
char cBlockNumber;
|
||||
uint32_t ulTemp;
|
||||
int tag_len;
|
||||
uint8_t tag_number;
|
||||
uint32_t len_value_type;
|
||||
|
||||
iLen = 0;
|
||||
|
||||
/* Error code is returned for read and write operations */
|
||||
|
||||
tag_len = decode_tag_number_and_value(
|
||||
&data->serviceParameters[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
#if PRINT_ENABLED
|
||||
printf("CPTA: Bad Encoding!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
iLen += decode_unsigned(
|
||||
&data->serviceParameters[iLen], len_value_type, &uiErrorCode);
|
||||
|
||||
if (data->serviceNumber == MY_SVC_READ) { /* Read I/O block so should be
|
||||
full block of data or error */
|
||||
/* Decode the error type and if necessary block number and then fetch
|
||||
* the info */
|
||||
|
||||
if (uiErrorCode == MY_ERR_OK) {
|
||||
/* Block Number */
|
||||
tag_len = decode_tag_number_and_value(
|
||||
&data->serviceParameters[iLen], &tag_number, &len_value_type);
|
||||
iLen += tag_len;
|
||||
if (tag_number != BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
#if PRINT_ENABLED
|
||||
printf("CPTA: Bad Encoding!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
iLen += decode_unsigned(
|
||||
&data->serviceParameters[iLen], len_value_type, &ulTemp);
|
||||
cBlockNumber = (char)ulTemp;
|
||||
DecodeBlock(cBlockNumber, &data->serviceParameters[iLen]);
|
||||
} else { /* Read error */
|
||||
printf("Private Transfer read operation returned error code: %lu\n",
|
||||
(unsigned long)uiErrorCode);
|
||||
return;
|
||||
}
|
||||
} else { /* Write I/O block - should just be an OK type message */
|
||||
printf("Private Transfer write operation returned error code: %lu\n",
|
||||
(unsigned long)uiErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called when we receive a private transfer packet ack.
|
||||
* We parse the response which the remote application generated
|
||||
* and decide what to do next...
|
||||
*/
|
||||
|
||||
void handler_conf_private_trans_ack(uint8_t *service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS *src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data)
|
||||
{
|
||||
BACNET_PRIVATE_TRANSFER_DATA data;
|
||||
int len;
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* We currently don't look at the source address and service data
|
||||
* but we probably should to verify that the ack is oneit is what
|
||||
* we were expecting. But this is just to silence some compiler
|
||||
* warnings from Borland.
|
||||
*/
|
||||
src = src;
|
||||
service_data = service_data;
|
||||
|
||||
len = 0;
|
||||
|
||||
#if PRINT_ENABLED
|
||||
printf("Received Confirmed Private Transfer Ack!\n");
|
||||
#endif
|
||||
|
||||
len = ptransfer_decode_service_request(service_request, service_len,
|
||||
&data); /* Same decode for ack as for service request! */
|
||||
if (len < 0) {
|
||||
#if PRINT_ENABLED
|
||||
printf("cpta: Bad Encoding!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
ProcessPTA(&data); /* See what to do with the response */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void PTErrorHandler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void) src;
|
||||
(void) invoke_id;
|
||||
printf("BACnet Error: %s: %s\r\n",
|
||||
bactext_error_class_name((int) error_class),
|
||||
bactext_error_code_name((int) error_code));
|
||||
Error_Detected = true;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Steve Karg
|
||||
* @date October 2019
|
||||
* @brief Header file for a basic ConfirmedPrivateTransfer-Ack service handler
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
* 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 HANDLER_CONFIRMED_PRIVATE_TRANSFER_ACK_H
|
||||
#define HANDLER_CONFIRMED_PRIVATE_TRANSFER_ACK_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/bacenum.h"
|
||||
#include "bacnet/apdu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void handler_conf_private_trans_ack(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,401 @@
|
||||
/*************************************************************************
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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, and displays the reply */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <time.h> /* for time */
|
||||
#include <ctype.h> /* for tupper */
|
||||
#if defined(WIN32) || defined(__BORLANDC__)
|
||||
#include <conio.h>
|
||||
#endif
|
||||
#define PRINT_ENABLED 1
|
||||
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/config.h"
|
||||
#include "bacnet/bactext.h"
|
||||
#include "bacnet/bacerror.h"
|
||||
#include "bacnet/iam.h"
|
||||
#include "bacnet/arf.h"
|
||||
#include "bacnet/npdu.h"
|
||||
#include "bacnet/apdu.h"
|
||||
#include "bacnet/whois.h"
|
||||
/* some demo stuff needed */
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
#include "bacnet/basic/binding/address.h"
|
||||
#include "bacnet/basic/object/device.h"
|
||||
#include "bacnet/basic/sys/filename.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
#include "bacnet/datalink/dlenv.h"
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
#define _kbhit kbhit
|
||||
#define _stricmp stricmp
|
||||
#endif
|
||||
|
||||
#define MY_MAX_STR 32
|
||||
#define MY_MAX_BLOCK 8
|
||||
|
||||
#define MY_SVC_READ 0
|
||||
#define MY_SVC_WRITE 1
|
||||
|
||||
#define MY_ERR_OK 0
|
||||
#define MY_ERR_BAD_INDEX 1
|
||||
|
||||
typedef struct MyData {
|
||||
uint8_t cMyByte1;
|
||||
uint8_t cMyByte2;
|
||||
float fMyReal;
|
||||
int8_t sMyString[MY_MAX_STR + 1]; /* A little extra for the nul */
|
||||
} DATABLOCK;
|
||||
|
||||
/* buffer used for receive */
|
||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
|
||||
/* global variables used in this file */
|
||||
static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE;
|
||||
|
||||
static int Target_Mode = 0;
|
||||
|
||||
static BACNET_ADDRESS Target_Address;
|
||||
static bool Error_Detected = false;
|
||||
|
||||
static void MyErrorHandler(BACNET_ADDRESS *src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void)src;
|
||||
(void)invoke_id;
|
||||
printf("BACnet Error: %s: %s\r\n",
|
||||
bactext_error_class_name((int)error_class),
|
||||
bactext_error_code_name((int)error_code));
|
||||
/* Error_Detected = true; */
|
||||
}
|
||||
|
||||
static void MyAbortHandler(
|
||||
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason, bool server)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void)src;
|
||||
(void)invoke_id;
|
||||
(void)server;
|
||||
printf(
|
||||
"BACnet Abort: %s\r\n", bactext_abort_reason_name((int)abort_reason));
|
||||
Error_Detected = true;
|
||||
}
|
||||
|
||||
static void MyRejectHandler(
|
||||
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t reject_reason)
|
||||
{
|
||||
/* FIXME: verify src and invoke id */
|
||||
(void)src;
|
||||
(void)invoke_id;
|
||||
printf("BACnet Reject: %s\r\n",
|
||||
bactext_reject_reason_name((int)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);
|
||||
/* handle i-am to support binding to other devices */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, handler_i_am_bind);
|
||||
/* 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);
|
||||
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_PRIVATE_TRANSFER, handler_conf_private_trans);
|
||||
/* handle the data coming back from confirmed requests */
|
||||
apdu_set_confirmed_ack_handler(
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property_ack);
|
||||
|
||||
apdu_set_confirmed_ack_handler(
|
||||
SERVICE_CONFIRMED_PRIVATE_TRANSFER, handler_conf_private_trans_ack);
|
||||
|
||||
/* handle any errors coming back */
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_PRIVATE_TRANSFER, MyErrorHandler);
|
||||
apdu_set_abort_handler(MyAbortHandler);
|
||||
apdu_set_reject_handler(MyRejectHandler);
|
||||
}
|
||||
|
||||
len += encode_application_unsigned(
|
||||
&pt_req_buffer[len], block_number); /* The block number */
|
||||
len += encode_application_unsigned(
|
||||
&pt_req_buffer[len], block->cMyByte1); /* And Then the block contents */
|
||||
len += encode_application_unsigned(&pt_req_buffer[len], block->cMyByte2);
|
||||
len += encode_application_real(&pt_req_buffer[len], block->fMyReal);
|
||||
characterstring_init_ansi(&bsTemp, (char *)block->sMyString);
|
||||
len += encode_application_character_string(&pt_req_buffer[len], &bsTemp);
|
||||
}
|
||||
|
||||
pt_block.serviceParameters = &pt_req_buffer[0];
|
||||
pt_block.serviceParametersLen = len;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
||||
uint16_t pdu_len = 0;
|
||||
unsigned timeout = 100; /* milliseconds */
|
||||
unsigned max_apdu = 0;
|
||||
time_t elapsed_seconds = 0;
|
||||
time_t last_seconds = 0;
|
||||
time_t current_seconds = 0;
|
||||
time_t timeout_seconds = 0;
|
||||
uint8_t invoke_id = 0;
|
||||
bool found = false;
|
||||
DATABLOCK NewData;
|
||||
int iCount = 0;
|
||||
int iType = 0;
|
||||
int iKey;
|
||||
|
||||
if (((argc != 2) && (argc != 3)) ||
|
||||
((argc >= 2) && (strcmp(argv[1], "--help") == 0))) {
|
||||
printf("%s\n", argv[0]);
|
||||
printf("Usage: %s server local-device-instance\r\n or\r\n"
|
||||
" %s remote-device-instance\r\n",
|
||||
filename_remove_path(argv[0]), filename_remove_path(argv[0]));
|
||||
if ((argc > 1) && (strcmp(argv[1], "--help") == 0)) {
|
||||
printf(
|
||||
"\r\nServer mode:\r\n\r\n"
|
||||
"local-device-instance determins the device id of the "
|
||||
"application\r\n"
|
||||
"when running as the server end of a test set up.\r\n\r\n"
|
||||
"Non server:\r\n\r\n"
|
||||
"remote-device-instance indicates the device id of the "
|
||||
"server\r\n"
|
||||
"instance of the application.\r\n"
|
||||
"The non server application will write a series of blocks to "
|
||||
"the\r\n"
|
||||
"server and then retrieve them for display locally\r\n"
|
||||
"First it writes all 8 blocks plus a 9th which should "
|
||||
"trigger\r\n"
|
||||
"an out of range error response. Then it reads all the "
|
||||
"blocks\r\n"
|
||||
"including the ninth and finally it repeats the read "
|
||||
"operation\r\n"
|
||||
"with some deliberate errors to trigger a nack response\r\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* decode the command line parameters */
|
||||
if (_stricmp(argv[1], "server") == 0) {
|
||||
Target_Mode = 1;
|
||||
} else {
|
||||
Target_Mode = 0;
|
||||
}
|
||||
|
||||
Target_Device_Object_Instance = strtol(argv[1 + Target_Mode], NULL, 0);
|
||||
|
||||
if (Target_Device_Object_Instance > BACNET_MAX_INSTANCE) {
|
||||
fprintf(stderr, "device-instance=%u - it must be less than %u\r\n",
|
||||
Target_Device_Object_Instance, BACNET_MAX_INSTANCE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* setup my info */
|
||||
if (Target_Mode) {
|
||||
Device_Set_Object_Instance_Number(Target_Device_Object_Instance);
|
||||
} else {
|
||||
Device_Set_Object_Instance_Number
|
||||
}
|
||||
(BACNET_MAX_INSTANCE);
|
||||
|
||||
address_init();
|
||||
Init_Service_Handlers();
|
||||
dlenv_init();
|
||||
atexit(datalink_cleanup);
|
||||
/* configure the timeout values */
|
||||
last_seconds = time(NULL);
|
||||
timeout_seconds = (apdu_timeout() / 1000) * apdu_retries();
|
||||
|
||||
if (Target_Mode) {
|
||||
printf("Entering server mode. press q to quit program\r\n\r\n");
|
||||
|
||||
for (;;) {
|
||||
/* increment timer - exit if timed out */
|
||||
current_seconds = time(NULL);
|
||||
if (current_seconds != last_seconds) {
|
||||
}
|
||||
|
||||
/* returns 0 bytes on timeout */
|
||||
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
|
||||
|
||||
/* process */
|
||||
if (pdu_len) {
|
||||
npdu_handler(&src, &Rx_Buf[0], pdu_len);
|
||||
}
|
||||
/* at least one second has passed */
|
||||
if (current_seconds != last_seconds) {
|
||||
putchar('.'); /* Just to show that time is passing... */
|
||||
last_seconds = current_seconds;
|
||||
tsm_timer_milliseconds(
|
||||
((current_seconds - last_seconds) * 1000));
|
||||
}
|
||||
|
||||
if (_kbhit()) {
|
||||
iKey = toupper(_getch());
|
||||
if (iKey == 'Q') {
|
||||
printf("\r\nExiting program now\r\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* try to bind with the device */
|
||||
found = address_bind_request(
|
||||
Target_Device_Object_Instance, &max_apdu, &Target_Address);
|
||||
if (!found) {
|
||||
Send_WhoIs(
|
||||
Target_Device_Object_Instance, Target_Device_Object_Instance);
|
||||
}
|
||||
/* loop forever */
|
||||
for (;;) {
|
||||
/* increment timer - exit if timed out */
|
||||
current_seconds = time(NULL);
|
||||
|
||||
/* returns 0 bytes on timeout */
|
||||
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
|
||||
|
||||
/* process */
|
||||
if (pdu_len) {
|
||||
npdu_handler(&src, &Rx_Buf[0], pdu_len);
|
||||
}
|
||||
/* at least one second has passed */
|
||||
if (current_seconds != last_seconds) {
|
||||
tsm_timer_milliseconds(
|
||||
((current_seconds - last_seconds) * 1000));
|
||||
}
|
||||
if (Error_Detected)
|
||||
break;
|
||||
/* wait until the device is bound, or timeout and quit */
|
||||
if (!found)
|
||||
found = address_bind_request(
|
||||
Target_Device_Object_Instance, &max_apdu, &Target_Address);
|
||||
if (found) {
|
||||
if (invoke_id == 0) { /* Safe to send a new request */
|
||||
switch (iType) {
|
||||
case 0: /* Write blocks to server */
|
||||
NewData.cMyByte1 = iCount;
|
||||
NewData.cMyByte2 = 255 - iCount;
|
||||
NewData.fMyReal = (float)iCount;
|
||||
strcpy(
|
||||
(char *)NewData.sMyString, "Test Data - [x]");
|
||||
NewData.sMyString[13] = 'a' + iCount;
|
||||
pt_write_block_to_server()
|
||||
printf("Sending block %d\n", iCount);
|
||||
invoke_id = Send_Private_Transfer_Request(
|
||||
Target_Device_Object_Instance, BACNET_VENDOR_ID,
|
||||
1, iCount, &NewData);
|
||||
break;
|
||||
|
||||
case 1: /* Read blocks from server */
|
||||
printf("Requesting block %d\n", iCount);
|
||||
invoke_id = Send_Private_Transfer_Request(
|
||||
Target_Device_Object_Instance, BACNET_VENDOR_ID,
|
||||
0, iCount, &NewData);
|
||||
break;
|
||||
|
||||
case 2: /* Generate some error responses */
|
||||
switch (iCount) {
|
||||
case 0: /* Bad service number i.e. 2 */
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 8:
|
||||
printf(
|
||||
"Requesting block %d with bad service "
|
||||
"number\n",
|
||||
iCount);
|
||||
invoke_id = Send_Private_Transfer_Request(
|
||||
Target_Device_Object_Instance,
|
||||
BACNET_VENDOR_ID, 2, iCount, &NewData);
|
||||
break;
|
||||
|
||||
case 1: /* Bad vendor ID number */
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
printf("Requesting block %d with invalid "
|
||||
"Vendor ID\n",
|
||||
iCount);
|
||||
invoke_id = Send_Private_Transfer_Request(
|
||||
Target_Device_Object_Instance,
|
||||
BACNET_VENDOR_ID + 1, 0, iCount,
|
||||
&NewData);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else if (tsm_invoke_id_free(invoke_id)) {
|
||||
if (iCount != MY_MAX_BLOCK) {
|
||||
iCount++;
|
||||
invoke_id = 0;
|
||||
} else {
|
||||
iType++;
|
||||
iCount = 0;
|
||||
invoke_id = 0;
|
||||
|
||||
if (iType > 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tsm_invoke_id_failed(invoke_id)) {
|
||||
fprintf(stderr, "\rError: TSM Timeout!\r\n");
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
Error_Detected = true;
|
||||
/* try again or abort? */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* increment timer - exit if timed out */
|
||||
elapsed_seconds += (current_seconds - last_seconds);
|
||||
if (elapsed_seconds > timeout_seconds) {
|
||||
printf("\rError: APDU Timeout!\r\n");
|
||||
Error_Detected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* keep track of time for next check */
|
||||
last_seconds = current_seconds;
|
||||
}
|
||||
}
|
||||
if (Error_Detected)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rdproperty", "rdproperty.vcproj", "{7AC60281-278A-4060-B900-A1343E438701}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7AC60281-278A-4060-B900-A1343E438701}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{7AC60281-278A-4060-B900-A1343E438701}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{7AC60281-278A-4060-B900-A1343E438701}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{7AC60281-278A-4060-B900-A1343E438701}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,123 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "bacnet/config.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/npdu.h"
|
||||
#include "bacnet/apdu.h"
|
||||
#include "bacnet/dcc.h"
|
||||
#include "bacnet/ptransfer.h"
|
||||
/* some demo stuff needed */
|
||||
#include "bacnet/basic/binding/address.h"
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
#include "bacnet/basic/object/device.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
|
||||
/** @file s_ptransfer.c Send a Private Transfer request. */
|
||||
|
||||
uint8_t Send_Private_Transfer_Request(uint32_t device_id,
|
||||
uint16_t vendor_id,
|
||||
uint32_t service_number,
|
||||
unsigned int block_number,
|
||||
char *block)
|
||||
{ /* NULL=optional */
|
||||
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;
|
||||
static uint8_t
|
||||
pt_req_buffer[300]; /* Somewhere to build the request packet */
|
||||
BACNET_PRIVATE_TRANSFER_DATA private_data;
|
||||
|
||||
/* if we are forbidden to send, don't send! */
|
||||
if (!dcc_communication_enabled()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
/* encode the APDU portion of the packet */
|
||||
private_data.vendorID = vendor_id;
|
||||
private_data.serviceNumber = service_number;
|
||||
len = uptransfer_encode_apdu(
|
||||
&Handler_Transmit_Buffer[pdu_len], &private_data);
|
||||
pdu_len += len;
|
||||
|
||||
if (service_number == MY_SVC_READ) {
|
||||
} else {
|
||||
len = ptransfer_encode_apdu(
|
||||
&Handler_Transmit_Buffer[pdu_len], invoke_id, &pt_block);
|
||||
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 Private Transfer Request (%s)!\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
tsm_free_invoke_id(invoke_id);
|
||||
invoke_id = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr,
|
||||
"Failed to Send Private Transfer Request "
|
||||
"(exceeds destination maximum APDU)!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return invoke_id;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Steve Karg
|
||||
* @date October 2019
|
||||
* @brief Header file for a basic WritePropertyMultiple service send
|
||||
*
|
||||
* @section LICENSE
|
||||
*
|
||||
* 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 SEND_WRITE_PROPERTY_MULTIPLE_H
|
||||
#define SEND_WRITE_PROPERTY_MULTIPLE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacnet/bacapp.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/bacenum.h"
|
||||
#include "bacnet/apdu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint8_t Send_Private_Transfer_Request(uint32_t device_id, uint16_t vendor_id,
|
||||
uint32_t service_number,
|
||||
char block_number, DATABLOCK *block);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Reference in New Issue
Block a user