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 00000000..6d06047c Binary files /dev/null and b/bacnet-stack/ports/atmega8/hardware.ods differ diff --git a/bacnet-stack/ports/atmega8/iar2gcc.h b/bacnet-stack/ports/atmega8/iar2gcc.h new file mode 100644 index 00000000..f80d7fc8 --- /dev/null +++ b/bacnet-stack/ports/atmega8/iar2gcc.h @@ -0,0 +1,226 @@ +/*####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####*/ +#ifndef IAR2GCC_H +#define IAR2GCC_H + +#if !defined(F_CPU) +#define F_CPU (7372800) +#endif + +/* IAR */ +#if defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ASM__) +#include +#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