From 67a7cdbc12b0a6bb0a9f1265aabb1ea2e20ef950 Mon Sep 17 00:00:00 2001 From: skarg Date: Sat, 27 Sep 2008 22:19:23 +0000 Subject: [PATCH] Added port for ATmega8 - but not quite small enough yet. Compiled for ATmega168 (but at 8734 bytes of flash). --- bacnet-stack/ports/atmega8/Makefile | 178 ++++ bacnet-stack/ports/atmega8/ai.c | 159 ++++ bacnet-stack/ports/atmega8/apdu.c | 123 +++ bacnet-stack/ports/atmega8/av.c | 253 +++++ bacnet-stack/ports/atmega8/avr035.h | 18 + bacnet-stack/ports/atmega8/bacnet.map | 1130 +++++++++++++++++++++++ bacnet-stack/ports/atmega8/bv.c | 302 ++++++ bacnet-stack/ports/atmega8/device.c | 331 +++++++ bacnet-stack/ports/atmega8/dlmstp.c | 765 +++++++++++++++ bacnet-stack/ports/atmega8/h_rp.c | 173 ++++ bacnet-stack/ports/atmega8/h_whois.c | 71 ++ bacnet-stack/ports/atmega8/h_wp.c | 139 +++ bacnet-stack/ports/atmega8/hardware.h | 54 ++ bacnet-stack/ports/atmega8/hardware.ods | Bin 0 -> 19823 bytes bacnet-stack/ports/atmega8/iar2gcc.h | 226 +++++ bacnet-stack/ports/atmega8/main.c | 122 +++ bacnet-stack/ports/atmega8/readme.txt | 45 + bacnet-stack/ports/atmega8/rs485.c | 292 ++++++ bacnet-stack/ports/atmega8/rs485.h | 70 ++ bacnet-stack/ports/atmega8/stdbool.h | 28 + bacnet-stack/ports/atmega8/stdint.h | 15 + bacnet-stack/ports/atmega8/timer.c | 109 +++ bacnet-stack/ports/atmega8/timer.h | 42 + 23 files changed, 4645 insertions(+) create mode 100644 bacnet-stack/ports/atmega8/Makefile create mode 100644 bacnet-stack/ports/atmega8/ai.c create mode 100644 bacnet-stack/ports/atmega8/apdu.c create mode 100644 bacnet-stack/ports/atmega8/av.c create mode 100644 bacnet-stack/ports/atmega8/avr035.h create mode 100644 bacnet-stack/ports/atmega8/bacnet.map create mode 100644 bacnet-stack/ports/atmega8/bv.c create mode 100644 bacnet-stack/ports/atmega8/device.c create mode 100644 bacnet-stack/ports/atmega8/dlmstp.c create mode 100644 bacnet-stack/ports/atmega8/h_rp.c create mode 100644 bacnet-stack/ports/atmega8/h_whois.c create mode 100644 bacnet-stack/ports/atmega8/h_wp.c create mode 100644 bacnet-stack/ports/atmega8/hardware.h create mode 100644 bacnet-stack/ports/atmega8/hardware.ods create mode 100644 bacnet-stack/ports/atmega8/iar2gcc.h create mode 100644 bacnet-stack/ports/atmega8/main.c create mode 100644 bacnet-stack/ports/atmega8/readme.txt create mode 100644 bacnet-stack/ports/atmega8/rs485.c create mode 100644 bacnet-stack/ports/atmega8/rs485.h create mode 100644 bacnet-stack/ports/atmega8/stdbool.h create mode 100644 bacnet-stack/ports/atmega8/stdint.h create mode 100644 bacnet-stack/ports/atmega8/timer.c create mode 100644 bacnet-stack/ports/atmega8/timer.h diff --git a/bacnet-stack/ports/atmega8/Makefile b/bacnet-stack/ports/atmega8/Makefile new file mode 100644 index 00000000..7456debb --- /dev/null +++ b/bacnet-stack/ports/atmega8/Makefile @@ -0,0 +1,178 @@ +############################################################################### +# Makefile for BACnet +############################################################################### + +## General Flags +PROJECT = bacnet +MCU = atmega168 +TARGET = bacnet +## Tools +CC = avr-gcc +AR = avr-ar +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size + +# Source locations +BACNET_CORE = ../../src +BACNET_INCLUDE = ../../include +BACNET_DEMO = ../../demo + +# local files for this project +CSRC = main.c \ + timer.c \ + rs485.c \ + dlmstp.c \ + apdu.c \ + $(BACNET_CORE)/crc.c + +# common demo files needed +DEMOSRC = h_rp.c \ + device.c \ + $(BACNET_DEMO)/handler/txbuf.c \ + $(BACNET_DEMO)/handler/h_npdu.c \ + $(BACNET_DEMO)/handler/noserv.c + +# core BACnet stack files +CORESRC = \ + $(BACNET_CORE)/apdu.c \ + $(BACNET_CORE)/npdu.c \ + $(BACNET_CORE)/bacdcode.c \ + $(BACNET_CORE)/bacint.c \ + $(BACNET_CORE)/bacreal.c \ + $(BACNET_CORE)/bacstr.c \ + $(BACNET_CORE)/rp.c \ + $(BACNET_CORE)/bacaddr.c \ + $(BACNET_CORE)/abort.c \ + $(BACNET_CORE)/reject.c \ + $(BACNET_CORE)/bacerror.c \ + $(BACNET_CORE)/bacapp.c + +# $(BACNET_CORE)/iam.c \ +# $(BACNET_CORE)/whois.c \ +# $(BACNET_CORE)/wp.c \ +# $(BACNET_CORE)/version.c +# $(BACNET_CORE)/bacprop.c \ +# $(BACNET_CORE)/bactext.c \ +# $(BACNET_CORE)/datetime.c \ +# $(BACNET_CORE)/indtext.c \ +# $(BACNET_CORE)/bigend.c \ +# $(BACNET_CORE)/arf.c \ +# $(BACNET_CORE)/awf.c \ +# $(BACNET_CORE)/cov.c \ +# $(BACNET_CORE)/dcc.c \ +# $(BACNET_CORE)/iam/iam_client.c \ +# $(BACNET_CORE)/ihave.c \ +# $(BACNET_CORE)/rd.c \ +# $(BACNET_CORE)/rpm.c \ +# $(BACNET_CORE)/timesync.c \ +# $(BACNET_CORE)/whohas.c \ +# $(BACNET_CORE)/filename.c \ +# $(BACNET_CORE)/tsm.c \ +# $(BACNET_CORE)/address.c \ + +## Include Directories +INCLUDES = -I. -I$(BACNET_INCLUDE) + +# Source to Object conversion +COBJ = $(CSRC:.c=.o) +DEMOOBJ = $(DEMOSRC:.c=.o) +COREOBJ = $(CORESRC:.c=.o) + +LIBRARY = lib$(TARGET).a + +## Options common to compile, link and assembly rules +COMMON = -mmcu=$(MCU) + +OPTIMIZE_FLAGS = -mcall-prologues +#OPTIMIZE_FLAGS += -finline-functions +OPTIMIZE_FLAGS += -finline-functions-called-once +#OPTIMIZATION = -O0 +#OPTIMIZATION = -Os +OPTIMIZATION = -Os $(OPTIMIZE_FLAGS) +#OPTIMIZATION = -O3 $(OPTIMIZE_FLAGS) + +## Compile options common for all C compilation units. +BFLAGS = -DBACDL_MSTP +BFLAGS += -DMAX_APDU=50 +BFLAGS += -DBIG_ENDIAN=0 +BFLAGS += -DMAX_TSM_TRANSACTIONS=0 +#BFLAGS += -DCRC_USE_TABLE +#BFLAGS += -DBACAPP_REAL +#BFLAGS += -DBACAPP_OBJECT_ID +#BFLAGS += -DBACAPP_UNSIGNED +#BFLAGS += -DBACAPP_ENUMERATED +#BFLAGS += -DBACAPP_CHARACTER_STRING +#BFLAGS += -DWRITE_PROPERTY +BFLAGS += -DMAX_ANALOG_VALUES=0 +BFLAGS += -DMAX_BINARY_VALUES=0 +CFLAGS = $(COMMON) +# dead code removal +CFLAGS += -ffunction-sections -fdata-sections +CFLAGS += -Wall -gdwarf-2 $(BFLAGS) $(OPTIMIZATION) -fsigned-char +CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d + +## Assembly specific flags +ASMFLAGS = $(COMMON) +ASMFLAGS += $(CFLAGS) +ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2 + +## Linker flags +LDFLAGS = $(COMMON) +#dead code removal +#LDFLAGS += -Wl,-nostartfiles,-nostdlib +LDFLAGS += -Wl,--gc-sections,-static +LDFLAGS += -Wl,-Map=$(TARGET).map,-L=.,-l$(TARGET) +#LDFLAGS += -Wl,-Map=$(TARGET).map + +## Intel Hex file production flags +HEX_FLASH_FLAGS = -R .eeprom +HEX_EEPROM_FLAGS = -j .eeprom +HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load" +HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings + +## Objects that must be built in order to link +OBJECTS = $(COBJ) $(DEMOOBJ) +#OBJECTS = $(COBJ) + +## Build +TARGET_ELF=$(TARGET).elf + +all: $(LIBRARY) $(TARGET_ELF) $(TARGET).hex $(TARGET).eep $(TARGET).lst \ + size Makefile + +##Link +$(TARGET_ELF): $(OBJECTS) $(LIBRARY) + $(CC) $(OBJECTS) $(LDFLAGS) -o $@ + +%.hex: $(TARGET_ELF) + $(OBJCOPY) -O ihex $(HEX_FLASH_FLAGS) $< $@ + +%.eep: $(TARGET_ELF) + -$(OBJCOPY) $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0 + +%.lst: $(TARGET_ELF) + $(OBJDUMP) -h -S $< > $@ + +lib: $(LIBRARY) + +$(LIBRARY): $(COREOBJ) Makefile + $(AR) rcs $@ $(COREOBJ) + $(OBJDUMP) --syms $@ > $(LIBRARY:.a=.lst) + +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@ + +size: ${TARGET_ELF} + @echo + @${SIZE} -C --mcu=${MCU} ${TARGET_ELF} + +## Clean target +.PHONY: clean +clean: + -rm -rf $(OBJECTS) $(TARGET_ELF) dep/* + -rm -rf $(LIBRARY) $(COREOBJ) $(LIBRARY:.a=.lst) + -rm -rf $(TARGET).hex $(TARGET).eep $(TARGET).lst $(TARGET).map + +## Other dependencies +-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*) diff --git a/bacnet-stack/ports/atmega8/ai.c b/bacnet-stack/ports/atmega8/ai.c new file mode 100644 index 00000000..00d0933f --- /dev/null +++ b/bacnet-stack/ports/atmega8/ai.c @@ -0,0 +1,159 @@ +/************************************************************************** +* +* 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. +* +*********************************************************************/ + +/* Analog Input Objects customize for your use */ + +#include +#include +#include +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "config.h" + +/* Analog Input = Photocell */ +#define MAX_ANALOG_INPUTS 9 +#if (MAX_ANALOG_INPUTS > 9) +#error Modify the Analog_Input_Name to handle multiple digits +#endif + +float Present_Value[MAX_ANALOG_INPUTS]; + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need validate that the */ +/* given instance exists */ +bool Analog_Input_Valid_Instance( + uint32_t object_instance) +{ + if (object_instance < MAX_ANALOG_INPUTS) + return true; + + return false; +} + +/* we simply have 0-n object instances. */ +unsigned Analog_Input_Count( + void) +{ + return MAX_ANALOG_INPUTS; +} + +/* we simply have 0-n object instances. */ +uint32_t Analog_Input_Index_To_Instance( + unsigned index) +{ + return index; +} + +/* we simply have 0-n object instances. */ +unsigned Analog_Input_Instance_To_Index( + uint32_t object_instance) +{ + return object_instance; +} + + +char *Analog_Input_Name( + uint32_t object_instance) +{ + static char text_string[5] = "AI-0"; /* okay for single thread */ + + if (object_instance < MAX_ANALOG_INPUTS) { + text_string[3] = '0' + (uint8_t) object_instance; + return text_string; + } + + return NULL; +} + +/* return apdu length, or -1 on error */ +/* assumption - object has already exists */ +int Analog_Input_Encode_Property_APDU( + uint8_t * apdu, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + unsigned object_index; + + + (void) array_index; + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = + encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT, + object_instance); + break; + /* note: Name and Description don't have to be the same. + You could make Description writable and different. + Note that Object-Name must be unique in this device */ + case PROP_OBJECT_NAME: + case PROP_DESCRIPTION: + characterstring_init_ansi(&char_string, + Analog_Input_Name(object_instance)); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = + encode_application_enumerated(&apdu[0], OBJECT_ANALOG_INPUT); + break; + case PROP_PRESENT_VALUE: + object_index = Analog_Input_Instance_To_Index(object_instance); + apdu_len = + encode_application_real(&apdu[0], Present_Value[object_index]); + break; + case PROP_STATUS_FLAGS: + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + case PROP_EVENT_STATE: + apdu_len = + encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); + break; + case PROP_OUT_OF_SERVICE: + apdu_len = encode_application_boolean(&apdu[0], false); + break; + case PROP_UNITS: + apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} diff --git a/bacnet-stack/ports/atmega8/apdu.c b/bacnet-stack/ports/atmega8/apdu.c new file mode 100644 index 00000000..e0e2e5b6 --- /dev/null +++ b/bacnet-stack/ports/atmega8/apdu.c @@ -0,0 +1,123 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2007 Steve Karg + + 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####*/ +#include +#include +#include +#include "bits.h" +#include "apdu.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "handlers.h" + +bool apdu_service_supported( + BACNET_SERVICES_SUPPORTED service_supported) +{ + bool status = false; + + if (service_supported == SERVICE_SUPPORTED_READ_PROPERTY) { + status = true; + } + + return status; +} + +uint16_t apdu_decode_confirmed_service_request( + uint8_t * apdu, /* APDU data */ + uint16_t apdu_len, + BACNET_CONFIRMED_SERVICE_DATA * service_data, + uint8_t * service_choice, + uint8_t ** service_request, + uint16_t * service_request_len) +{ + uint16_t len = 0; /* counts where we are in PDU */ + + service_data->segmented_message = (apdu[0] & BIT3) ? true : false; + service_data->more_follows = (apdu[0] & BIT2) ? true : false; + service_data->segmented_response_accepted = + (apdu[0] & BIT1) ? true : false; + service_data->max_segs = decode_max_segs(apdu[1]); + service_data->max_resp = decode_max_apdu(apdu[1]); + service_data->invoke_id = apdu[2]; + len = 3; + if (service_data->segmented_message) { + service_data->sequence_number = apdu[len++]; + service_data->proposed_window_number = apdu[len++]; + } + *service_choice = apdu[len++]; + *service_request = &apdu[len]; + *service_request_len = apdu_len - len; + + return len; +} + +void apdu_handler( + BACNET_ADDRESS * src, + uint8_t * apdu, /* APDU data */ + uint16_t apdu_len) +{ + BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 }; + uint8_t service_choice = 0; + uint8_t *service_request = NULL; + uint16_t service_request_len = 0; + uint16_t len = 0; /* counts where we are in PDU */ + + if (apdu) { + /* PDU Type */ + switch (apdu[0] & 0xF0) { + case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: + len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */ + apdu_len, &service_data, &service_choice, &service_request, + &service_request_len); + if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) { + handler_read_property(service_request, service_request_len, + src, &service_data); + } else { + handler_unrecognized_service(service_request, + service_request_len, src, &service_data); + } + break; + case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST: + case PDU_TYPE_SIMPLE_ACK: + case PDU_TYPE_COMPLEX_ACK: + case PDU_TYPE_SEGMENT_ACK: + case PDU_TYPE_ERROR: + case PDU_TYPE_REJECT: + case PDU_TYPE_ABORT: + default: + break; + } + } + return; +} diff --git a/bacnet-stack/ports/atmega8/av.c b/bacnet-stack/ports/atmega8/av.c new file mode 100644 index 00000000..14b3dc7a --- /dev/null +++ b/bacnet-stack/ports/atmega8/av.c @@ -0,0 +1,253 @@ +/************************************************************************** +* +* 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. +* +*********************************************************************/ + +/* Analog Value Objects - customize for your use */ + +#include +#include +#include "hardware.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "bacapp.h" +#include "config.h" /* the custom stuff */ +#include "wp.h" +#include "av.h" + +#if (MAX_ANALOG_VALUES > 10) +#error Modify the Analog_Value_Name to handle multiple digits +#endif + +float AV_Present_Value[MAX_ANALOG_VALUES]; + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need validate that the */ +/* given instance exists */ +bool Analog_Value_Valid_Instance( + uint32_t object_instance) +{ + if (object_instance < MAX_ANALOG_VALUES) + return true; + + return false; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then count how many you have */ +unsigned Analog_Value_Count( + void) +{ + return MAX_ANALOG_VALUES; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the instance */ +/* that correlates to the correct index */ +uint32_t Analog_Value_Index_To_Instance( + unsigned index) +{ + return index; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the index */ +/* that correlates to the correct instance number */ +unsigned Analog_Value_Instance_To_Index( + uint32_t object_instance) +{ + return object_instance; +} + +/* note: the object name must be unique within this device */ +char *Analog_Value_Name( + uint32_t object_instance) +{ + static char text_string[5] = "AV-"; /* okay for single thread */ + + text_string[3] = '0' + (uint8_t) object_instance; + + return text_string; +} + +/* return apdu len, or -1 on error */ +int Analog_Value_Encode_Property_APDU( + uint8_t * apdu, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + unsigned object_index; + + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = + encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE, + object_instance); + break; + case PROP_OBJECT_NAME: + characterstring_init_ansi(&char_string, + Analog_Value_Name(object_instance)); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = + encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE); + break; + case PROP_PRESENT_VALUE: + object_index = Analog_Value_Instance_To_Index(object_instance); + apdu_len = + encode_application_real(&apdu[0], + AV_Present_Value[object_index]); + break; + case PROP_STATUS_FLAGS: + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + case PROP_EVENT_STATE: + apdu_len = + encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); + break; + case PROP_OUT_OF_SERVICE: + apdu_len = encode_application_boolean(&apdu[0], false); + break; + case PROP_UNITS: + apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + +/* returns true if successful */ +bool Analog_Value_Write_Property( + BACNET_WRITE_PROPERTY_DATA * wp_data, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + bool status = false; /* return value */ + unsigned int object_index = 0; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + + if (!Analog_Value_Valid_Instance(wp_data->object_instance)) { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + return false; + } + /* decode the some of the request */ + len = + bacapp_decode_application_data(wp_data->application_data, + wp_data->application_data_len, &value); + /* FIXME: len < application_data_len: more data? */ + /* FIXME: len == 0: unable to decode? */ + switch (wp_data->object_property) { + case PROP_PRESENT_VALUE: + if (value.tag == BACNET_APPLICATION_TAG_REAL) { + object_index = + Analog_Value_Instance_To_Index(wp_data->object_instance); + AV_Present_Value[object_index] = value.type.Real; + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } + + return status; +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testAnalog_Value( + Test * pTest) +{ + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0; + uint32_t len_value = 0; + uint8_t tag_number = 0; + BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_VALUE; + uint32_t decoded_instance = 0; + uint32_t instance = 123; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; + + len = + Analog_Value_Encode_Property_APDU(&apdu[0], instance, + PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code); + ct_test(pTest, len != 0); + len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); + len = + decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance); + ct_test(pTest, decoded_type == OBJECT_ANALOG_VALUE); + ct_test(pTest, decoded_instance == instance); + + return; +} + +#ifdef TEST_ANALOG_VALUE +int main( + void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet Analog Value", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testAnalog_Value); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_ANALOG_VALUE */ +#endif /* TEST */ diff --git a/bacnet-stack/ports/atmega8/avr035.h b/bacnet-stack/ports/atmega8/avr035.h new file mode 100644 index 00000000..3e287aec --- /dev/null +++ b/bacnet-stack/ports/atmega8/avr035.h @@ -0,0 +1,18 @@ +#ifndef AVR035_H +#define AVR035_H + +/* from AVR035: Efficient C Coding for AVR */ + +/* a=register, b=bit number to act upon */ +#define BIT_SET(a,b) ((a) |= (1<<(b))) +#define BIT_CLEAR(a,b) ((a) &= ~(1<<(b))) +#define BIT_FLIP(a,b) ((a) ^= (1<<(b))) +#define BIT_CHECK(a,b) ((a) & (1<<(b))) + +/* x=target variable, y=mask */ +#define BITMASK_SET(x,y) ((x) |= (y)) +#define BITMASK_CLEAR(x,y) ((x) &= (~(y))) +#define BITMASK_FLIP(x,y) ((x) ^= (y)) +#define BITMASK_CHECK(x,y) ((x) & (y)) + +#endif diff --git a/bacnet-stack/ports/atmega8/bacnet.map b/bacnet-stack/ports/atmega8/bacnet.map new file mode 100644 index 00000000..ad4abae0 --- /dev/null +++ b/bacnet-stack/ports/atmega8/bacnet.map @@ -0,0 +1,1130 @@ +Archive member included because of file (symbol) + +.\libbacnet.a(npdu.o) h_rp.o (npdu_encode_npdu_data) +.\libbacnet.a(bacdcode.o) apdu.o (decode_max_segs) +.\libbacnet.a(bacint.o) .\libbacnet.a(npdu.o) (encode_unsigned16) +.\libbacnet.a(bacreal.o) .\libbacnet.a(bacdcode.o) (encode_bacnet_real) +.\libbacnet.a(bacstr.o) device.o (bitstring_init) +.\libbacnet.a(rp.o) h_rp.o (rp_decode_service_request) +.\libbacnet.a(abort.o) h_rp.o (abort_encode_apdu) +.\libbacnet.a(reject.o) ../../demo/handler/noserv.o (reject_encode_apdu) +.\libbacnet.a(bacerror.o) h_rp.o (bacerror_encode_apdu) +c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_udivmodsi4.o) + rs485.o (__udivmodsi4) +c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_prologue.o) + main.o (__prologue_saves__) +c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_epilogue.o) + dlmstp.o (__epilogue_restores__) +c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_exit.o) + c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o (exit) +c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_copy_data.o) + main.o (__do_copy_data) +c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_clear_bss.o) + main.o (__do_clear_bss) + +Discarded input sections + + .data 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + .bss 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + .text 0x00000000 0x0 main.o + .data 0x00000000 0x0 main.o + .bss 0x00000000 0x0 main.o + .text.dcc_communication_enabled + 0x00000000 0x0 main.o + .data.BACnet_Version + 0x00000000 0x0 main.o + .text 0x00000000 0x0 timer.o + .data 0x00000000 0x0 timer.o + .bss 0x00000000 0x0 timer.o + .text 0x00000000 0x0 rs485.o + .data 0x00000000 0x0 rs485.o + .bss 0x00000000 0x0 rs485.o + .text.RS485_Get_Baud_Rate + 0x00000000 0x0 rs485.o + .text 0x00000000 0x0 dlmstp.o + .data 0x00000000 0x0 dlmstp.o + .bss 0x00000000 0x0 dlmstp.o + .text.dlmstp_cleanup + 0x00000000 0x0 dlmstp.o + .text.dlmstp_fill_bacnet_address + 0x00000000 0x0 dlmstp.o + .text.dlmstp_set_mac_address + 0x00000000 0x0 dlmstp.o + .text.dlmstp_mac_address + 0x00000000 0x0 dlmstp.o + .text.dlmstp_get_broadcast_address + 0x00000000 0x0 dlmstp.o + .text 0x00000000 0x0 apdu.o + .data 0x00000000 0x0 apdu.o + .bss 0x00000000 0x0 apdu.o + .text 0x00000000 0x0 ../../src/crc.o + .data 0x00000000 0x0 ../../src/crc.o + .bss 0x00000000 0x0 ../../src/crc.o + .text 0x00000000 0x0 h_rp.o + .data 0x00000000 0x0 h_rp.o + .bss 0x00000000 0x0 h_rp.o + .text 0x00000000 0x0 device.o + .bss 0x00000000 0x0 device.o + .text.Device_Init + 0x00000000 0x0 device.o + .text.Device_Object_Instance_Number + 0x00000000 0x0 device.o + .text.Device_Set_Object_Instance_Number + 0x00000000 0x0 device.o + .text.Device_Vendor_Identifier + 0x00000000 0x0 device.o + .text.Device_Object_List_Count + 0x00000000 0x0 device.o + .text 0x00000000 0x0 ../../demo/handler/txbuf.o + .data 0x00000000 0x0 ../../demo/handler/txbuf.o + .bss 0x00000000 0x0 ../../demo/handler/txbuf.o + .text 0x00000000 0x0 ../../demo/handler/h_npdu.o + .data 0x00000000 0x0 ../../demo/handler/h_npdu.o + .bss 0x00000000 0x0 ../../demo/handler/h_npdu.o + .text 0x00000000 0x0 ../../demo/handler/noserv.o + .data 0x00000000 0x0 ../../demo/handler/noserv.o + .bss 0x00000000 0x0 ../../demo/handler/noserv.o + .text 0x00000000 0x0 .\libbacnet.a(npdu.o) + .data 0x00000000 0x0 .\libbacnet.a(npdu.o) + .bss 0x00000000 0x0 .\libbacnet.a(npdu.o) + .text.npdu_copy_data + 0x00000000 0x0 .\libbacnet.a(npdu.o) + .text 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .data 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .bss 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_max_segs_max_apdu + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_is_context_specific + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_is_opening_tag + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_is_closing_tag + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_is_opening_tag_number + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_is_closing_tag_number + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_context_boolean + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_boolean + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_bacnet_time + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_bacnet_time + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_bacnet_date + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_date + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_simple_ack + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_bacnet_signed + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_signed + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_date + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_application_date + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_time + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_application_time + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_double + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_application_double + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_real + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_application_real + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_signed + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_application_signed + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_null + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_application_null + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_boolean + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_application_boolean + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_character_string + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_character_string + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_octet_string + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_octet_string + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_octet_string + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_application_octet_string + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.encode_context_bitstring + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text.decode_bitstring + 0x00000000 0x0 .\libbacnet.a(bacdcode.o) + .text 0x00000000 0x0 .\libbacnet.a(bacint.o) + .data 0x00000000 0x0 .\libbacnet.a(bacint.o) + .bss 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text.encode_signed8 + 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text.decode_signed8 + 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text.encode_signed16 + 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text.decode_signed16 + 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text.encode_signed24 + 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text.decode_signed24 + 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text.encode_signed32 + 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text.decode_signed32 + 0x00000000 0x0 .\libbacnet.a(bacint.o) + .text 0x00000000 0x0 .\libbacnet.a(bacreal.o) + .data 0x00000000 0x0 .\libbacnet.a(bacreal.o) + .bss 0x00000000 0x0 .\libbacnet.a(bacreal.o) + .text.decode_real + 0x00000000 0x0 .\libbacnet.a(bacreal.o) + .text.encode_bacnet_real + 0x00000000 0x0 .\libbacnet.a(bacreal.o) + .text.decode_double + 0x00000000 0x0 .\libbacnet.a(bacreal.o) + .text.encode_bacnet_double + 0x00000000 0x0 .\libbacnet.a(bacreal.o) + .text 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .data 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .bss 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.bitstring_bit + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.bitstring_set_octet + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.bitstring_set_bits_used + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.bitstring_bits_capacity + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.bitstring_copy + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.characterstring_ansi_copy + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.characterstring_same + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.characterstring_append + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.characterstring_truncate + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.characterstring_capacity + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.octetstring_init + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.octetstring_append + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.octetstring_truncate + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.octetstring_value + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.octetstring_length + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.octetstring_capacity + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.characterstring_ansi_same + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.characterstring_copy + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text.octetstring_copy + 0x00000000 0x0 .\libbacnet.a(bacstr.o) + .text 0x00000000 0x0 .\libbacnet.a(rp.o) + .data 0x00000000 0x0 .\libbacnet.a(rp.o) + .bss 0x00000000 0x0 .\libbacnet.a(rp.o) + .text.rp_ack_decode_service_request + 0x00000000 0x0 .\libbacnet.a(rp.o) + .text.rp_ack_encode_apdu + 0x00000000 0x0 .\libbacnet.a(rp.o) + .text.rp_encode_apdu + 0x00000000 0x0 .\libbacnet.a(rp.o) + .text 0x00000000 0x0 .\libbacnet.a(abort.o) + .data 0x00000000 0x0 .\libbacnet.a(abort.o) + .bss 0x00000000 0x0 .\libbacnet.a(abort.o) + .text.abort_decode_service_request + 0x00000000 0x0 .\libbacnet.a(abort.o) + .text 0x00000000 0x0 .\libbacnet.a(reject.o) + .data 0x00000000 0x0 .\libbacnet.a(reject.o) + .bss 0x00000000 0x0 .\libbacnet.a(reject.o) + .text.reject_decode_service_request + 0x00000000 0x0 .\libbacnet.a(reject.o) + .text 0x00000000 0x0 .\libbacnet.a(bacerror.o) + .data 0x00000000 0x0 .\libbacnet.a(bacerror.o) + .bss 0x00000000 0x0 .\libbacnet.a(bacerror.o) + .text.bacerror_decode_error_class_and_code + 0x00000000 0x0 .\libbacnet.a(bacerror.o) + .text.bacerror_decode_service_request + 0x00000000 0x0 .\libbacnet.a(bacerror.o) + .text 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_udivmodsi4.o) + .data 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_udivmodsi4.o) + .bss 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_udivmodsi4.o) + .text 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_prologue.o) + .data 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_prologue.o) + .bss 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_prologue.o) + .text 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_epilogue.o) + .data 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_epilogue.o) + .bss 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_epilogue.o) + .text 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_exit.o) + .data 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_exit.o) + .bss 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_exit.o) + .text.libgcc 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_exit.o) + .text 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_copy_data.o) + .data 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_copy_data.o) + .bss 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_copy_data.o) + .text.libgcc 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_copy_data.o) + .text 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_clear_bss.o) + .data 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_clear_bss.o) + .bss 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_clear_bss.o) + .text.libgcc 0x00000000 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_clear_bss.o) + +Memory Configuration + +Name Origin Length Attributes +text 0x00000000 0x00020000 xr +data 0x00800060 0x0000ffa0 rw !x +eeprom 0x00810000 0x00010000 rw !x +fuse 0x00820000 0x00000400 rw !x +lock 0x00830000 0x00000400 rw !x +signature 0x00840000 0x00000400 rw !x +*default* 0x00000000 0xffffffff + +Linker script and memory map + +Address of section .data set to 0x800100 +LOAD c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o +LOAD main.o +LOAD timer.o +LOAD rs485.o +LOAD dlmstp.o +LOAD apdu.o +LOAD ../../src/crc.o +LOAD h_rp.o +LOAD device.o +LOAD ../../demo/handler/txbuf.o +LOAD ../../demo/handler/h_npdu.o +LOAD ../../demo/handler/noserv.o +LOAD .\libbacnet.a +LOAD c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a +LOAD c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5\libc.a +LOAD c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a + +.hash + *(.hash) + +.dynsym + *(.dynsym) + +.dynstr + *(.dynstr) + +.gnu.version + *(.gnu.version) + +.gnu.version_d + *(.gnu.version_d) + +.gnu.version_r + *(.gnu.version_r) + +.rel.init + *(.rel.init) + +.rela.init + *(.rela.init) + +.rel.text + *(.rel.text) + *(.rel.text.*) + *(.rel.gnu.linkonce.t*) + +.rela.text + *(.rela.text) + *(.rela.text.*) + *(.rela.gnu.linkonce.t*) + +.rel.fini + *(.rel.fini) + +.rela.fini + *(.rela.fini) + +.rel.rodata + *(.rel.rodata) + *(.rel.rodata.*) + *(.rel.gnu.linkonce.r*) + +.rela.rodata + *(.rela.rodata) + *(.rela.rodata.*) + *(.rela.gnu.linkonce.r*) + +.rel.data + *(.rel.data) + *(.rel.data.*) + *(.rel.gnu.linkonce.d*) + +.rela.data + *(.rela.data) + *(.rela.data.*) + *(.rela.gnu.linkonce.d*) + +.rel.ctors + *(.rel.ctors) + +.rela.ctors + *(.rela.ctors) + +.rel.dtors + *(.rel.dtors) + +.rela.dtors + *(.rela.dtors) + +.rel.got + *(.rel.got) + +.rela.got + *(.rela.got) + +.rel.bss + *(.rel.bss) + +.rela.bss + *(.rela.bss) + +.rel.plt + *(.rel.plt) + +.rela.plt + *(.rela.plt) + +.text 0x00000000 0x21de + *(.vectors) + .vectors 0x00000000 0x68 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + 0x00000000 __vectors + 0x00000000 __vector_default + *(.vectors) + *(.progmem.gcc*) + *(.progmem*) + 0x00000068 . = ALIGN (0x2) + 0x00000068 __trampolines_start = . + *(.trampolines) + .trampolines 0x00000068 0x0 linker stubs + *(.trampolines*) + 0x00000068 __trampolines_end = . + *(.jumptables) + *(.jumptables*) + *(.lowtext) + *(.lowtext*) + 0x00000068 __ctors_start = . + *(.ctors) + 0x00000068 __ctors_end = . + 0x00000068 __dtors_start = . + *(.dtors) + 0x00000068 __dtors_end = . + SORT(*)(.ctors) + SORT(*)(.dtors) + *(.init0) + .init0 0x00000068 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + 0x00000068 __init + *(.init0) + *(.init1) + *(.init1) + *(.init2) + .init2 0x00000068 0xc c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + *(.init2) + *(.init3) + *(.init3) + *(.init4) + .init4 0x00000074 0x16 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_copy_data.o) + 0x00000074 __do_copy_data + .init4 0x0000008a 0x10 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_clear_bss.o) + 0x0000008a __do_clear_bss + *(.init4) + *(.init5) + *(.init5) + *(.init6) + *(.init6) + *(.init7) + *(.init7) + *(.init8) + *(.init8) + *(.init9) + .init9 0x0000009a 0x8 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + *(.init9) + *(.text) + .text 0x000000a2 0x4 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + 0x000000a2 __vector_22 + 0x000000a2 __vector_1 + 0x000000a2 __vector_24 + 0x000000a2 __vector_12 + 0x000000a2 __bad_interrupt + 0x000000a2 __vector_6 + 0x000000a2 __vector_3 + 0x000000a2 __vector_23 + 0x000000a2 __vector_25 + 0x000000a2 __vector_11 + 0x000000a2 __vector_13 + 0x000000a2 __vector_17 + 0x000000a2 __vector_19 + 0x000000a2 __vector_7 + 0x000000a2 __vector_5 + 0x000000a2 __vector_4 + 0x000000a2 __vector_9 + 0x000000a2 __vector_2 + 0x000000a2 __vector_21 + 0x000000a2 __vector_15 + 0x000000a2 __vector_8 + 0x000000a2 __vector_14 + 0x000000a2 __vector_10 + 0x000000a2 __vector_18 + 0x000000a2 __vector_20 + 0x000000a6 . = ALIGN (0x2) + *(.text.*) + .text.main 0x000000a6 0x78 main.o + 0x000000a6 main + .text.timer_init + 0x0000011e 0x24 timer.o + 0x0000011e timer_init + .text.__vector_16 + 0x00000142 0x32 timer.o + 0x00000142 __vector_16 + .text.timer_silence_elapsed + 0x00000174 0x20 timer.o + 0x00000174 timer_silence_elapsed + .text.timer_silence_reset + 0x00000194 0x10 timer.o + 0x00000194 timer_silence_reset + .text.RS485_Initialize + 0x000001a4 0x1c rs485.o + 0x000001a4 RS485_Initialize + .text.RS485_Set_Baud_Rate + 0x000001c0 0xc0 rs485.o + 0x000001c0 RS485_Set_Baud_Rate + .text.RS485_Transmitter_Enable + 0x00000280 0xc rs485.o + 0x00000280 RS485_Transmitter_Enable + .text.RS485_ReceiveError + 0x0000028c 0x1e rs485.o + 0x0000028c RS485_ReceiveError + .text.RS485_DataAvailable + 0x000002aa 0x1a rs485.o + 0x000002aa RS485_DataAvailable + .text.RS485_Send_Data + 0x000002c4 0x34 rs485.o + 0x000002c4 RS485_Send_Data + .text.RS485_Turnaround_Delay + 0x000002f8 0x34 rs485.o + 0x000002f8 RS485_Turnaround_Delay + .text.dlmstp_send_pdu + 0x0000032c 0x46 dlmstp.o + 0x0000032c dlmstp_send_pdu + .text.dlmstp_get_my_address + 0x00000372 0x24 dlmstp.o + 0x00000372 dlmstp_get_my_address + .text.MSTP_Send_Frame + 0x00000396 0xc0 dlmstp.o + .text.dlmstp_receive + 0x00000456 0x3b2 dlmstp.o + 0x00000456 dlmstp_receive + .text.dlmstp_init + 0x00000808 0xa dlmstp.o + 0x00000808 dlmstp_init + .text.apdu_service_supported + 0x00000812 0x10 apdu.o + 0x00000812 apdu_service_supported + .text.apdu_decode_confirmed_service_request + 0x00000822 0xa8 apdu.o + 0x00000822 apdu_decode_confirmed_service_request + .text.apdu_handler + 0x000008ca 0x84 apdu.o + 0x000008ca apdu_handler + .text.CRC_Calc_Header + 0x0000094e 0x5a ../../src/crc.o + 0x0000094e CRC_Calc_Header + .text.CRC_Calc_Data + 0x000009a8 0x5c ../../src/crc.o + 0x000009a8 CRC_Calc_Data + .text.Encode_Property_APDU + 0x00000a04 0x62 h_rp.o + 0x00000a04 Encode_Property_APDU + .text.handler_read_property + 0x00000a66 0x126 h_rp.o + 0x00000a66 handler_read_property + .text.Device_Valid_Object_Instance_Number + 0x00000b8c 0x34 device.o + 0x00000b8c Device_Valid_Object_Instance_Number + .text.Device_Object_List_Identifier + 0x00000bc0 0x3a device.o + 0x00000bc0 Device_Object_List_Identifier + .text.Device_Encode_Property_APDU + 0x00000bfa 0x2d6 device.o + 0x00000bfa Device_Encode_Property_APDU + .text.npdu_handler + 0x00000ed0 0x7a ../../demo/handler/h_npdu.o + 0x00000ed0 npdu_handler + .text.handler_unrecognized_service + 0x00000f4a 0x6c ../../demo/handler/noserv.o + 0x00000f4a handler_unrecognized_service + .text.npdu_encode_npdu_data + 0x00000fb6 0x24 .\libbacnet.a(npdu.o) + 0x00000fb6 npdu_encode_npdu_data + .text.npdu_decode + 0x00000fda 0x1f2 .\libbacnet.a(npdu.o) + 0x00000fda npdu_decode + .text.npdu_encode_pdu + 0x000011cc 0x192 .\libbacnet.a(npdu.o) + 0x000011cc npdu_encode_pdu + .text.decode_max_segs + 0x0000135e 0x68 .\libbacnet.a(bacdcode.o) + 0x0000135e decode_max_segs + .text.decode_max_apdu + 0x000013c6 0x56 .\libbacnet.a(bacdcode.o) + 0x000013c6 decode_max_apdu + .text.encode_opening_tag + 0x0000141c 0x2c .\libbacnet.a(bacdcode.o) + 0x0000141c encode_opening_tag + .text.encode_closing_tag + 0x00001448 0x2c .\libbacnet.a(bacdcode.o) + 0x00001448 encode_closing_tag + .text.decode_tag_number + 0x00001474 0x36 .\libbacnet.a(bacdcode.o) + 0x00001474 decode_tag_number + .text.byte_reverse_bits + 0x000014aa 0x2e .\libbacnet.a(bacdcode.o) + .text.encode_bacnet_unsigned + 0x000014d8 0x50 .\libbacnet.a(bacdcode.o) + 0x000014d8 encode_bacnet_unsigned + .text.encode_bacnet_enumerated + 0x00001528 0x10 .\libbacnet.a(bacdcode.o) + 0x00001528 encode_bacnet_enumerated + .text.encode_bacnet_object_id + 0x00001538 0x3e .\libbacnet.a(bacdcode.o) + 0x00001538 encode_bacnet_object_id + .text.encode_tag + 0x00001576 0xa8 .\libbacnet.a(bacdcode.o) + 0x00001576 encode_tag + .text.encode_context_enumerated + 0x0000161e 0x50 .\libbacnet.a(bacdcode.o) + 0x0000161e encode_context_enumerated + .text.encode_application_enumerated + 0x0000166e 0x3c .\libbacnet.a(bacdcode.o) + 0x0000166e encode_application_enumerated + .text.encode_application_unsigned + 0x000016aa 0x3c .\libbacnet.a(bacdcode.o) + 0x000016aa encode_application_unsigned + .text.encode_context_unsigned + 0x000016e6 0x52 .\libbacnet.a(bacdcode.o) + 0x000016e6 encode_context_unsigned + .text.encode_application_object_id + 0x00001738 0x3c .\libbacnet.a(bacdcode.o) + 0x00001738 encode_application_object_id + .text.encode_context_object_id + 0x00001774 0x54 .\libbacnet.a(bacdcode.o) + 0x00001774 encode_context_object_id + .text.decode_unsigned + 0x000017c8 0xa4 .\libbacnet.a(bacdcode.o) + 0x000017c8 decode_unsigned + .text.decode_enumerated + 0x0000186c 0x3c .\libbacnet.a(bacdcode.o) + 0x0000186c decode_enumerated + .text.decode_object_id + 0x000018a8 0x66 .\libbacnet.a(bacdcode.o) + 0x000018a8 decode_object_id + .text.encode_bacnet_character_string + 0x0000190e 0x56 .\libbacnet.a(bacdcode.o) + 0x0000190e encode_bacnet_character_string + .text.encode_application_character_string + 0x00001964 0x60 .\libbacnet.a(bacdcode.o) + 0x00001964 encode_application_character_string + .text.encode_bitstring + 0x000019c4 0x82 .\libbacnet.a(bacdcode.o) + 0x000019c4 encode_bitstring + .text.encode_application_bitstring + 0x00001a46 0x4e .\libbacnet.a(bacdcode.o) + 0x00001a46 encode_application_bitstring + .text.decode_is_context_tag + 0x00001a94 0x46 .\libbacnet.a(bacdcode.o) + 0x00001a94 decode_is_context_tag + .text.decode_tag_number_and_value + 0x00001ada 0xfc .\libbacnet.a(bacdcode.o) + 0x00001ada decode_tag_number_and_value + .text.encode_unsigned16 + 0x00001bd6 0x10 .\libbacnet.a(bacint.o) + 0x00001bd6 encode_unsigned16 + .text.decode_unsigned16 + 0x00001be6 0x30 .\libbacnet.a(bacint.o) + 0x00001be6 decode_unsigned16 + .text.encode_unsigned24 + 0x00001c16 0xe .\libbacnet.a(bacint.o) + 0x00001c16 encode_unsigned24 + .text.decode_unsigned24 + 0x00001c24 0x64 .\libbacnet.a(bacint.o) + 0x00001c24 decode_unsigned24 + .text.encode_unsigned32 + 0x00001c88 0x18 .\libbacnet.a(bacint.o) + 0x00001c88 encode_unsigned32 + .text.decode_unsigned32 + 0x00001ca0 0x84 .\libbacnet.a(bacint.o) + 0x00001ca0 decode_unsigned32 + .text.bitstring_init + 0x00001d24 0x1a .\libbacnet.a(bacstr.o) + 0x00001d24 bitstring_init + .text.bitstring_set_bit + 0x00001d3e 0x66 .\libbacnet.a(bacstr.o) + 0x00001d3e bitstring_set_bit + .text.bitstring_bits_used + 0x00001da4 0x8 .\libbacnet.a(bacstr.o) + 0x00001da4 bitstring_bits_used + .text.bitstring_bytes_used + 0x00001dac 0x1c .\libbacnet.a(bacstr.o) + 0x00001dac bitstring_bytes_used + .text.bitstring_octet + 0x00001dc8 0x18 .\libbacnet.a(bacstr.o) + 0x00001dc8 bitstring_octet + .text.characterstring_init + 0x00001de0 0x8a .\libbacnet.a(bacstr.o) + 0x00001de0 characterstring_init + .text.characterstring_value + 0x00001e6a 0xe .\libbacnet.a(bacstr.o) + 0x00001e6a characterstring_value + .text.characterstring_length + 0x00001e78 0x12 .\libbacnet.a(bacstr.o) + 0x00001e78 characterstring_length + .text.characterstring_encoding + 0x00001e8a 0x10 .\libbacnet.a(bacstr.o) + 0x00001e8a characterstring_encoding + .text.characterstring_init_ansi + 0x00001e9a 0x2a .\libbacnet.a(bacstr.o) + 0x00001e9a characterstring_init_ansi + .text.rp_decode_service_request + 0x00001ec4 0x12a .\libbacnet.a(rp.o) + 0x00001ec4 rp_decode_service_request + .text.rp_ack_encode_apdu_init + 0x00001fee 0xa2 .\libbacnet.a(rp.o) + 0x00001fee rp_ack_encode_apdu_init + .text.rp_ack_encode_apdu_object_property_end + 0x00002090 0x12 .\libbacnet.a(rp.o) + 0x00002090 rp_ack_encode_apdu_object_property_end + .text.abort_encode_apdu + 0x000020a2 0x22 .\libbacnet.a(abort.o) + 0x000020a2 abort_encode_apdu + .text.reject_encode_apdu + 0x000020c4 0x1a .\libbacnet.a(reject.o) + 0x000020c4 reject_encode_apdu + .text.bacerror_encode_apdu + 0x000020de 0x4c .\libbacnet.a(bacerror.o) + 0x000020de bacerror_encode_apdu + .text.libgcc 0x0000212a 0x44 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_udivmodsi4.o) + 0x0000212a __udivmodsi4 + .text.libgcc 0x0000216e 0x38 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_prologue.o) + 0x0000216e __prologue_saves__ + .text.libgcc 0x000021a6 0x36 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_epilogue.o) + 0x000021a6 __epilogue_restores__ + 0x000021dc . = ALIGN (0x2) + *(.fini9) + .fini9 0x000021dc 0x0 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_exit.o) + 0x000021dc exit + 0x000021dc _exit + *(.fini9) + *(.fini8) + *(.fini8) + *(.fini7) + *(.fini7) + *(.fini6) + *(.fini6) + *(.fini5) + *(.fini5) + *(.fini4) + *(.fini4) + *(.fini3) + *(.fini3) + *(.fini2) + *(.fini2) + *(.fini1) + *(.fini1) + *(.fini0) + .fini0 0x000021dc 0x2 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/avr5\libgcc.a(_exit.o) + *(.fini0) + 0x000021de _etext = . + +.data 0x00800100 0x40 load address 0x000021de + 0x00800100 PROVIDE (__data_start, .) + *(.data) + .data 0x00800100 0x39 device.o + *(.data*) + .data.Object_Instance_Number + 0x00800139 0x4 device.o + *(.rodata) + *(.rodata*) + .rodata.Object_Name + 0x0080013d 0x2 device.o + *(.gnu.linkonce.d*) + 0x00800140 . = ALIGN (0x2) + *fill* 0x0080013f 0x1 00 + 0x00800140 _edata = . + 0x00800140 PROVIDE (__data_end, .) + +.bss 0x00800140 0xbe load address 0x0000221e + 0x00800140 PROVIDE (__bss_start, .) + *(.bss) + *(.bss*) + .bss.PDUBuffer + 0x00800140 0x56 main.o + .bss.Timer_Silence + 0x00800196 0x2 timer.o + .bss.RS485_Baud + 0x00800198 0x4 rs485.o + .bss.Index.3067 + 0x0080019c 0x1 dlmstp.o + .bss.HeaderCRC.3066 + 0x0080019d 0x1 dlmstp.o + .bss.DataCRC.3065 + 0x0080019e 0x2 dlmstp.o + .bss.Receive_State + 0x008001a0 0x2 dlmstp.o + .bss.MSTP_Flag + 0x008001a2 0x1 dlmstp.o + .bss.DataLength + 0x008001a3 0x2 dlmstp.o + .bss.DestinationAddress + 0x008001a5 0x1 dlmstp.o + .bss.FrameType + 0x008001a6 0x1 dlmstp.o + .bss.InputBuffer + 0x008001a7 0x2 dlmstp.o + .bss.InputBufferSize + 0x008001a9 0x2 dlmstp.o + .bss.SourceAddress + 0x008001ab 0x1 dlmstp.o + .bss.This_Station + 0x008001ac 0x1 dlmstp.o + .bss.TransmitPacket + 0x008001ad 0x2 dlmstp.o + .bss.TransmitPacketLen + 0x008001af 0x2 dlmstp.o + .bss.TransmitPacketDest + 0x008001b1 0x1 dlmstp.o + .bss.Handler_Transmit_Buffer + 0x008001b2 0x4c ../../demo/handler/txbuf.o + 0x008001b2 Handler_Transmit_Buffer + *(COMMON) + 0x008001fe PROVIDE (__bss_end, .) + 0x000021de __data_load_start = LOADADDR (.data) + 0x0000221e __data_load_end = (__data_load_start + SIZEOF (.data)) + +.noinit 0x008001fe 0x0 + 0x008001fe PROVIDE (__noinit_start, .) + *(.noinit*) + 0x008001fe PROVIDE (__noinit_end, .) + 0x008001fe _end = . + 0x008001fe PROVIDE (__heap_start, .) + +.eeprom 0x00810000 0x0 + *(.eeprom*) + 0x00810000 __eeprom_end = . + +.fuse + *(.fuse) + *(.lfuse) + *(.hfuse) + *(.efuse) + +.lock + *(.lock*) + +.signature + *(.signature*) + +.stab 0x00000000 0x378 + *(.stab) + .stab 0x00000000 0x378 c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + +.stabstr 0x00000000 0x5f + *(.stabstr) + .stabstr 0x00000000 0x5f c:/winavr-20071221rc1/bin/../lib/gcc/avr/4.2.2/../../../../avr/lib/avr5/crtm168.o + +.stab.excl + *(.stab.excl) + +.stab.exclstr + *(.stab.exclstr) + +.stab.index + *(.stab.index) + +.stab.indexstr + *(.stab.indexstr) + +.comment + *(.comment) + +.debug + *(.debug) + +.line + *(.line) + +.debug_srcinfo + *(.debug_srcinfo) + +.debug_sfnames + *(.debug_sfnames) + +.debug_aranges 0x00000000 0x798 + *(.debug_aranges) + .debug_aranges + 0x00000000 0x30 main.o + .debug_aranges + 0x00000030 0x40 timer.o + .debug_aranges + 0x00000070 0x60 rs485.o + .debug_aranges + 0x000000d0 0x70 dlmstp.o + .debug_aranges + 0x00000140 0x38 apdu.o + .debug_aranges + 0x00000178 0x30 ../../src/crc.o + .debug_aranges + 0x000001a8 0x30 h_rp.o + .debug_aranges + 0x000001d8 0x60 device.o + .debug_aranges + 0x00000238 0x28 ../../demo/handler/h_npdu.o + .debug_aranges + 0x00000260 0x28 ../../demo/handler/noserv.o + .debug_aranges + 0x00000288 0x40 .\libbacnet.a(npdu.o) + .debug_aranges + 0x000002c8 0x210 .\libbacnet.a(bacdcode.o) + .debug_aranges + 0x000004d8 0x90 .\libbacnet.a(bacint.o) + .debug_aranges + 0x00000568 0x40 .\libbacnet.a(bacreal.o) + .debug_aranges + 0x000005a8 0x108 .\libbacnet.a(bacstr.o) + .debug_aranges + 0x000006b0 0x50 .\libbacnet.a(rp.o) + .debug_aranges + 0x00000700 0x30 .\libbacnet.a(abort.o) + .debug_aranges + 0x00000730 0x30 .\libbacnet.a(reject.o) + .debug_aranges + 0x00000760 0x38 .\libbacnet.a(bacerror.o) + +.debug_pubnames + 0x00000000 0x11f6 + *(.debug_pubnames) + .debug_pubnames + 0x00000000 0x4c main.o + .debug_pubnames + 0x0000004c 0x63 timer.o + .debug_pubnames + 0x000000af 0xd2 rs485.o + .debug_pubnames + 0x00000181 0xe8 dlmstp.o + .debug_pubnames + 0x00000269 0x68 apdu.o + .debug_pubnames + 0x000002d1 0x38 ../../src/crc.o + .debug_pubnames + 0x00000309 0x45 h_rp.o + .debug_pubnames + 0x0000034e 0x10e device.o + .debug_pubnames + 0x0000045c 0x2e ../../demo/handler/txbuf.o + .debug_pubnames + 0x0000048a 0x23 ../../demo/handler/h_npdu.o + .debug_pubnames + 0x000004ad 0x33 ../../demo/handler/noserv.o + .debug_pubnames + 0x000004e0 0x63 .\libbacnet.a(npdu.o) + .debug_pubnames + 0x00000543 0x66b .\libbacnet.a(bacdcode.o) + .debug_pubnames + 0x00000bae 0x134 .\libbacnet.a(bacint.o) + .debug_pubnames + 0x00000ce2 0x64 .\libbacnet.a(bacreal.o) + .debug_pubnames + 0x00000d46 0x2e1 .\libbacnet.a(bacstr.o) + .debug_pubnames + 0x00001027 0xc3 .\libbacnet.a(rp.o) + .debug_pubnames + 0x000010ea 0x49 .\libbacnet.a(abort.o) + .debug_pubnames + 0x00001133 0x4b .\libbacnet.a(reject.o) + .debug_pubnames + 0x0000117e 0x78 .\libbacnet.a(bacerror.o) + +.debug_info 0x00000000 0x818f + *(.debug_info) + .debug_info 0x00000000 0x19e main.o + .debug_info 0x0000019e 0x121 timer.o + .debug_info 0x000002bf 0x208 rs485.o + .debug_info 0x000004c7 0x6fb dlmstp.o + .debug_info 0x00000bc2 0x4f5 apdu.o + .debug_info 0x000010b7 0x100 ../../src/crc.o + .debug_info 0x000011b7 0x11ed h_rp.o + .debug_info 0x000023a4 0x117a device.o + .debug_info 0x0000351e 0x95 ../../demo/handler/txbuf.o + .debug_info 0x000035b3 0x28e ../../demo/handler/h_npdu.o + .debug_info 0x00003841 0x39b ../../demo/handler/noserv.o + .debug_info 0x00003bdc 0x39e .\libbacnet.a(npdu.o) + .debug_info 0x00003f7a 0x1858 .\libbacnet.a(bacdcode.o) + .debug_info 0x000057d2 0x415 .\libbacnet.a(bacint.o) + .debug_info 0x00005be7 0x274 .\libbacnet.a(bacreal.o) + .debug_info 0x00005e5b 0xb9d .\libbacnet.a(bacstr.o) + .debug_info 0x000069f8 0xe78 .\libbacnet.a(rp.o) + .debug_info 0x00007870 0x17f .\libbacnet.a(abort.o) + .debug_info 0x000079ef 0x16b .\libbacnet.a(reject.o) + .debug_info 0x00007b5a 0x635 .\libbacnet.a(bacerror.o) + *(.gnu.linkonce.wi.*) + +.debug_abbrev 0x00000000 0x17a5 + *(.debug_abbrev) + .debug_abbrev 0x00000000 0x119 main.o + .debug_abbrev 0x00000119 0xbb timer.o + .debug_abbrev 0x000001d4 0x10d rs485.o + .debug_abbrev 0x000002e1 0x2b1 dlmstp.o + .debug_abbrev 0x00000592 0x14b apdu.o + .debug_abbrev 0x000006dd 0x92 ../../src/crc.o + .debug_abbrev 0x0000076f 0x15c h_rp.o + .debug_abbrev 0x000008cb 0x1a5 device.o + .debug_abbrev 0x00000a70 0x63 ../../demo/handler/txbuf.o + .debug_abbrev 0x00000ad3 0x124 ../../demo/handler/h_npdu.o + .debug_abbrev 0x00000bf7 0x118 ../../demo/handler/noserv.o + .debug_abbrev 0x00000d0f 0x148 .\libbacnet.a(npdu.o) + .debug_abbrev 0x00000e57 0x20f .\libbacnet.a(bacdcode.o) + .debug_abbrev 0x00001066 0x8c .\libbacnet.a(bacint.o) + .debug_abbrev 0x000010f2 0xdf .\libbacnet.a(bacreal.o) + .debug_abbrev 0x000011d1 0x253 .\libbacnet.a(bacstr.o) + .debug_abbrev 0x00001424 0x10e .\libbacnet.a(rp.o) + .debug_abbrev 0x00001532 0xc7 .\libbacnet.a(abort.o) + .debug_abbrev 0x000015f9 0xc7 .\libbacnet.a(reject.o) + .debug_abbrev 0x000016c0 0xe5 .\libbacnet.a(bacerror.o) + +.debug_line 0x00000000 0x3cb7 + *(.debug_line) + .debug_line 0x00000000 0x137 main.o + .debug_line 0x00000137 0x138 timer.o + .debug_line 0x0000026f 0x1eb rs485.o + .debug_line 0x0000045a 0x633 dlmstp.o + .debug_line 0x00000a8d 0x18e apdu.o + .debug_line 0x00000c1b 0xb4 ../../src/crc.o + .debug_line 0x00000ccf 0x189 h_rp.o + .debug_line 0x00000e58 0x30b device.o + .debug_line 0x00001163 0x6b ../../demo/handler/txbuf.o + .debug_line 0x000011ce 0xf2 ../../demo/handler/h_npdu.o + .debug_line 0x000012c0 0xec ../../demo/handler/noserv.o + .debug_line 0x000013ac 0x42d .\libbacnet.a(npdu.o) + .debug_line 0x000017d9 0x10a6 .\libbacnet.a(bacdcode.o) + .debug_line 0x0000287f 0x37f .\libbacnet.a(bacint.o) + .debug_line 0x00002bfe 0x184 .\libbacnet.a(bacreal.o) + .debug_line 0x00002d82 0x7b6 .\libbacnet.a(bacstr.o) + .debug_line 0x00003538 0x3c6 .\libbacnet.a(rp.o) + .debug_line 0x000038fe 0x111 .\libbacnet.a(abort.o) + .debug_line 0x00003a0f 0x102 .\libbacnet.a(reject.o) + .debug_line 0x00003b11 0x1a6 .\libbacnet.a(bacerror.o) + +.debug_frame 0x00000000 0xba0 + *(.debug_frame) + .debug_frame 0x00000000 0x30 main.o + .debug_frame 0x00000030 0x50 timer.o + .debug_frame 0x00000080 0x90 rs485.o + .debug_frame 0x00000110 0xb0 dlmstp.o + .debug_frame 0x000001c0 0x40 apdu.o + .debug_frame 0x00000200 0x30 ../../src/crc.o + .debug_frame 0x00000230 0x30 h_rp.o + .debug_frame 0x00000260 0x90 device.o + .debug_frame 0x000002f0 0x20 ../../demo/handler/h_npdu.o + .debug_frame 0x00000310 0x20 ../../demo/handler/noserv.o + .debug_frame 0x00000330 0x50 .\libbacnet.a(npdu.o) + .debug_frame 0x00000380 0x3f0 .\libbacnet.a(bacdcode.o) + .debug_frame 0x00000770 0xf0 .\libbacnet.a(bacint.o) + .debug_frame 0x00000860 0x50 .\libbacnet.a(bacreal.o) + .debug_frame 0x000008b0 0x1e0 .\libbacnet.a(bacstr.o) + .debug_frame 0x00000a90 0x70 .\libbacnet.a(rp.o) + .debug_frame 0x00000b00 0x30 .\libbacnet.a(abort.o) + .debug_frame 0x00000b30 0x30 .\libbacnet.a(reject.o) + .debug_frame 0x00000b60 0x40 .\libbacnet.a(bacerror.o) + +.debug_str 0x00000000 0x57cf + *(.debug_str) + .debug_str 0x00000000 0x113 main.o + 0x13e (size before relaxing) + .debug_str 0x00000113 0x5c timer.o + 0x123 (size before relaxing) + .debug_str 0x0000016f 0xf7 rs485.o + 0x1d6 (size before relaxing) + .debug_str 0x00000266 0x627 dlmstp.o + 0x743 (size before relaxing) + .debug_str 0x0000088d 0xbc6 apdu.o + 0xd16 (size before relaxing) + .debug_str 0x00001453 0x48 ../../src/crc.o + 0xfc (size before relaxing) + .debug_str 0x0000149b 0x2e28 h_rp.o + 0x37a1 (size before relaxing) + .debug_str 0x000042c3 0x295 device.o + 0x35f8 (size before relaxing) + .debug_str 0x00004558 0x1b ../../demo/handler/txbuf.o + 0xe4 (size before relaxing) + .debug_str 0x00004573 0x49 ../../demo/handler/h_npdu.o + 0x436 (size before relaxing) + .debug_str 0x000045bc 0x1e3 ../../demo/handler/noserv.o + 0x6d6 (size before relaxing) + .debug_str 0x0000479f 0x7e .\libbacnet.a(npdu.o) + 0x463 (size before relaxing) + .debug_str 0x0000481d 0x934 .\libbacnet.a(bacdcode.o) + 0xbfc (size before relaxing) + .debug_str 0x00005151 0xfd .\libbacnet.a(bacint.o) + 0x1dc (size before relaxing) + .debug_str 0x0000524e 0x6e .\libbacnet.a(bacreal.o) + 0x143 (size before relaxing) + .debug_str 0x000052bc 0x325 .\libbacnet.a(bacstr.o) + 0x4dc (size before relaxing) + .debug_str 0x000055e1 0xca .\libbacnet.a(rp.o) + 0x2715 (size before relaxing) + .debug_str 0x000056ab 0x55 .\libbacnet.a(abort.o) + 0x1d7 (size before relaxing) + .debug_str 0x00005700 0x52 .\libbacnet.a(reject.o) + 0x1ce (size before relaxing) + .debug_str 0x00005752 0x7d .\libbacnet.a(bacerror.o) + 0x1521 (size before relaxing) + +.debug_loc 0x00000000 0x58bf + *(.debug_loc) + .debug_loc 0x00000000 0x38 main.o + .debug_loc 0x00000038 0x2b timer.o + .debug_loc 0x00000063 0x11f rs485.o + .debug_loc 0x00000182 0x583 dlmstp.o + .debug_loc 0x00000705 0x262 apdu.o + .debug_loc 0x00000967 0x141 ../../src/crc.o + .debug_loc 0x00000aa8 0x1f0 h_rp.o + .debug_loc 0x00000c98 0x540 device.o + .debug_loc 0x000011d8 0xa0 ../../demo/handler/h_npdu.o + .debug_loc 0x00001278 0x80 ../../demo/handler/noserv.o + .debug_loc 0x000012f8 0x416 .\libbacnet.a(npdu.o) + .debug_loc 0x0000170e 0x2257 .\libbacnet.a(bacdcode.o) + .debug_loc 0x00003965 0x330 .\libbacnet.a(bacint.o) + .debug_loc 0x00003c95 0x6e .\libbacnet.a(bacreal.o) + .debug_loc 0x00003d03 0x1078 .\libbacnet.a(bacstr.o) + .debug_loc 0x00004d7b 0x5b5 .\libbacnet.a(rp.o) + .debug_loc 0x00005330 0x128 .\libbacnet.a(abort.o) + .debug_loc 0x00005458 0x108 .\libbacnet.a(reject.o) + .debug_loc 0x00005560 0x35f .\libbacnet.a(bacerror.o) + +.debug_macinfo + *(.debug_macinfo) +OUTPUT(bacnet.elf elf32-avr) +LOAD linker stubs + +.debug_ranges 0x00000000 0xb0 + .debug_ranges 0x00000000 0xb0 dlmstp.o diff --git a/bacnet-stack/ports/atmega8/bv.c b/bacnet-stack/ports/atmega8/bv.c new file mode 100644 index 00000000..ce03d362 --- /dev/null +++ b/bacnet-stack/ports/atmega8/bv.c @@ -0,0 +1,302 @@ +/************************************************************************** +* +* 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. +* +*********************************************************************/ + +/* Binary Value Objects - customize for your use */ + +#include +#include +#include +#include "hardware.h" +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "config.h" /* the custom stuff */ +#include "wp.h" +#include "bv.h" + +#if (MAX_BINARY_VALUES > 10) +#error Modify the Binary_Value_Name to handle multiple digits +#endif + +static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES]; + +/* we simply have 0-n object instances. */ +bool Binary_Value_Valid_Instance( + uint32_t object_instance) +{ + if (object_instance < MAX_BINARY_VALUES) + return true; + + return false; +} + +/* we simply have 0-n object instances. */ +unsigned Binary_Value_Count( + void) +{ + return MAX_BINARY_VALUES; +} + +/* we simply have 0-n object instances. */ +uint32_t Binary_Value_Index_To_Instance( + unsigned index) +{ + return index; +} + +/* we simply have 0-n object instances. */ +unsigned Binary_Value_Instance_To_Index( + uint32_t object_instance) +{ + unsigned index = MAX_BINARY_VALUES; + + if (object_instance < MAX_BINARY_VALUES) + index = object_instance; + + return index; +} + +static BACNET_BINARY_PV Binary_Value_Present_Value( + uint32_t object_instance) +{ + BACNET_BINARY_PV value = BINARY_INACTIVE; + + if (object_instance < MAX_BINARY_VALUES) { + value = Present_Value[object_instance]; + } + + return value; +} + +/* note: the object name must be unique within this device */ +char *Binary_Value_Name( + uint32_t object_instance) +{ + static char text_string[5] = "BV-0"; /* okay for single thread */ + + if (object_instance < MAX_BINARY_VALUES) { + text_string[3] = '0' + (uint8_t) object_instance; + return text_string; + } + + return NULL; +} + +/* return apdu len, or -1 on error */ +int Binary_Value_Encode_Property_APDU( + uint8_t * apdu, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + BACNET_BINARY_PV present_value = BINARY_INACTIVE; + BACNET_POLARITY polarity = POLARITY_NORMAL; + + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = + encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE, + object_instance); + break; + /* note: Name and Description don't have to be the same. + You could make Description writable and different */ + case PROP_OBJECT_NAME: + characterstring_init_ansi(&char_string, + Binary_Value_Name(object_instance)); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = + encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE); + break; + case PROP_PRESENT_VALUE: + present_value = Binary_Value_Present_Value(object_instance); + apdu_len = encode_application_enumerated(&apdu[0], present_value); + break; + case PROP_STATUS_FLAGS: + /* note: see the details in the standard on how to use these */ + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + case PROP_EVENT_STATE: + /* note: see the details in the standard on how to use this */ + apdu_len = + encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL); + break; + case PROP_OUT_OF_SERVICE: + apdu_len = encode_application_boolean(&apdu[0], false); + break; + case PROP_POLARITY: + /* FIXME: figure out the polarity */ + apdu_len = encode_application_enumerated(&apdu[0], polarity); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + +/* returns true if successful */ +bool Binary_Value_Write_Property( + BACNET_WRITE_PROPERTY_DATA * wp_data, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + bool status = false; /* return value */ + unsigned int object_index = 0; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + + if (!Binary_Value_Valid_Instance(wp_data->object_instance)) { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + return false; + } + /* decode the some of the request */ + len = + bacapp_decode_application_data(wp_data->application_data, + wp_data->application_data_len, &value); + /* FIXME: len < application_data_len: more data? */ + /* FIXME: len == 0: unable to decode? */ + switch (wp_data->object_property) { + case PROP_PRESENT_VALUE: + if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) { + if ((value.type.Enumerated == BINARY_ACTIVE) || + (value.type.Enumerated == BINARY_INACTIVE)) { + object_index = + Binary_Value_Instance_To_Index(wp_data-> + object_instance); + /* NOTE: this Binary value has no priority array */ + Present_Value[object_index] = + (BACNET_BINARY_PV) value.type.Enumerated; + /* Note: you could set the physical output here if we + are the highest priority. + However, if Out of Service is TRUE, then don't set the + physical output. */ + if (Present_Value[0] == BINARY_ACTIVE) { + LED_GREEN_ON(); + } else { + LED_GREEN_OFF(); + } + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; +#if 0 + case PROP_OUT_OF_SERVICE: + if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { + object_index = + Binary_Value_Instance_To_Index(wp_data->object_instance); + Binary_Value_Out_Of_Service[object_index] = value.type.Boolean; + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; +#endif + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } + + return status; +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testBinary_Value( + Test * pTest) +{ + uint8_t apdu[MAX_APDU] = { 0 }; + int len = 0; + uint32_t len_value = 0; + uint8_t tag_number = 0; + BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_VALUE; + uint32_t decoded_instance = 0; + uint32_t instance = 123; + BACNET_ERROR_CLASS error_class; + BACNET_ERROR_CODE error_code; + + + len = + Binary_Value_Encode_Property_APDU(&apdu[0], instance, + PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code); + ct_test(pTest, len != 0); + len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value); + ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID); + len = + decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance); + ct_test(pTest, decoded_type == OBJECT_BINARY_VALUE); + ct_test(pTest, decoded_instance == instance); + + return; +} + +#ifdef TEST_BINARY_VALUE +int main( + void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet Binary_Value", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testBinary_Value); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_BINARY_VALUE */ +#endif /* TEST */ diff --git a/bacnet-stack/ports/atmega8/device.c b/bacnet-stack/ports/atmega8/device.c new file mode 100644 index 00000000..28246d85 --- /dev/null +++ b/bacnet-stack/ports/atmega8/device.c @@ -0,0 +1,331 @@ +/************************************************************************** +* +* Copyright (C) 2007 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 "bacdef.h" +#include "bacdcode.h" +#include "bacstr.h" +#include "bacenum.h" +#include "apdu.h" +#include "dcc.h" +#include "dlmstp.h" +#include "rs485.h" +#include "version.h" +/* objects */ +#include "device.h" +#include "av.h" + +/* note: you really only need to define variables for + properties that are writable or that may change. + The properties that are constant can be hard coded + into the read-property encoding. */ +static uint32_t Object_Instance_Number = 260001; +static char *Object_Name = "My Device"; +static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; + +void Device_Init( + void) +{ + /* Reinitialize_State = REINITIALIZED_STATE_IDLE; */ + /* dcc_set_status_duration(COMMUNICATION_ENABLE, 0); */ + /* FIXME: Get the data from the eeprom */ + /* I2C_Read_Block(EEPROM_DEVICE_ADDRESS, + (char *)&Object_Instance_Number, + sizeof(Object_Instance_Number), + EEPROM_BACNET_ID_ADDR); */ +} + +/* methods to manipulate the data */ +uint32_t Device_Object_Instance_Number( + void) +{ + return Object_Instance_Number; +} + +bool Device_Set_Object_Instance_Number( + uint32_t object_id) +{ + bool status = true; /* return value */ + + if (object_id <= BACNET_MAX_INSTANCE) { + Object_Instance_Number = object_id; + /* FIXME: Write the data to the eeprom */ + /* I2C_Write_Block( + EEPROM_DEVICE_ADDRESS, + (char *)&Object_Instance_Number, + sizeof(Object_Instance_Number), + EEPROM_BACNET_ID_ADDR); */ + } else + status = false; + + return status; +} + +bool Device_Valid_Object_Instance_Number( + uint32_t object_id) +{ + /* BACnet allows for a wildcard instance number */ + return ((Object_Instance_Number == object_id) || + (object_id == BACNET_MAX_INSTANCE)); +} + +uint16_t Device_Vendor_Identifier( + void) +{ + return BACNET_VENDOR_ID; +} + +unsigned Device_Object_List_Count( + void) +{ + unsigned count = 1; /* at least 1 for device object */ + +#if MAX_ANALOG_VALUES + /* FIXME: add objects as needed */ + count += Analog_Value_Count(); +#endif +#if MAX_BINARY_VALUES + /* FIXME: add objects as needed */ + count += Binary_Value_Count(); +#endif + + return count; +} + +bool Device_Object_List_Identifier( + unsigned array_index, + int *object_type, + uint32_t * instance) +{ + bool status = false; + unsigned object_index = 0; + unsigned object_count = 0; + + /* device object */ + if (array_index == 1) { + *object_type = OBJECT_DEVICE; + *instance = Object_Instance_Number; + status = true; + } + /* normalize the index since + we know it is not the previous objects */ + /* array index starts at 1 */ + object_index = array_index - 1; + /* 1 for the device object */ + object_count = 1; + /* FIXME: add objects as needed */ +#if MAX_ANALOG_VALUES + /* analog value objects */ + if (!status) { + /* array index starts at 1, and 1 for the device object */ + object_index -= object_count; + object_count = Analog_Value_Count(); + if (object_index < object_count) { + *object_type = OBJECT_ANALOG_VALUE; + *instance = Analog_Value_Index_To_Instance(object_index); + status = true; + } + } +#endif +#if MAX_BINARY_VALUES + /* binary value objects */ + if (!status) { + object_index -= object_count; + object_count = Binary_Value_Count(); + /* is it a valid index for this object? */ + if (object_index < object_count) { + *object_type = OBJECT_BINARY_VALUE; + *instance = Binary_Value_Index_To_Instance(object_index); + status = true; + } + } +#endif + + return status; +} + +/* return the length of the apdu encoded or -1 for error */ +int Device_Encode_Property_APDU( + uint8_t * apdu, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + int apdu_len = 0; /* return value */ + int len = 0; /* apdu len intermediate value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + unsigned i = 0; + int object_type = 0; + uint32_t instance = 0; + unsigned count = 0; + + /* FIXME: change the hardcoded names to suit your application */ + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = + encode_application_object_id(&apdu[0], OBJECT_DEVICE, + Object_Instance_Number); + break; + case PROP_OBJECT_NAME: + characterstring_init_ansi(&char_string, Object_Name); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE); + break; + case PROP_SYSTEM_STATUS: + apdu_len = encode_application_enumerated(&apdu[0], System_Status); + break; + case PROP_VENDOR_NAME: + characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_VENDOR_IDENTIFIER: + apdu_len = + encode_application_unsigned(&apdu[0], + Device_Vendor_Identifier()); + break; + case PROP_MODEL_NAME: + characterstring_init_ansi(&char_string, "GNU Demo"); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_FIRMWARE_REVISION: + characterstring_init_ansi(&char_string, BACNET_VERSION_TEXT); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_APPLICATION_SOFTWARE_VERSION: + characterstring_init_ansi(&char_string, "1.0"); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_PROTOCOL_VERSION: + apdu_len = encode_application_unsigned(&apdu[0], 1); + break; + case PROP_PROTOCOL_REVISION: + apdu_len = encode_application_unsigned(&apdu[0], 5); + break; + case PROP_PROTOCOL_SERVICES_SUPPORTED: + /* Note: list of services that are executed, not initiated. */ + bitstring_init(&bit_string); + for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) { + /* automatic lookup based on handlers set */ + bitstring_set_bit(&bit_string, (uint8_t) i, + apdu_service_supported((BACNET_SERVICES_SUPPORTED) i)); + } + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: + /* Note: this is the list of objects that can be in this device, + not a list of objects that this device can access */ + bitstring_init(&bit_string); + /* must have the bit string as big as it can be */ + for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { + /* initialize all the object types to not-supported */ + bitstring_set_bit(&bit_string, (uint8_t) i, false); + } + /* FIXME: indicate the objects that YOU support */ + bitstring_set_bit(&bit_string, OBJECT_DEVICE, true); +#if MAX_ANALOG_VALUES + bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true); +#endif +#if MAX_BINARY_VALUES + bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true); +#endif + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + case PROP_OBJECT_LIST: + count = Device_Object_List_Count(); + /* Array element zero is the number of objects in the list */ + if (array_index == 0) + apdu_len = encode_application_unsigned(&apdu[0], count); + /* if no index was specified, then try to encode the entire list */ + /* into one packet. Note that more than likely you will have */ + /* to return an error if the number of encoded objects exceeds */ + /* your maximum APDU size. */ + else if (array_index == BACNET_ARRAY_ALL) { + for (i = 1; i <= count; i++) { + Device_Object_List_Identifier(i, &object_type, &instance); + len = + encode_application_object_id(&apdu[apdu_len], + object_type, instance); + apdu_len += len; + /* assume next one is the same size as this one */ + /* can we all fit into the APDU? */ + if ((apdu_len + len) >= MAX_APDU) { + *error_class = ERROR_CLASS_SERVICES; + *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; + apdu_len = -1; + break; + } + } + } else { + if (Device_Object_List_Identifier(array_index, &object_type, + &instance)) + apdu_len = + encode_application_object_id(&apdu[0], object_type, + instance); + else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = -1; + } + } + break; + case PROP_MAX_APDU_LENGTH_ACCEPTED: + apdu_len = encode_application_unsigned(&apdu[0], MAX_APDU); + break; + case PROP_SEGMENTATION_SUPPORTED: + apdu_len = + encode_application_enumerated(&apdu[0], SEGMENTATION_NONE); + break; + case PROP_APDU_TIMEOUT: + apdu_len = encode_application_unsigned(&apdu[0], 60000); + break; + case PROP_NUMBER_OF_APDU_RETRIES: + apdu_len = encode_application_unsigned(&apdu[0], 0); + break; + case PROP_DEVICE_ADDRESS_BINDING: + /* FIXME: encode the list here, if it exists */ + break; + case PROP_DATABASE_REVISION: + apdu_len = encode_application_unsigned(&apdu[0], 0); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + diff --git a/bacnet-stack/ports/atmega8/dlmstp.c b/bacnet-stack/ports/atmega8/dlmstp.c new file mode 100644 index 00000000..c3a19f62 --- /dev/null +++ b/bacnet-stack/ports/atmega8/dlmstp.c @@ -0,0 +1,765 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2008 Steve Karg + + 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####*/ +#include +#include +#include +#include +#include "bacdef.h" +#include "dlmstp.h" +#include "rs485.h" +#include "crc.h" +#include "npdu.h" +#include "bits.h" +#include "bacaddr.h" +#include "txbuf.h" + +/* This file has been customized for use with small microprocessors */ +/* Assumptions: + Only one slave node MS/TP datalink layer +*/ +#include "hardware.h" +#include "timer.h" + +/* The value 255 is used to denote broadcast when used as a */ +/* destination address but is not allowed as a value for a station. */ +/* Station addresses for master nodes can be 0-127. */ +/* Station addresses for slave nodes can be 127-254. */ +#define MSTP_BROADCAST_ADDRESS 255 + +/* MS/TP Frame Type */ +/* Frame Types 8 through 127 are reserved by ASHRAE. */ +#define FRAME_TYPE_TOKEN 0 +#define FRAME_TYPE_POLL_FOR_MASTER 1 +#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2 +#define FRAME_TYPE_TEST_REQUEST 3 +#define FRAME_TYPE_TEST_RESPONSE 4 +#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5 +#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6 +#define FRAME_TYPE_REPLY_POSTPONED 7 +/* Frame Types 128 through 255: Proprietary Frames */ +/* These frames are available to vendors as proprietary (non-BACnet) frames. */ +/* The first two octets of the Data field shall specify the unique vendor */ +/* identification code, most significant octet first, for the type of */ +/* vendor-proprietary frame to be conveyed. The length of the data portion */ +/* of a Proprietary frame shall be in the range of 2 to 501 octets. */ +#define FRAME_TYPE_PROPRIETARY_MIN 128 +#define FRAME_TYPE_PROPRIETARY_MAX 255 + +/* receive FSM states */ +typedef enum { + MSTP_RECEIVE_STATE_IDLE = 0, + MSTP_RECEIVE_STATE_PREAMBLE = 1, + MSTP_RECEIVE_STATE_HEADER = 2, + MSTP_RECEIVE_STATE_DATA = 3 +} MSTP_RECEIVE_STATE; + +/* The state of the Receive State Machine */ +static MSTP_RECEIVE_STATE Receive_State; +static struct mstp_flag_t { + /* A Boolean flag set to TRUE by the Receive State Machine */ + /* if an invalid or valid frame is received. */ + /* Set to FALSE by the main state machine. */ + unsigned ReceivedInvalidFrame:1; + unsigned ReceivedValidFrame:1; + /* A Boolean flag set TRUE by the datalink transmit if a + frame is pending */ + unsigned TransmitPacketPending:1; + /* A Boolean flag set TRUE by the datalink transmit if a + pending packet is DataExpectingReply */ + unsigned TransmitPacketDER:1; + /* A Boolean flag set TRUE by the datalink if a + packet has been received, but not processed. */ + unsigned ReceivePacketPending:1; +} MSTP_Flag; + +/* data passed to receive handler */ +struct mstp_packet_info_t +{ + /* A Boolean flag set to TRUE by the Receive State Machine */ + /* if a valid frame is received. */ + unsigned valid_frame:1; + /* preamble flags */ + unsigned preamble1:1; + unsigned preamble2:1; + uint8_t header[6]; /* buffer to put the header bytes */ + uint8_t *buffer; /* buffer to put the data */ + uint8_t buffer_len; /* buffer to put the data */ + uint8_t index; /* index into receive buffer */ +}; +static struct nitoo_packet_info_t MSTP_Receive_Packet; + +/* Used to store the data length of a received frame. */ +static uint16_t DataLength; +/* Used to store the destination address of a received frame. */ +static uint8_t DestinationAddress; +/* Used to store the frame type of a received frame. */ +static uint8_t FrameType; +/* An array of octets, used to store octets as they are received. */ +/* InputBuffer is indexed from 0 to InputBufferSize-1. */ +/* FIXME: assign this to an actual array of bytes! */ +/* Note: the buffer is designed as a pointer since some compilers + and microcontroller architectures have limits as to places to + hold contiguous memory. */ +static uint8_t *InputBuffer; +static uint16_t InputBufferSize; +/* Used to store the Source Address of a received frame. */ +static uint8_t SourceAddress; +/* "This Station," the MAC address of this node. TS is generally read from a */ +/* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */ +/* 0 to 254. The value 255 is used to denote broadcast when used as a */ +/* destination address but is not allowed as a value for TS. */ +static uint8_t This_Station; +/* An array of octets, used to store octets for transmitting */ +/* OutputBuffer is indexed from 0 to OutputBufferSize-1. */ +/* The MAX_PDU size of a frame is MAX_APDU + MAX_NPDU octets. */ +/* FIXME: assign this to an actual array of bytes! */ +/* Note: the buffer is designed as a pointer since some compilers + and microcontroller architectures have limits as to places to + hold contiguous memory. */ +static uint8_t *TransmitPacket; +static uint16_t TransmitPacketLen; +static uint8_t TransmitPacketDest; + +/* The minimum time without a DataAvailable or ReceiveError event within */ +/* a frame before a receiving node may discard the frame: 60 bit times. */ +/* (Implementations may use larger values for this timeout, */ +/* not to exceed 100 milliseconds.) */ +/* At 9600 baud, 60 bit times would be about 6.25 milliseconds */ +/* const uint16_t Tframe_abort = 1 + ((1000 * 60) / 9600); */ +#define Tframe_abort 30 + +/* The maximum idle time a sending node may allow to elapse between octets */ +/* of a frame the node is transmitting: 20 bit times. */ +#define Tframe_gap 20 + +/* The maximum time a node may wait after reception of a frame that expects */ +/* a reply before sending the first octet of a reply or Reply Postponed */ +/* frame: 250 milliseconds. */ +#define Treply_delay 250 + +/* The width of the time slot within which a node may generate a token: */ +/* 10 milliseconds. */ +#define Tslot 10 + +/* The maximum time a node may wait after reception of the token or */ +/* a Poll For Master frame before sending the first octet of a frame: */ +/* 15 milliseconds. */ +#define Tusage_delay 15 + +/* we need to be able to increment without rolling over */ +#define INCREMENT_AND_LIMIT_UINT8(x) {if (x < 0xFF) x++;} + +bool dlmstp_init( + char *ifname) +{ + ifname = ifname; + /* initialize hardware */ + RS485_Initialize(); + + return true; +} + +void dlmstp_cleanup( + void) +{ + /* nothing to do for static buffers */ +} + +void dlmstp_fill_bacnet_address( + BACNET_ADDRESS * src, + uint8_t mstp_address) +{ + int i = 0; + + if (mstp_address == MSTP_BROADCAST_ADDRESS) { + /* mac_len = 0 if broadcast address */ + src->mac_len = 0; + src->mac[0] = 0; + } else { + src->mac_len = 1; + src->mac[0] = mstp_address; + } + /* fill with 0's starting with index 1; index 0 filled above */ + for (i = 1; i < MAX_MAC_LEN; i++) { + src->mac[i] = 0; + } + src->net = 0; + src->len = 0; + for (i = 0; i < MAX_MAC_LEN; i++) { + src->adr[i] = 0; + } +} + +/* MS/TP Frame Format */ +/* All frames are of the following format: */ +/* */ +/* Preamble: two octet preamble: X`55', X`FF' */ +/* Frame Type: one octet */ +/* Destination Address: one octet address */ +/* Source Address: one octet address */ +/* Length: two octets, most significant octet first, of the Data field */ +/* Header CRC: one octet */ +/* Data: (present only if Length is non-zero) */ +/* Data CRC: (present only if Length is non-zero) two octets, */ +/* least significant octet first */ +/* (pad): (optional) at most one octet of padding: X'FF' */ +static void MSTP_Send_Frame( + uint8_t frame_type, /* type of frame to send - see defines */ + uint8_t destination, /* destination address */ + uint8_t source, /* source address */ + uint8_t * pdu, /* any data to be sent - may be null */ + uint16_t pdu_len) +{ /* number of bytes of data (up to 501) */ + uint8_t crc8 = 0xFF; /* used to calculate the crc value */ + uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */ + uint8_t buffer[8]; /* stores the header and crc */ + uint8_t datacrc[2]; /* stores the data crc */ + uint16_t i = 0; /* used to calculate CRC for data */ + + /* create the MS/TP header */ + buffer[0] = 0x55; + buffer[1] = 0xFF; + buffer[2] = frame_type; + crc8 = CRC_Calc_Header(buffer[2], crc8); + buffer[3] = destination; + crc8 = CRC_Calc_Header(buffer[3], crc8); + buffer[4] = source; + crc8 = CRC_Calc_Header(buffer[4], crc8); + buffer[5] = pdu_len / 256; + crc8 = CRC_Calc_Header(buffer[5], crc8); + buffer[6] = pdu_len % 256; + crc8 = CRC_Calc_Header(buffer[6], crc8); + buffer[7] = ~crc8; + if (pdu_len) { + /* calculate CRC for any data */ + for (i = 0; i < pdu_len; i++) { + crc16 = CRC_Calc_Data(pdu[i], crc16); + } + crc16 = ~crc16; + datacrc[0] = (crc16 & 0x00FF); + datacrc[1] = ((crc16 & 0xFF00) >> 8); + } + /* now transmit the frame */ + RS485_Turnaround_Delay(); + RS485_Transmitter_Enable(true); + RS485_Send_Data(buffer, 8); + /* send any data */ + if (pdu_len) { + RS485_Send_Data(pdu, pdu_len); + RS485_Send_Data(datacrc, 2); + } + RS485_Transmitter_Enable(false); +} + +#if 0 +/* return true if the packet is good. */ +/* note: buffer should include the CRC as the last byte */ +static bool crc_header_good(uint8_t *buffer, uint8_t len) +{ + uint8_t i; /* loop counter */ + uint8_t crc8 = 0xFF; /* loop counter */ + + for (i = 0; i < len; i++) { + crc8 = CRC_Calc_Header(buffer[i], crc8); + } + + return (crc8 == 0x55); +} + + +static void mstp_receive_handler(void) +{ + uint8_t data_register = 0; /* data from UART */ + + if (RS485_ReceiveError()) { + timer_silence_reset(); + } else if (RS485_DataAvailable(&data_register)) { + timer_silence_reset(); + if ((MSTP_Receive_Packet.preamble1 == false) && + (data_register == 0x55)) { + MSTP_Receive_Packet.preamble1 = true; + return; + } + if ((MSTP_Receive_Packet.preamble2 == false) && + (MSTP_Receive_Packet.preamble1 == true)) { + if (data_register == 0xFF) { + MSTP_Receive_Packet.preamble2 = true; + MSTP_Receive_Packet.index = 0; + MSTP_Receive_Packet.data_len = 0; + } else if (data_register == 0x55) { + /* repeated preamble1 */ + return; + } else { + MSTP_Receive_Packet.preamble1 = false; + } + return; + } + if (DataLength == 0) { + MSTP_Receive_Packet.header[MSTP_Receive_Packet.index] = data_register; + if (MSTP_Receive_Packet.index == 5) { + if (crc_header_good(MSTP_Receive_Packet.header, 6)) { + FrameType = MSTP_Receive_Packet.header[0]; + DestinationAddress = MSTP_Receive_Packet.header[1]; + SourceAddress = MSTP_Receive_Packet.header[2]; + DataLength = (MSTP_Receive_Packet.header[3] * 256) + + MSTP_Receive_Packet.header[4]; + if (DataLength == 0) { + MSTP_Receive_Packet.valid_frame = true; + } else { + MSTP_Receive_Packet.index = 0; + } + } else { + MSTP_Receive_Packet.preamble2 = false; + MSTP_Receive_Packet.preamble2 = false; + MSTP_Receive_Packet.index = 0; + } + } + } else { + MSTP_Receive_Packet.buffer[MSTP_Receive_Packet.index] = data_register; + if (packet_info->index == packet_info->len) { + /* PDU length ended */ + packet_info->ready = true; + } else if (packet_info->index >= sizeof(packet_info->buffer)){ + /* exceeded the size of the storage */ + packet_info->len = packet_info->index; + packet_info->ready = true; + } else { + packet_info->index++; + } + MSTP_Receive_Packet.index++; + if (packet_info->ready) { + /* validate the CRC */ + if (!lrc_packet_good(packet_info->buffer,packet_info->len+1)) { + packet_info->ready = false; + } + /* pull off the CRC */ + packet_info->crc = packet_info->buffer[packet_info->len]; + /* get ready for the next packet */ + packet_info->index = 0; + packet_info->preamble1 = false; + packet_info->preamble2 = false; + led_setup_off(); + } + } + } else { + if (ReceivePreamble1 == true) { + if (timer_silence_elapsed(Tframe_abort)) { + /* we've been busy too long! Abort packet! */ + Index = 0; + ReceivePreamble1 = false; + ReceivePreamble2 = false; + } + } + } +} +#endif + +static void MSTP_Receive_Frame_FSM( + void) +{ + /* stores the latest received data octet */ + uint8_t DataRegister = 0; + /* Used to accumulate the CRC on the data field of a frame. */ + static uint16_t DataCRC = 0; + /* Used to accumulate the CRC on the header of a frame. */ + static uint8_t HeaderCRC = 0; + /* Used as an index by the Receive State Machine, + up to a maximum value of the MPDU */ + static uint8_t Index = 0; + + switch (Receive_State) { + case MSTP_RECEIVE_STATE_IDLE: + /* In the IDLE state, the node waits for the beginning of a frame. */ + if (RS485_ReceiveError()) { + /* EatAnError */ + timer_silence_reset(); + } else if (RS485_DataAvailable(&DataRegister)) { + timer_silence_reset(); + if (DataRegister == 0x55) { + /* Preamble1 */ + /* receive the remainder of the frame. */ + Receive_State = MSTP_RECEIVE_STATE_PREAMBLE; + } + } + break; + case MSTP_RECEIVE_STATE_PREAMBLE: + /* In the PREAMBLE state, the node waits for the + second octet of the preamble. */ + if (timer_silence_elapsed(Tframe_abort)) { + /* Timeout */ + /* a correct preamble has not been received */ + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_ReceiveError()) { + /* Error */ + timer_silence_reset(); + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_DataAvailable(&DataRegister)) { + timer_silence_reset(); + if (DataRegister == 0xFF) { + /* Preamble2 */ + Index = 0; + HeaderCRC = 0xFF; + /* receive the remainder of the frame. */ + Receive_State = MSTP_RECEIVE_STATE_HEADER; + } else if (DataRegister == 0x55) { + /* ignore RepeatedPreamble1 */ + /* wait for the second preamble octet. */ + Receive_State = MSTP_RECEIVE_STATE_PREAMBLE; + } else { + /* NotPreamble */ + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + case MSTP_RECEIVE_STATE_HEADER: + /* In the HEADER state, the node waits for the fixed message header. */ + if (timer_silence_elapsed(Tframe_abort)) { + /* Timeout */ + /* indicate that an error has occurred during the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_ReceiveError()) { + /* Error */ + timer_silence_reset(); + /* indicate that an error has occurred during the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_DataAvailable(&DataRegister)) { + timer_silence_reset(); + if (Index == 0) { + /* FrameType */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + FrameType = DataRegister; + Index = 1; + } else if (Index == 1) { + /* Destination */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + DestinationAddress = DataRegister; + Index = 2; + } else if (Index == 2) { + /* Source */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + SourceAddress = DataRegister; + Index = 3; + } else if (Index == 3) { + /* Length1 */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + DataLength = DataRegister * 256; + Index = 4; + } else if (Index == 4) { + /* Length2 */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + DataLength += DataRegister; + Index = 5; + } else if (Index == 5) { + /* HeaderCRC */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + /* In the HEADER_CRC state, the node validates the CRC + on the fixed message header. */ + if (HeaderCRC != 0x55) { + /* BadCRC */ + /* indicate that an error has occurred during + the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else { + /* Note: proposed change to BACnet MSTP state machine! + If we don't decode data that is not for us, we could + get confused about the start if the Preamble 55 FF + is part of the data. */ + if ((DataLength) && (DataLength <= InputBufferSize)) { + /* Data */ + Index = 0; + DataCRC = 0xFFFF; + /* receive the data portion of the frame. */ + Receive_State = MSTP_RECEIVE_STATE_DATA; + } else { + if (DataLength == 0) { + /* NoData */ + if ((DestinationAddress == This_Station) || + (DestinationAddress == + MSTP_BROADCAST_ADDRESS)) { + /* ForUs */ + /* indicate that a frame with + no data has been received */ + MSTP_Flag.ReceivedValidFrame = true; + } else { + /* NotForUs - drop */ + } + } else { + /* FrameTooLong */ + /* indicate that a frame with an illegal or */ + /* unacceptable data length has been received */ + MSTP_Flag.ReceivedInvalidFrame = true; + } + /* wait for the start of the next frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } + } + } else { + /* indicate that an error has occurred during */ + /* the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + case MSTP_RECEIVE_STATE_DATA: + /* In the DATA state, the node waits for the data portion of a frame. */ + if (timer_silence_elapsed(Tframe_abort)) { + /* Timeout */ + /* indicate that an error has occurred during the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_ReceiveError()) { + /* Error */ + timer_silence_reset(); + /* indicate that an error has occurred during + the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_DataAvailable(&DataRegister)) { + timer_silence_reset(); + if (Index < DataLength) { + /* DataOctet */ + DataCRC = CRC_Calc_Data(DataRegister, DataCRC); + InputBuffer[Index] = DataRegister; + Index++; + } else if (Index == DataLength) { + /* CRC1 */ + DataCRC = CRC_Calc_Data(DataRegister, DataCRC); + Index++; + } else if (Index == (DataLength + 1)) { + /* CRC2 */ + DataCRC = CRC_Calc_Data(DataRegister, DataCRC); + /* STATE DATA CRC - no need for new state */ + /* indicate the complete reception of a valid frame */ + if (DataCRC == 0xF0B8) { + if ((DestinationAddress == This_Station) || + (DestinationAddress == MSTP_BROADCAST_ADDRESS)) { + /* ForUs */ + /* indicate that a frame with no data + has been received */ + MSTP_Flag.ReceivedValidFrame = true; + } + } else { + MSTP_Flag.ReceivedInvalidFrame = true; + } + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + default: + /* shouldn't get here - but if we do... */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + break; + } + + return; +} + +static void MSTP_Slave_Node_FSM( + void) +{ + if (MSTP_Flag.ReceivedValidFrame) { + MSTP_Flag.ReceivedValidFrame = false; + switch (FrameType) { + case FRAME_TYPE_TOKEN: + break; + case FRAME_TYPE_POLL_FOR_MASTER: + break; + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + break; + case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: + /* indicate successful reception to the higher layers */ + MSTP_Flag.ReceivePacketPending = true; + break; + case FRAME_TYPE_TEST_REQUEST: + MSTP_Send_Frame(FRAME_TYPE_TEST_RESPONSE, + SourceAddress, This_Station, &InputBuffer[0], + DataLength); + break; + case FRAME_TYPE_TEST_RESPONSE: + default: + break; + } + } else if (MSTP_Flag.TransmitPacketPending) { + /* Reply */ + /* If a reply is available from the higher layers */ + /* within Treply_delay after the reception of the */ + /* final octet of the requesting frame */ + /* (the mechanism used to determine this is a local matter), */ + /* then call MSTP_Send_Frame to transmit the reply frame */ + /* and enter the IDLE state to wait for the next frame. */ + /* Note: optimized such that we are never a client */ + MSTP_Send_Frame(FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY, + TransmitPacketDest, This_Station, + (uint8_t *) & TransmitPacket[0], TransmitPacketLen); + MSTP_Flag.TransmitPacketPending = false; + MSTP_Flag.ReceivePacketPending = false; + } +} + +/* returns number of bytes sent on success, zero on failure */ +int dlmstp_send_pdu( + BACNET_ADDRESS * dest, /* destination address */ + BACNET_NPDU_DATA * npdu_data, /* network information */ + uint8_t * pdu, /* any data to be sent - may be null */ + unsigned pdu_len) +{ /* number of bytes of data */ + int bytes_sent = 0; + + if (MSTP_Flag.TransmitPacketPending == false) { + MSTP_Flag.TransmitPacketDER = npdu_data->data_expecting_reply; + TransmitPacket = pdu; + TransmitPacketLen = pdu_len; + bytes_sent = pdu_len; + TransmitPacketDest = dest->mac[0]; + MSTP_Flag.TransmitPacketPending = true; + } + + return bytes_sent; +} + +/* Return the length of the packet */ +uint16_t dlmstp_receive( + BACNET_ADDRESS * src, /* source address */ + uint8_t * pdu, /* PDU data */ + uint16_t max_pdu, /* amount of space available in the PDU */ + unsigned timeout) +{ /* milliseconds to wait for a packet */ + uint16_t pdu_len = 0; /* return value */ + + /* dummy - unused parameter */ + timeout = timeout; + /* set the input buffer to the same data storage for zero copy */ + if (!InputBuffer) { + InputBuffer = pdu; + InputBufferSize = max_pdu; + } + /* only do receive state machine while we don't have a frame */ + if ((MSTP_Flag.ReceivedValidFrame == false) && + (MSTP_Flag.ReceivedInvalidFrame == false) && + (MSTP_Flag.ReceivePacketPending == false)) { + for (;;) { + MSTP_Receive_Frame_FSM(); + if (MSTP_Flag.ReceivedValidFrame || MSTP_Flag.ReceivedInvalidFrame) + break; + /* if we are not idle, then we are + receiving a frame or timing out */ + if (Receive_State == MSTP_RECEIVE_STATE_IDLE) + break; + } + } + /* only do master state machine while rx is idle */ + if (Receive_State == MSTP_RECEIVE_STATE_IDLE) { + MSTP_Slave_Node_FSM(); + } + /* if there is a packet that needs processed, do it now. */ + if (MSTP_Flag.ReceivePacketPending) { + MSTP_Flag.ReceivePacketPending = false; + pdu_len = DataLength; + src->mac_len = 1; + src->mac[0] = SourceAddress; + /* data is already in the pdu pointer */ + } + + return pdu_len; +} + +void dlmstp_set_mac_address( + uint8_t mac_address) +{ + /* Master Nodes can only have address 0-127 */ + if (mac_address <= 127) { + This_Station = mac_address; + /* FIXME: implement your data storage */ + /* I2C_Write_Byte( + EEPROM_DEVICE_ADDRESS, + mac_address, + EEPROM_MSTP_MAC_ADDR); */ + } + + return; +} + +uint8_t dlmstp_mac_address( + void) +{ + return This_Station; +} + +void dlmstp_get_my_address( + BACNET_ADDRESS * my_address) +{ + int i = 0; /* counter */ + + my_address->mac_len = 1; + my_address->mac[0] = This_Station; + my_address->net = 0; /* local only, no routing */ + my_address->len = 0; + for (i = 0; i < MAX_MAC_LEN; i++) { + my_address->adr[i] = 0; + } + + return; +} + +void dlmstp_get_broadcast_address( + BACNET_ADDRESS * dest) +{ /* destination address */ + int i = 0; /* counter */ + + if (dest) { + dest->mac_len = 1; + dest->mac[0] = MSTP_BROADCAST_ADDRESS; + dest->net = BACNET_BROADCAST_NETWORK; + dest->len = 0; /* always zero when DNET is broadcast */ + for (i = 0; i < MAX_MAC_LEN; i++) { + dest->adr[i] = 0; + } + } + + return; +} diff --git a/bacnet-stack/ports/atmega8/h_rp.c b/bacnet-stack/ports/atmega8/h_rp.c new file mode 100644 index 00000000..d34bbb58 --- /dev/null +++ b/bacnet-stack/ports/atmega8/h_rp.c @@ -0,0 +1,173 @@ +/************************************************************************** +* +* 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 "bacerror.h" +#include "apdu.h" +#include "npdu.h" +#include "abort.h" +#include "rp.h" +/* demo objects */ +#include "device.h" +#if MAX_ANALOG_VALUES +#include "av.h" +#endif +#if MAX_BINARY_VALUES +#include "bv.h" +#endif + +/* Encodes the property APDU and returns the length, + or sets the error, and returns -1 */ +int Encode_Property_APDU( + uint8_t * apdu, + BACNET_READ_PROPERTY_DATA * rp_data, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + int apdu_len = -1; + + /* handle each object type */ + switch (rp_data->object_type) { + case OBJECT_DEVICE: + if (Device_Valid_Object_Instance_Number(rp_data->object_instance)) { + apdu_len = + Device_Encode_Property_APDU(&apdu[0], + rp_data->object_property, rp_data->array_index, + error_class, error_code); + } + break; +#if MAX_ANALOG_VALUES + case OBJECT_ANALOG_VALUE: + if (Analog_Value_Valid_Instance(rp_data->object_instance)) { + apdu_len = + Analog_Value_Encode_Property_APDU(&apdu[0], + rp_data->object_instance, rp_data->object_property, + rp_data->array_index, error_class, error_code); + } + break; +#endif +#if MAX_BINARY_VALUES + case OBJECT_BINARY_VALUE: + if (Binary_Value_Valid_Instance(rp_data->object_instance)) { + apdu_len = + Binary_Value_Encode_Property_APDU(&apdu[0], + rp_data->object_instance, rp_data->object_property, + rp_data->array_index, error_class, error_code); + } + break; +#endif + default: + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE; + break; + } + + return apdu_len; +} + +void handler_read_property( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src, + BACNET_CONFIRMED_SERVICE_DATA * service_data) +{ + BACNET_READ_PROPERTY_DATA data; + int len = 0; + int ack_len = 0; + int property_len = 0; + int pdu_len = 0; + BACNET_NPDU_DATA npdu_data; + int bytes_sent = 0; + BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; + BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; + 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); + goto RP_ABORT; + } + len = rp_decode_service_request(service_request, service_len, &data); + 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); + goto RP_ABORT; + } + /* most cases will be error */ + ack_len = + rp_ack_encode_apdu_init(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, &data); + /* FIXME: add buffer len as passed into function or use smart buffer */ + property_len = + Encode_Property_APDU(&Handler_Transmit_Buffer[pdu_len + ack_len], + &data, &error_class, &error_code); + if (property_len >= 0) { + len = + rp_ack_encode_apdu_object_property_end(&Handler_Transmit_Buffer + [pdu_len + property_len + ack_len]); + len += ack_len + property_len; + } else { + switch (property_len) { + /* BACnet APDU too small to fit data, so proper response is Abort */ + case -2: + len = + abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); + break; + default: + len = + bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY, + error_class, error_code); + break; + } + } + RP_ABORT: + pdu_len += len; + bytes_sent = + datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], + pdu_len); + + return; +} diff --git a/bacnet-stack/ports/atmega8/h_whois.c b/bacnet-stack/ports/atmega8/h_whois.c new file mode 100644 index 00000000..3a0d56ec --- /dev/null +++ b/bacnet-stack/ports/atmega8/h_whois.c @@ -0,0 +1,71 @@ +/************************************************************************** +* +* 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 "whois.h" +#include "iam.h" +#include "device.h" +#include "client.h" +#include "txbuf.h" + +bool Send_I_Am = true; + +void handler_who_is( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src) +{ + int len = 0; + int32_t low_limit = 0; + int32_t high_limit = 0; + int32_t target_device; + + (void) src; + len = + whois_decode_service_request(service_request, service_len, &low_limit, + &high_limit); + if (len == 0) { + Send_I_Am = true; + } else if (len != -1) { + /* is my device id within the limits? */ + target_device = Device_Object_Instance_Number(); + if (((target_device >= low_limit) && (target_device <= high_limit)) + || + /* BACnet wildcard is the max instance number - everyone responds */ + ((BACNET_MAX_INSTANCE >= (uint32_t) low_limit) && + (BACNET_MAX_INSTANCE <= (uint32_t) high_limit))) { + Send_I_Am = true; + } + } + + return; +} diff --git a/bacnet-stack/ports/atmega8/h_wp.c b/bacnet-stack/ports/atmega8/h_wp.c new file mode 100644 index 00000000..7c4daca0 --- /dev/null +++ b/bacnet-stack/ports/atmega8/h_wp.c @@ -0,0 +1,139 @@ +/************************************************************************** +* +* 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 "bacerror.h" +#include "apdu.h" +#include "npdu.h" +#include "abort.h" +#include "wp.h" +/* demo objects */ +#include "device.h" +#include "av.h" +#include "bv.h" + +/* too big to reside on stack frame for PIC */ +static BACNET_WRITE_PROPERTY_DATA wp_data; + +void handler_write_property( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src, + BACNET_CONFIRMED_SERVICE_DATA * service_data) +{ + int len = 0; + int pdu_len = 0; + BACNET_NPDU_DATA npdu_data; + BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; + BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; + int bytes_sent = 0; + BACNET_ADDRESS my_address; + + /* decode the service request only */ + len = wp_decode_service_request(service_request, service_len, &wp_data); + /* 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); + /* bad decoding or something we didn't understand - send an abort */ + if (len <= 0) { + len = + abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, ABORT_REASON_OTHER, true); + } else if (service_data->segmented_message) { + len = + abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, + true); + } else { + switch (wp_data.object_type) { + case OBJECT_DEVICE: + if (Device_Write_Property(&wp_data, &error_class, &error_code)) { + len = + encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY); + } else { + len = + bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, + error_code); + } + break; + case OBJECT_ANALOG_VALUE: + if (Analog_Value_Write_Property(&wp_data, &error_class, + &error_code)) { + len = + encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY); + } else { + len = + bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, + error_code); + } + break; + case OBJECT_BINARY_VALUE: + if (Binary_Value_Write_Property(&wp_data, &error_class, + &error_code)) { + len = + encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY); + } else { + len = + bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, + error_code); + } + break; + default: + len = + bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY, + error_class, error_code); + break; + } + } + pdu_len += len; + bytes_sent = + datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], + pdu_len); + + return; +} diff --git a/bacnet-stack/ports/atmega8/hardware.h b/bacnet-stack/ports/atmega8/hardware.h new file mode 100644 index 00000000..b2fa9008 --- /dev/null +++ b/bacnet-stack/ports/atmega8/hardware.h @@ -0,0 +1,54 @@ +/************************************************************************** +* +* Copyright (C) 2007 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. +* +*********************************************************************/ +#ifndef HARDWARE_H +#define HARDWARE_H + +#if !defined(F_CPU) + /* The processor clock frequency */ +#define F_CPU 7372800UL +#endif + +#if defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ASM__) +#include +#else +#if !defined(__AVR_ATmega168__) +#error Firmware is configured for ATmega168 only (-mmcu=atmega168) +#endif +#endif +#include "iar2gcc.h" +#include "avr035.h" + +#define LED_NPDU_INIT() BIT_SET(DDRD, DDD5) +#define LED_NPDU_ON() BIT_CLEAR(PORTD, PD5) +#define LED_NPDU_OFF() BIT_SET(PORTD, PD5) +/* #define LED_NPDU PORTD_Bit5 */ +/* #define LED_NPDU_OFF() {LED_NPDU = false;} */ +/* #define LED_NPDU_ON() {LED_NPDU = true;} */ + +#define LED_GREEN_INIT() BIT_SET(DDRD, DDD4) +#define LED_GREEN_ON() BIT_CLEAR(PORTD, PD4) +#define LED_GREEN_OFF() BIT_SET(PORTD, PD4) + +#endif diff --git a/bacnet-stack/ports/atmega8/hardware.ods b/bacnet-stack/ports/atmega8/hardware.ods new file mode 100644 index 0000000000000000000000000000000000000000..6d06047c5c4306055b0f15988229b9c0b5fba778 GIT binary patch literal 19823 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 +#include +/* BitValue is used alot in GCC examples */ +#define _BV(bit_num) (1 << (bit_num)) + +/* inline function */ +static inline void _delay_us( + uint8_t microseconds) +{ + do { + __delay_cycles(F_CPU / 1000000UL); + } while (microseconds--); +} +#endif + +/* Input/Output Registers */ +#if defined(__GNUC__) +#include + +typedef struct { + unsigned char bit0:1; + unsigned char bit1:1; + unsigned char bit2:1; + unsigned char bit3:1; + unsigned char bit4:1; + unsigned char bit5:1; + unsigned char bit6:1; + unsigned char bit7:1; +} BitRegisterType; + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +#define GPIO_BITREG(port,bitnum) \ + ((volatile BitRegisterType*)_SFR_MEM_ADDR(port) \ + )->bit ## bitnum + +#define PINA_Bit0 GPIO_BITREG(PINA,0) +#define PINA_Bit1 GPIO_BITREG(PINA,1) +#define PINA_Bit2 GPIO_BITREG(PINA,2) +#define PINA_Bit3 GPIO_BITREG(PINA,3) +#define PINA_Bit4 GPIO_BITREG(PINA,4) +#define PINA_Bit5 GPIO_BITREG(PINA,5) +#define PINA_Bit6 GPIO_BITREG(PINA,6) +#define PINA_Bit7 GPIO_BITREG(PINA,7) + +#define PORTA_Bit0 GPIO_BITREG(PORTA,0) +#define PORTA_Bit1 GPIO_BITREG(PORTA,1) +#define PORTA_Bit2 GPIO_BITREG(PORTA,2) +#define PORTA_Bit3 GPIO_BITREG(PORTA,3) +#define PORTA_Bit4 GPIO_BITREG(PORTA,4) +#define PORTA_Bit5 GPIO_BITREG(PORTA,5) +#define PORTA_Bit6 GPIO_BITREG(PORTA,6) +#define PORTA_Bit7 GPIO_BITREG(PORTA,7) + +#define PINB_Bit0 GPIO_BITREG(PINB,0) +#define PINB_Bit1 GPIO_BITREG(PINB,1) +#define PINB_Bit2 GPIO_BITREG(PINB,2) +#define PINB_Bit3 GPIO_BITREG(PINB,3) +#define PINB_Bit4 GPIO_BITREG(PINB,4) +#define PINB_Bit5 GPIO_BITREG(PINB,5) +#define PINB_Bit6 GPIO_BITREG(PINB,6) +#define PINB_Bit7 GPIO_BITREG(PINB,7) + +#define PORTB_Bit0 GPIO_BITREG(PORTB,0) +#define PORTB_Bit1 GPIO_BITREG(PORTB,1) +#define PORTB_Bit2 GPIO_BITREG(PORTB,2) +#define PORTB_Bit3 GPIO_BITREG(PORTB,3) +#define PORTB_Bit4 GPIO_BITREG(PORTB,4) +#define PORTB_Bit5 GPIO_BITREG(PORTB,5) +#define PORTB_Bit6 GPIO_BITREG(PORTB,6) +#define PORTB_Bit7 GPIO_BITREG(PORTB,7) + +#define PINC_Bit0 GPIO_BITREG(PINC,0) +#define PINC_Bit1 GPIO_BITREG(PINC,1) +#define PINC_Bit2 GPIO_BITREG(PINC,2) +#define PINC_Bit3 GPIO_BITREG(PINC,3) +#define PINC_Bit4 GPIO_BITREG(PINC,4) +#define PINC_Bit5 GPIO_BITREG(PINC,5) +#define PINC_Bit6 GPIO_BITREG(PINC,6) +#define PINC_Bit7 GPIO_BITREG(PINC,7) + +#define PORTC_Bit0 GPIO_BITREG(PORTC,0) +#define PORTC_Bit1 GPIO_BITREG(PORTC,1) +#define PORTC_Bit2 GPIO_BITREG(PORTC,2) +#define PORTC_Bit3 GPIO_BITREG(PORTC,3) +#define PORTC_Bit4 GPIO_BITREG(PORTC,4) +#define PORTC_Bit5 GPIO_BITREG(PORTC,5) +#define PORTC_Bit6 GPIO_BITREG(PORTC,6) +#define PORTC_Bit7 GPIO_BITREG(PORTC,7) + +#define PIND_Bit0 GPIO_BITREG(PIND,0) +#define PIND_Bit1 GPIO_BITREG(PIND,1) +#define PIND_Bit2 GPIO_BITREG(PIND,2) +#define PIND_Bit3 GPIO_BITREG(PIND,3) +#define PIND_Bit4 GPIO_BITREG(PIND,4) +#define PIND_Bit5 GPIO_BITREG(PIND,5) +#define PIND_Bit6 GPIO_BITREG(PIND,6) +#define PIND_Bit7 GPIO_BITREG(PIND,7) + +#define PORTD_Bit0 GPIO_BITREG(PORTD,0) +#define PORTD_Bit1 GPIO_BITREG(PORTD,1) +#define PORTD_Bit2 GPIO_BITREG(PORTD,2) +#define PORTD_Bit3 GPIO_BITREG(PORTD,3) +#define PORTD_Bit4 GPIO_BITREG(PORTD,4) +#define PORTD_Bit5 GPIO_BITREG(PORTD,5) +#define PORTD_Bit6 GPIO_BITREG(PORTD,6) +#define PORTD_Bit7 GPIO_BITREG(PORTD,7) + +#define GPIOR0_Bit0 GPIO_BITREG(GPIOR0,0) +#define GPIOR0_Bit1 GPIO_BITREG(GPIOR0,1) +#define GPIOR0_Bit2 GPIO_BITREG(GPIOR0,2) +#define GPIOR0_Bit3 GPIO_BITREG(GPIOR0,3) +#define GPIOR0_Bit4 GPIO_BITREG(GPIOR0,4) +#define GPIOR0_Bit5 GPIO_BITREG(GPIOR0,5) +#define GPIOR0_Bit6 GPIO_BITREG(GPIOR0,6) +#define GPIOR0_Bit7 GPIO_BITREG(GPIOR0,7) + +#define GPIOR1_Bit0 GPIO_BITREG(GPIOR1,0) +#define GPIOR1_Bit1 GPIO_BITREG(GPIOR1,1) +#define GPIOR1_Bit2 GPIO_BITREG(GPIOR1,2) +#define GPIOR1_Bit3 GPIO_BITREG(GPIOR1,3) +#define GPIOR1_Bit4 GPIO_BITREG(GPIOR1,4) +#define GPIOR1_Bit5 GPIO_BITREG(GPIOR1,5) +#define GPIOR1_Bit6 GPIO_BITREG(GPIOR1,6) +#define GPIOR1_Bit7 GPIO_BITREG(GPIOR1,7) + +#define GPIOR2_Bit0 GPIO_BITREG(GPIOR2,0) +#define GPIOR2_Bit1 GPIO_BITREG(GPIOR2,1) +#define GPIOR2_Bit2 GPIO_BITREG(GPIOR2,2) +#define GPIOR2_Bit3 GPIO_BITREG(GPIOR2,3) +#define GPIOR2_Bit4 GPIO_BITREG(GPIOR2,4) +#define GPIOR2_Bit5 GPIO_BITREG(GPIOR2,5) +#define GPIOR2_Bit6 GPIO_BITREG(GPIOR2,6) +#define GPIOR2_Bit7 GPIO_BITREG(GPIOR2,7) + +#endif + +/* Global Interrupts */ +#if defined(__GNUC__) +#define __enable_interrupt() sei() +#define __disable_interrupt() cli() +#endif + +/* Interrupts */ +#if defined(__ICCAVR__) +#define PRAGMA(x) _Pragma( #x ) +#define ISR(vec) PRAGMA( vector=vec ) __interrupt void handler_##vec(void) +#endif +#if defined(__GNUC__) +#include +#endif + +/* Flash */ +#if defined(__ICCAVR__) +#define FLASH_DECLARE(x) __flash x +#endif +#if defined(__GNUC__) +#define FLASH_DECLARE(x) x __attribute__((__progmem__)) +#endif + +/* EEPROM */ +#if defined(__ICCAVR__) +#define EEPROM_DECLARE(x) __eeprom x +#endif +#if defined(__GNUC__) +#include +#define EEPROM_DECLARE(x) x __attribute__((section (".eeprom"))) +#endif + +/* IAR intrinsic routines */ +#if defined(__GNUC__) + /* FIXME: intrinsic routines: map to assembler for size/speed */ +#define __multiply_unsigned(x,y) ((x)*(y)) + /* FIXME: __root means to not optimize or strip */ +#define __root +#endif + +#endif diff --git a/bacnet-stack/ports/atmega8/main.c b/bacnet-stack/ports/atmega8/main.c new file mode 100644 index 00000000..a3ddb262 --- /dev/null +++ b/bacnet-stack/ports/atmega8/main.c @@ -0,0 +1,122 @@ +/************************************************************************** +* +* Copyright (C) 2007 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 "hardware.h" +#include "timer.h" +#include "rs485.h" +#include "datalink.h" +#include "npdu.h" +#include "txbuf.h" +#include "iam.h" +#include "device.h" +#include "av.h" +#include "handlers.h" + +/* local version override */ +const char *BACnet_Version = "1.0"; + +/* For porting to IAR, see: + http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/ + +/* dummy function - so we can use default demo handlers */ +bool dcc_communication_enabled( + void) +{ + return true; +} + +static void init( + void) +{ + /* FIXME: Initialize the Clock Prescaler for ATmega8 */ +#if defined(__AVR_ATmega168__) + /* The default CLKPSx bits are factory set to 0011 */ + /* Enbable the Clock Prescaler */ + CLKPR = _BV(CLKPCE); + /* CLKPS3 CLKPS2 CLKPS1 CLKPS0 Clock Division Factor + ------ ------ ------ ------ --------------------- + 0 0 0 0 1 + 0 0 0 1 2 + 0 0 1 0 4 + 0 0 1 1 8 + 0 1 0 0 16 + 0 1 0 1 32 + 0 1 1 0 64 + 0 1 1 1 128 + 1 0 0 0 256 + 1 x x x Reserved + */ + /* Set the CLKPS3..0 bits to Prescaler of 1 */ + CLKPR = 0; +#endif + /* Initialize I/O ports */ + /* For Port DDRx (Data Direction) Input=0, Output=1 */ + /* For Port PORTx (Bit Value) TriState=0, High=1 */ + DDRB = 0; + PORTB = 0; + DDRC = 0; + PORTC = 0; + DDRD = 0; + PORTD = 0; + + /* Configure the watchdog timer - Disabled for testing */ +#if defined(__AVR_ATmega168__) + BIT_CLEAR(MCUSR, WDRF); + WDTCSR = 0; +#else + BIT_CLEAR(MCUCSR, WDRF); + WDTCR = 0; +#endif + + /* Configure Specialized Hardware */ + RS485_Initialize(); + RS485_Set_Baud_Rate(38400); + /* Configure Timer0 for millisecond timer */ + timer_init(); + /* Enable global interrupts */ + __enable_interrupt(); +} + +static uint8_t PDUBuffer[MAX_MPDU]; + +int main( + void) +{ + uint16_t pdu_len = 0; + BACNET_ADDRESS src; /* source address */ + + init(); + datalink_init(NULL); + for (;;) { + /* other tasks */ + /* BACnet handling */ + pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0); + if (pdu_len) { + npdu_handler(&src, &PDUBuffer[0], pdu_len); + } + } +} diff --git a/bacnet-stack/ports/atmega8/readme.txt b/bacnet-stack/ports/atmega8/readme.txt new file mode 100644 index 00000000..7a110a05 --- /dev/null +++ b/bacnet-stack/ports/atmega8/readme.txt @@ -0,0 +1,45 @@ +This port was originally done with the Atmel ATmega168 +I used the following tools: +1. The WinAVR compiler avr-gcc (GCC) 4.1.2 (WinAVR 20070525) +and tools from , hints and +sample code from and +. +"avr-binutils, avr-gcc, and avr-libc form the heart of the +Free Software toolchain for the Atmel AVR microcontrollers." +2. AVR Studio 4 from Atmel + +The hardware is expected to utilize the signals as defined +in the spreadsheet hardware.ods (OpenOffice.org calc). +Attach a DS75176 RS-485 transceiver (or similar) to the USART. +DS75176 ATmega168 +------ --------- + RO RXD + /RE --choice of I/O + DE --choice of I/O + DI TXD + GND GND + DO --to RS-485 wire + DO --to RS-485 wire + +5V From 5V Regulator + +The makefile allows you to build a simple server. +dlmstp is the datalink layer for MS/TP over RS-485. +This project uses an MS/TP Slave Node. + +I used the makefile from the command line on Windows: +C:\code\bacnet-stack\ports\atmega168> make clean all + +The BACnet Capabilities include ReadProperty support. +The BACnet objects include only a Device object. +All required object properties can be retrieved using ReadProperty. + +With full optimization, the statistics on the demo are: + +avr-gcc (GCC) 4.2.2 (WinAVR 20071221rc1) +Device: atmega168 +Program: 8734 bytes (53.3% Full) +Data: 254 bytes (24.8% Full) (does not include CStack) + +Hopefully you find this code useful! + +Steve Karg diff --git a/bacnet-stack/ports/atmega8/rs485.c b/bacnet-stack/ports/atmega8/rs485.c new file mode 100644 index 00000000..3c57b72f --- /dev/null +++ b/bacnet-stack/ports/atmega8/rs485.c @@ -0,0 +1,292 @@ +/************************************************************************** +* +* Copyright (C) 2007 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. +* +*********************************************************************/ + +/* The module handles sending data out the RS-485 port */ +/* and handles receiving data from the RS-485 port. */ +/* Customize this file for your specific hardware */ +#include +#include +#include +#include +#include +/*#include "mstp.h" */ + +/* This file has been customized for use with ATMEGA168 */ +#if defined(__AVR_ATmega168__) + /* USART defines for RS-485 port */ + #define UCSRB UCSR0B + #define TXEN TXEN0 + #define RXEN RXEN0 + #define UCSRC UCSR0C + #define UCSZ1 UCSZ01 + #define UCSZ0 UCSZ00 + #define UCSRA UCSR0A + #define U2X U2X0 + #define UBRRL UBRR0 + #define UCSRA UCSR0A + #define UDRE UDRE0 + #define UDR UDR0 + #define TXC TXC0 + #define FE FE0 + #define DOR DOR0 + #define UPE UPE0 + #define DOR DOR0 + #define RXC RXC0 +#endif + +#include "hardware.h" +#include "timer.h" + +/* baud rate */ +static uint32_t RS485_Baud; + +/* The minimum time after the end of the stop bit of the final octet of a */ +/* received frame before a node may enable its EIA-485 driver: 40 bit times. */ +/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */ +/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */ +/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */ +/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */ +/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */ +/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */ +/* 40 bits is 4 octets including a start and stop bit with each octet */ +#define Tturnaround (40UL) +/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */ + +/**************************************************************************** +* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in +* receive mode. +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Initialize( + void) +{ + /* enable Transmit and Receive */ + UCSRB = _BV(TXEN) | _BV(RXEN); + + /* Set USART Control and Status Register n C */ + /* Asynchronous USART 8-bit data, No parity, 1 stop */ + /* Set USART Mode Select: UMSELn1 UMSELn0 = 00 for Asynchronous USART */ + /* Set Parity Mode: UPMn1 UPMn0 = 00 for Parity Disabled */ + /* Set Stop Bit Select: USBSn = 0 for 1 stop bit */ + /* Set Character Size: UCSZn2 UCSZn1 UCSZn0 = 011 for 8-bit */ + /* Clock Polarity: UCPOLn = 0 when asynchronous mode is used. */ + UCSRC = _BV(UCSZ1) | _BV(UCSZ0); +#if defined(__AVR_ATmega168__) + /* Clear Power Reduction USART0 */ + BIT_CLEAR(PRR, PRUSART0); +#endif + /* Use port PD2 for RTS - enable and disable of Transceiver Tx/Rx */ + /* Set port bit as Output - initially receiving */ + BIT_CLEAR(PORTD, PD2); + BIT_SET(DDRD, DDD2); + + return; +} + +/**************************************************************************** +* DESCRIPTION: Returns the baud rate that we are currently running at +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +uint32_t RS485_Get_Baud_Rate( + void) +{ + return RS485_Baud; +} + +/**************************************************************************** +* DESCRIPTION: Sets the baud rate for the chip USART +* RETURN: true if valid baud rate +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +bool RS485_Set_Baud_Rate( + uint32_t baud) +{ + bool valid = true; + + switch (baud) { + case 9600: + case 19200: + case 38400: + case 57600: + case 76800: + case 115200: + RS485_Baud = baud; + /* 2x speed mode */ + BIT_SET(UCSRA, U2X); + /* configure baud rate */ + UBRRL = (F_CPU / (8UL * RS485_Baud)) - 1; + /* FIXME: store the baud rate */ + break; + default: + valid = false; + break; + } + + return valid; +} + +/**************************************************************************** +* DESCRIPTION: Waits on the SilenceTimer for 40 bits. +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Turnaround_Delay( + void) +{ + uint16_t turnaround_time; + + /* delay after reception before trasmitting - per MS/TP spec */ + /* wait a minimum 40 bit times since reception */ + /* at least 1 ms for errors: rounding, clock tick */ + turnaround_time = 1 + ((Tturnaround * 1000UL) / RS485_Baud); + while (!timer_silence_elapsed(turnaround_time)) { + /* do nothing - wait for timer to increment */ + }; +} + +/**************************************************************************** +* DESCRIPTION: Enable or disable the transmitter +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Transmitter_Enable( + bool enable) +{ + if (enable) { + BIT_SET(PORTD, PD2); + } else { + BIT_CLEAR(PORTD, PD2); + } +} + +/**************************************************************************** +* DESCRIPTION: Send some data and wait until it is sent +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Send_Data( + uint8_t * buffer, /* data to send */ + uint16_t nbytes) +{ /* number of bytes of data */ + while (nbytes) { + while (!BIT_CHECK(UCSRA, UDRE)) { + /* do nothing - wait until Tx buffer is empty */ + } + /* Send the data byte */ + UDR = *buffer; + buffer++; + nbytes--; + } + /* was the frame sent? */ + while (!BIT_CHECK(UCSRA, TXC)) { + /* do nothing - wait until the entire frame in the + Transmit Shift Register has been shifted out */ + } + /* Clear the Transmit Complete flag by writing a one to it. */ + BIT_SET(UCSRA, TXC); + /* per MSTP spec, sort of */ + timer_silence_reset(); +} + + +/**************************************************************************** +* DESCRIPTION: Return true if a framing or overrun error is present +* RETURN: true if error +* ALGORITHM: autobaud - if there are a lot of errors, switch baud rate +* NOTES: Clears any error flags. +*****************************************************************************/ +bool RS485_ReceiveError( + void) +{ + bool ReceiveError = false; + uint8_t dummy_data; + + /* check for framing error */ +#if 0 + if (BIT_CHECK(UCSRA, FE0)) { + /* FIXME: how do I clear the error flags? */ + BITMASK_CLEAR(UCSRA, (_BV(FE) | _BV(DOR) | _BV(UPE))); + ReceiveError = true; + } +#endif + /* check for overrun error */ + if (BIT_CHECK(UCSRA, DOR)) { + /* flush the receive buffer */ + do { + dummy_data = UDR; + } while (BIT_CHECK(UCSRA, RXC)); + ReceiveError = true; + } + + return ReceiveError; +} + +/**************************************************************************** +* DESCRIPTION: Return true if data is available +* RETURN: true if data is available, with the data in the parameter set +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +bool RS485_DataAvailable( + uint8_t * data) +{ + bool DataAvailable = false; + + /* check for data */ + if (BIT_CHECK(UCSRA, RXC)) { + *data = UDR; + DataAvailable = true; + } + + return DataAvailable; +} + +#ifdef TEST_RS485 +int main( + void) +{ + unsigned i = 0; + uint8_t DataRegister; + + RS485_Set_Baud_Rate(38400); + RS485_Initialize(); + /* receive task */ + for (;;) { + if (RS485_ReceiveError()) { + fprintf(stderr, "ERROR "); + } else if (RS485_DataAvailable(&DataRegister)) { + fprintf(stderr, "%02X ", DataRegister); + } + } +} +#endif /* TEST_RS485 */ diff --git a/bacnet-stack/ports/atmega8/rs485.h b/bacnet-stack/ports/atmega8/rs485.h new file mode 100644 index 00000000..fe0dd706 --- /dev/null +++ b/bacnet-stack/ports/atmega8/rs485.h @@ -0,0 +1,70 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2004 Steve Karg + + 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 RS485_H +#define RS485_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void RS485_Initialize( + void); + + void RS485_Transmitter_Enable( + bool enable); + + void RS485_Send_Data( + uint8_t * buffer, /* data to send */ + uint16_t nbytes); /* number of bytes of data */ + + bool RS485_ReceiveError( + void); + bool RS485_DataAvailable( + uint8_t * data); + + void RS485_Turnaround_Delay( + void); + uint32_t RS485_Get_Baud_Rate( + void); + bool RS485_Set_Baud_Rate( + uint32_t baud); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/atmega8/stdbool.h b/bacnet-stack/ports/atmega8/stdbool.h new file mode 100644 index 00000000..80e1ee96 --- /dev/null +++ b/bacnet-stack/ports/atmega8/stdbool.h @@ -0,0 +1,28 @@ +#ifndef STDBOOL_H +#define STDBOOL_H + +/* C99 Boolean types for compilers without C99 support */ + +#ifndef __cplusplus +/* typedef char _Bool; */ +#ifndef bool +#define bool _Bool +#endif +#ifndef true +#define true 1 +#endif +#ifndef false +#define false 0 +#endif +#define __bool_true_false_are_defined 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#endif diff --git a/bacnet-stack/ports/atmega8/stdint.h b/bacnet-stack/ports/atmega8/stdint.h new file mode 100644 index 00000000..93556b05 --- /dev/null +++ b/bacnet-stack/ports/atmega8/stdint.h @@ -0,0 +1,15 @@ +/* Defines the standard integer types that are used in code */ + +#ifndef STDINT_H +#define STDINT_H 1 + +#include + +typedef unsigned char uint8_t; /* 1 byte 0 to 255 */ +typedef signed char int8_t; /* 1 byte -127 to 127 */ +typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */ +typedef signed short int16_t; /* 2 bytes -32767 to 32767 */ +typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */ +typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */ + +#endif /* STDINT_H */ diff --git a/bacnet-stack/ports/atmega8/timer.c b/bacnet-stack/ports/atmega8/timer.c new file mode 100644 index 00000000..49d1190d --- /dev/null +++ b/bacnet-stack/ports/atmega8/timer.c @@ -0,0 +1,109 @@ +/************************************************************************** +* +* Copyright (C) 2007 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 "hardware.h" + +/* This module is a 1 millisecond timer */ + +/* Prescaling: 1, 8, 64, 256, 1024 */ +#define TIMER_PRESCALER 64 +/* Count: Timer0 counts up to 0xFF and then signals overflow */ +#define TIMER_TICKS (F_CPU/TIMER_PRESCALER/1000) +#if (TIMER_TICKS > 0xFF) +#error Timer Prescaler value is too small +#endif +#define TIMER_COUNT (0xFF-TIMER_TICKS) +/* millisecond timer count */ +static volatile uint16_t Timer_Silence; + +/* FIXME: Configure the Timer */ +void timer_init( + void) +{ + /* Normal Operation */ + TCCR1A = 0; + /* CSn2 CSn1 CSn0 Description + ---- ---- ---- ----------- + 0 0 0 No Clock Source + 0 0 1 No prescaling + 0 1 0 CLKio/8 + 0 1 1 CLKio/64 + 1 0 0 CLKio/256 + 1 0 1 CLKio/1024 + 1 1 0 Falling Edge of T0 (external) + 1 1 1 Rising Edge of T0 (external) + */ +#if defined(__AVR_ATmega168__) + TCCR0B = _BV(CS01) | _BV(CS00); + /* Clear any TOV1 Flag set when the timer overflowed */ + BIT_CLEAR(TIFR0, TOV0); + /* Initial value */ + TCNT0 = TIMER_COUNT; + /* Enable the overflow interrupt */ + BIT_SET(TIMSK0, TOIE0); + /* Clear the Power Reduction Timer/Counter0 */ + BIT_CLEAR(PRR, PRTIM0); +#endif +} + +/* Timer interupt */ +/* note: Global interupts must be enabled - sei() */ +/* Timer Overflowed! Increment the time. */ +ISR(TIMER0_OVF_vect) +{ + /* Set the counter for the next interrupt */ + TCNT0 = TIMER_COUNT; + /* Overflow Flag is automatically cleared */ + /* Update the global timer */ + Timer_Silence++; +} + +/* return true if time has expired */ +bool timer_silence_elapsed( + uint16_t value) +{ + bool status = false; + uint8_t sreg; + + sreg = SREG; + __disable_interrupt(); + if (Timer_Silence >= value) { + status = true; + } + SREG = sreg; + + return status; +} + +void timer_silence_reset(void) +{ + uint8_t sreg; + + sreg = SREG; + __disable_interrupt(); + Timer_Silence = 0; + SREG = sreg; +} diff --git a/bacnet-stack/ports/atmega8/timer.h b/bacnet-stack/ports/atmega8/timer.h new file mode 100644 index 00000000..9e6d207b --- /dev/null +++ b/bacnet-stack/ports/atmega8/timer.h @@ -0,0 +1,42 @@ +/************************************************************************** +* +* Copyright (C) 2007 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. +* +*********************************************************************/ +#ifndef TIMER_H +#define TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void timer_init( + void); + bool timer_silence_elapsed( + uint16_t value); + void timer_silence_reset( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif