From 6768cc719de1d3d7c08fa8700e1cfd27d7820012 Mon Sep 17 00:00:00 2001 From: skarg Date: Tue, 17 Jan 2006 15:44:39 +0000 Subject: [PATCH] Added new command line demo for AtomicWriteFile service called writefile. Tested with borland compiler on win32. --- bacnet-stack/demo/writefile/makefile.mak | 141 ++++++++ bacnet-stack/demo/writefile/writefile.c | 422 ++++++++++++++++++++++ bacnet-stack/demo/writefile/writefile.ide | Bin 0 -> 53350 bytes 3 files changed, 563 insertions(+) create mode 100644 bacnet-stack/demo/writefile/makefile.mak create mode 100644 bacnet-stack/demo/writefile/writefile.c create mode 100644 bacnet-stack/demo/writefile/writefile.ide diff --git a/bacnet-stack/demo/writefile/makefile.mak b/bacnet-stack/demo/writefile/makefile.mak new file mode 100644 index 00000000..7fb6415e --- /dev/null +++ b/bacnet-stack/demo/writefile/makefile.mak @@ -0,0 +1,141 @@ +# +# Simple makefile to build an executable for Win32 +# +# This makefile assumes Borland bcc32 development environment +# on Windows NT/9x/2000/XP +# + +!ifndef BORLAND_DIR +BORLAND_DIR_Not_Defined: + @echo . + @echo You must define environment variable BORLAND_DIR to compile. +!endif + +PRODUCT = writefile +PRODUCT_EXE = $(PRODUCT).exe + +# Choose the Data Link Layer to Enable +DEFINES = -DBACDL_BIP=1 + +SRCS = writefile.c \ + ..\..\ports\win32\bip-init.c \ + ..\..\bip.c \ + ..\..\demo\handler\txbuf.c \ + ..\..\demo\handler\noserv.c \ + ..\..\demo\handler\h_whois.c \ + ..\..\demo\handler\h_rp.c \ + ..\..\bacdcode.c \ + ..\..\bacapp.c \ + ..\..\bacstr.c \ + ..\..\bactext.c \ + ..\..\indtext.c \ + ..\..\bigend.c \ + ..\..\whois.c \ + ..\..\iam.c \ + ..\..\rp.c \ + ..\..\wp.c \ + ..\..\arf.c \ + ..\..\awf.c \ + ..\..\demo\object\bacfile.c \ + ..\..\demo\object\device.c \ + ..\..\demo\object\ai.c \ + ..\..\demo\object\ao.c \ + ..\..\datalink.c \ + ..\..\tsm.c \ + ..\..\address.c \ + ..\..\abort.c \ + ..\..\reject.c \ + ..\..\bacerror.c \ + ..\..\apdu.c \ + ..\..\npdu.c + +OBJS = $(SRCS:.c=.obj) + +# Compiler definitions +# +CC = $(BORLAND_DIR)\bin\bcc32 +bcc32.cfg +#LINK = $(BORLAND_DIR)\bin\tlink32 +LINK = $(BORLAND_DIR)\bin\ilink32 +TLIB = $(BORLAND_DIR)\bin\tlib + +# +# Include directories +# +CC_DIR = $(BORLAND_DIR)\BIN +INCL_DIRS = -I$(BORLAND_DIR)\include;..\..\;..\..\demo\object\;..\..\demo\handler\;..\..\ports\win32\;. + +CFLAGS = $(INCL_DIRS) $(CS_FLAGS) $(DEFINES) + +# Libraries +# +C_LIB_DIR = $(BORLAND_DIR)\lib + +LIBS = $(C_LIB_DIR)\IMPORT32.lib \ +$(C_LIB_DIR)\CW32MT.lib + +# +# Main target +# +# This should be the first one in the makefile + +all : bcc32.cfg $(PRODUCT_EXE) + +# Linker specific: the link below is for BCC linker/compiler. If you link +# with a different linker - please change accordingly. +# + +# need a temp response file (@&&) because command line is too long +$(PRODUCT_EXE) : $(OBJS) + @echo Running Linker for $(PRODUCT_EXE) + $(LINK) -L$(C_LIB_DIR) -m -c -s -v @&&| # temp response file, starts with | + $(BORLAND_DIR)\lib\c0x32.obj $** # $** lists each dependency + $< + $*.map + $(LIBS) +| # end of temp response file + +# +# Utilities + +clean : + @echo Deleting obj files, $(PRODUCT_EXE) and map files. +# del $(OBJS) # command too long, bummer! + del *.obj + del ..\..\*.obj + del ..\..\demo\handler\*.obj + del ..\..\demo\object\*.obj + del ..\..\ports\win32\*.obj + del $(PRODUCT_EXE) + del *.map + del bcc32.cfg + +# +# Generic rules +# +.SUFFIXES: .cpp .c .sbr .obj + +# +# cc generic rule +# +.c.obj: + $(CC) -o$@ $< + +# Compiler configuration file +bcc32.cfg : + Copy &&| +$(CFLAGS) +-c +-y #include line numbers in OBJ's +-v #include debug info +-w+ #turn on all warnings +-Od #disable all optimizations +#-a4 #32 bit data alignment +#-M # generate link map +#-ls # linker options +#-WM- #not multithread +-WM #multithread +-w-aus # ignore warning assigned a value that is never used +-w-sig # ignore warning conversion may lose sig digits +| $@ + +# EOF: makefile diff --git a/bacnet-stack/demo/writefile/writefile.c b/bacnet-stack/demo/writefile/writefile.c new file mode 100644 index 00000000..24b21479 --- /dev/null +++ b/bacnet-stack/demo/writefile/writefile.c @@ -0,0 +1,422 @@ +/************************************************************************** +* +* Copyright (C) 2006 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. +* +*********************************************************************/ + +/* READFILE: command line tool that writes a file to a BACnet device. */ +#include +#include +#include +#include +#include /* for time */ +#include +#include "bactext.h" +#include "iam.h" +#include "awf.h" +#include "tsm.h" +#include "address.h" +#include "config.h" +#include "bacdef.h" +#include "npdu.h" +#include "apdu.h" +#include "device.h" +#include "net.h" +#include "datalink.h" +#include "whois.h" +/* some demo stuff needed */ +#include "handlers.h" +#include "txbuf.h" + +// buffer used for receive +static uint8_t Rx_Buf[MAX_MPDU] = {0}; + +/* global variables used in this file */ +static uint32_t Target_File_Object_Instance = 4194303; +static uint32_t Target_Device_Object_Instance = 4194303; +static BACNET_ADDRESS Target_Address; +static char *Local_File_Name = NULL; +static bool End_Of_File_Detected = false; +static bool Error_Detected = false; +static uint8_t Current_Invoke_ID = 0; + +static void Atomic_Read_File_Error_Handler( + 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("\r\nBACnet Error!\r\n"); + printf("Error Class: %s\r\n", + bactext_error_class_name(error_class)); + printf("Error Code: %s\r\n", + bactext_error_code_name(error_code)); + Error_Detected = true; +} + +void MyAbortHandler( + BACNET_ADDRESS *src, + uint8_t invoke_id, + uint8_t abort_reason) +{ + /* FIXME: verify src and invoke id */ + (void)src; + (void)invoke_id; + printf("\r\nBACnet Abort!\r\n"); + printf("Abort Reason: %s\r\n", + bactext_abort_reason_name(abort_reason)); + Error_Detected = true; +} + +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("\r\nBACnet Reject!\r\n"); + printf("Reject Reason: %s\r\n", + bactext_reject_reason_name(reject_reason)); + Error_Detected = true; +} + +static uint8_t Send_Atomic_Write_File_Stream( + uint32_t device_id, + uint32_t file_instance, + int fileStartPosition, + BACNET_OCTET_STRING *fileData) +{ + 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_ATOMIC_WRITE_FILE_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_FILE; + data.object_instance = file_instance; + data.access = FILE_STREAM_ACCESS; + data.type.stream.fileStartPosition = fileStartPosition; + status = octetstring_copy(&data.fileData, fileData); + if (status) + { + pdu_len += awf_encode_apdu( + &Handler_Transmit_Buffer[pdu_len], + invoke_id, + &data); + /* will the APDU fit the target device? + 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,"Failed to Send AtomicWriteFile Request (%s)!\n", + strerror(errno)); + } + else + fprintf(stderr,"Failed to Send AtomicWriteFile Request " + "(payload [%d] exceeds destination maximum APDU [%u])!\n", + pdu_len,max_apdu); + } + else + fprintf(stderr,"Failed to Send AtomicWriteFile Request " + "(payload [%d] exceeds octet string capacity)!\n"); + } + + return invoke_id; +} + +static void Send_WhoIs(uint32_t device_id) +{ + 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], + device_id, + device_id); + + 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,"Failed to Send Who-Is Request (%s)!\n", strerror(errno)); +} + +static void LocalIAmHandler( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src) +{ + int len = 0; + uint32_t device_id = 0; + unsigned max_apdu = 0; + int segmentation = 0; + uint16_t vendor_id = 0; + + (void)src; + (void)service_len; + len = iam_decode_service_request( + service_request, + &device_id, + &max_apdu, + &segmentation, + &vendor_id); + if (len != -1) + { + address_add(device_id, + max_apdu, + src); + } + else + fprintf(stderr,"!\n"); + + return; +} + +static void Init_Service_Handlers(void) +{ + /* 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, + LocalIAmHandler); + /* 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); + /* handle any errors coming back */ + apdu_set_error_handler( + SERVICE_CONFIRMED_ATOMIC_READ_FILE, + Atomic_Read_File_Error_Handler); + apdu_set_abort_handler( + MyAbortHandler); + apdu_set_reject_handler( + MyRejectHandler); +} + +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; + int fileStartPosition = 0; + unsigned requestedOctetCount = 0; + uint8_t invoke_id = 0; + bool found = false; + uint16_t my_max_apdu = 0; + FILE *pFile = NULL; + static BACNET_OCTET_STRING fileData; + size_t len = 0; + + if (argc < 4) + { + /* FIXME: what about access method - record or stream? */ + printf("%s device-instance file-instance local-name\r\n",argv[0]); + return 0; + } + /* decode the command line parameters */ + Target_Device_Object_Instance = strtol(argv[1],NULL,0); + Target_File_Object_Instance = strtol(argv[2],NULL,0); + Local_File_Name = argv[3]; + 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; + } + if (Target_File_Object_Instance >= BACNET_MAX_INSTANCE) + { + fprintf(stderr,"file-instance=%u - it must be less than %u\r\n", + Target_File_Object_Instance,BACNET_MAX_INSTANCE+1); + return 1; + } + /* setup my info */ + Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); + address_init(); + Init_Service_Handlers(); + /* configure standard BACnet/IP port */ + bip_set_interface("eth0"); /* for linux */ + bip_set_port(0xBAC0); + if (!bip_init()) + return 1; + /* configure the timeout values */ + last_seconds = time(NULL); + timeout_seconds = (Device_APDU_Timeout() / 1000) * + Device_Number_Of_APDU_Retries(); + /* try to bind with the device */ + Send_WhoIs(Target_Device_Object_Instance); + /* loop forever */ + for (;;) + { + /* increment timer - exit if timed out */ + current_seconds = time(NULL); + + /* returns 0 bytes on timeout */ + pdu_len = bip_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 (End_Of_File_Detected || Error_Detected) + break; + if (I_Am_Request) + { + I_Am_Request = false; + iam_send(&Handler_Transmit_Buffer[0]); + } + else + { + /* wait until the device is bound, or timeout and quit */ + found = address_bind_request( + Target_Device_Object_Instance, + &max_apdu, + &Target_Address); + if (found) + { + /* calculate the smaller of our APDU size or theirs + and remove the overhead of the APDU (about 20 octets max). + note: we could fail if there is a bottle neck (router) + and smaller MPDU in betweeen. */ + if (max_apdu < MAX_APDU) + my_max_apdu = max_apdu; + else + my_max_apdu = MAX_APDU; + requestedOctetCount = my_max_apdu - 20; + /* 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)) + { + if (invoke_id != 0) + fileStartPosition += requestedOctetCount; + /* we'll read the file in chunks + less than max_apdu to keep unsegmented */ + pFile = fopen(Local_File_Name,"rb"); + if (pFile) + { + (void)fseek(pFile, + fileStartPosition, + SEEK_SET); + len = fread(octetstring_value(&fileData), 1, + requestedOctetCount, pFile); + if (len < requestedOctetCount) + End_Of_File_Detected = true; + octetstring_truncate(&fileData,len); + fclose(pFile); + } + printf("\rSending %d bytes",(fileStartPosition+len)); + invoke_id = Send_Atomic_Write_File_Stream( + Target_Device_Object_Instance, + Target_File_Object_Instance, + fileStartPosition, + &fileData); + Current_Invoke_ID = invoke_id; + } + } + else + { + /* increment timer - exit if timed out */ + elapsed_seconds += (current_seconds - last_seconds); + if (elapsed_seconds > timeout_seconds) + break; + } + } + /* keep track of time for next check */ + last_seconds = current_seconds; + } + + return 0; +} diff --git a/bacnet-stack/demo/writefile/writefile.ide b/bacnet-stack/demo/writefile/writefile.ide new file mode 100644 index 0000000000000000000000000000000000000000..a6a3468e30f9c0b99742397635220deb4349354f GIT binary patch literal 53350 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 Pf1&R;8VnLEgq;5aQJ!5l literal 0 HcmV?d00001