From 0c4edb33d9f9ab2b4ec664c53831f3e4c8368aee Mon Sep 17 00:00:00 2001 From: skarg Date: Wed, 13 May 2009 03:46:02 +0000 Subject: [PATCH] Fixed up file indent, comments, and eol-type. --- bacnet-stack/demo/handler/s_router.c | 6 +- bacnet-stack/demo/initrouter/main.c | 3 +- bacnet-stack/demo/object/device.c | 5 +- bacnet-stack/demo/readpropm/main.c | 3 +- bacnet-stack/demo/ucov/main.c | 4 +- bacnet-stack/include/bacenum.h | 2 +- bacnet-stack/include/bo.h | 5 +- bacnet-stack/include/device.h | 7 +- bacnet-stack/ports/at91sam7s/device.c | 2 +- bacnet-stack/ports/atmega168/stack.c | 191 +- bacnet-stack/ports/atmega168/stack.h | 99 +- bacnet-stack/ports/bdk-atxx4-mstp/Makefile | 456 +-- bacnet-stack/ports/bdk-atxx4-mstp/ai.c | 392 +-- bacnet-stack/ports/bdk-atxx4-mstp/bi.c | 464 +-- bacnet-stack/ports/bdk-atxx4-mstp/bo.c | 1055 ++++--- .../ports/bdk-atxx4-mstp/bootloader/defines.h | 92 +- .../ports/bdk-atxx4-mstp/bootloader/main.c | 555 ++-- .../ports/bdk-atxx4-mstp/bootloader/serial.c | 24 +- .../ports/bdk-atxx4-mstp/bootloader/serial.h | 9 +- bacnet-stack/ports/bdk-atxx4-mstp/device.c | 1268 ++++---- bacnet-stack/ports/bdk-atxx4-mstp/dlmstp.c | 2684 ++++++++--------- bacnet-stack/ports/bdk-atxx4-mstp/eeprom.c | 140 +- bacnet-stack/ports/bdk-atxx4-mstp/eeprom.h | 92 +- bacnet-stack/ports/bdk-atxx4-mstp/h_rd.c | 226 +- bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c | 360 +-- bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c | 268 +- bacnet-stack/ports/bdk-atxx4-mstp/hardware.h | 110 +- bacnet-stack/ports/bdk-atxx4-mstp/iar2gcc.h | 478 +-- bacnet-stack/ports/bdk-atxx4-mstp/init.c | 126 +- bacnet-stack/ports/bdk-atxx4-mstp/init.h | 78 +- bacnet-stack/ports/bdk-atxx4-mstp/input.c | 121 +- bacnet-stack/ports/bdk-atxx4-mstp/input.h | 84 +- bacnet-stack/ports/bdk-atxx4-mstp/led.c | 422 +-- bacnet-stack/ports/bdk-atxx4-mstp/led.h | 111 +- bacnet-stack/ports/bdk-atxx4-mstp/main.c | 439 ++- bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h | 264 +- bacnet-stack/ports/bdk-atxx4-mstp/rs485.c | 516 ++-- bacnet-stack/ports/bdk-atxx4-mstp/rs485.h | 131 +- bacnet-stack/ports/bdk-atxx4-mstp/seeprom.c | 850 +++--- bacnet-stack/ports/bdk-atxx4-mstp/seeprom.h | 96 +- bacnet-stack/ports/bdk-atxx4-mstp/serial.c | 350 +-- bacnet-stack/ports/bdk-atxx4-mstp/serial.h | 108 +- bacnet-stack/ports/bdk-atxx4-mstp/stack.c | 157 +- bacnet-stack/ports/bdk-atxx4-mstp/stack.h | 98 +- bacnet-stack/ports/bdk-atxx4-mstp/timer.h | 134 +- bacnet-stack/ports/bdk-atxx4-mstp/timer2.c | 445 +-- bacnet-stack/ports/pic18f6720/device.c | 2 +- bacnet-stack/ports/win32/rs485.c | 16 +- bacnet-stack/src/bacapp.c | 15 +- 49 files changed, 6758 insertions(+), 6805 deletions(-) diff --git a/bacnet-stack/demo/handler/s_router.c b/bacnet-stack/demo/handler/s_router.c index ae2b00e5..872f7099 100644 --- a/bacnet-stack/demo/handler/s_router.c +++ b/bacnet-stack/demo/handler/s_router.c @@ -153,7 +153,7 @@ void Send_Initialize_Routing_Table( BACNET_NPDU_DATA npdu_data; uint8_t number_of_ports = 0; BACNET_ROUTER_PORT *router_port; - uint8_t i = 0; /* counter */ + uint8_t i = 0; /* counter */ npdu_encode_npdu_network(&npdu_data, NETWORK_MESSAGE_INIT_RT_TABLE, true, MESSAGE_PRIORITY_NORMAL); @@ -203,8 +203,8 @@ void Send_Initialize_Routing_Table_Ack( BACNET_ADDRESS dest; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; - - + + /* FIXME: is this parameter needed? */ router_port_list = router_port_list; /* setup packet for sending */ diff --git a/bacnet-stack/demo/initrouter/main.c b/bacnet-stack/demo/initrouter/main.c index 6103488a..71583f48 100644 --- a/bacnet-stack/demo/initrouter/main.c +++ b/bacnet-stack/demo/initrouter/main.c @@ -325,7 +325,8 @@ static void address_parse(BACNET_ADDRESS * dst, dst->mac_len = 6; for (index = 0; index < 4; index++) { dst->mac[index] = mac[index]; - } encode_unsigned16(&dst->mac[4], + } + encode_unsigned16(&dst->mac[4], port); } else { count = diff --git a/bacnet-stack/demo/object/device.c b/bacnet-stack/demo/object/device.c index ca364e64..1f26936b 100644 --- a/bacnet-stack/demo/object/device.c +++ b/bacnet-stack/demo/object/device.c @@ -137,7 +137,7 @@ BACNET_DATE Local_Date; /* rely on OS, if there is one */ If your UTC offset is -5hours of GMT, then BACnet UTC offset is +5hours. BACnet UTC offset is expressed in minutes. */ -static int32_t UTC_Offset = 5*60; +static int32_t UTC_Offset = 5 * 60; static bool Daylight_Savings_Status = false; /* rely on OS */ /* List_Of_Session_Keys */ /* Time_Synchronization_Recipients */ @@ -680,8 +680,7 @@ int Device_Encode_Property_APDU( case PROP_LOCATION: characterstring_init_ansi(&char_string, Location); apdu_len = - encode_application_character_string(&apdu[0], - &char_string); + encode_application_character_string(&apdu[0], &char_string); break; /* FIXME: if you support time */ case PROP_LOCAL_TIME: diff --git a/bacnet-stack/demo/readpropm/main.c b/bacnet-stack/demo/readpropm/main.c index 9aab6228..4368b7d4 100644 --- a/bacnet-stack/demo/readpropm/main.c +++ b/bacnet-stack/demo/readpropm/main.c @@ -230,8 +230,7 @@ void cleanup(void) { old_rpm_property = rpm_property; rpm_property = rpm_property->next; free(old_rpm_property); - } - old_rpm_object = rpm_object; + } old_rpm_object = rpm_object; rpm_object = rpm_object->next; free(old_rpm_object); } diff --git a/bacnet-stack/demo/ucov/main.c b/bacnet-stack/demo/ucov/main.c index 8622b935..c80c5032 100644 --- a/bacnet-stack/demo/ucov/main.c +++ b/bacnet-stack/demo/ucov/main.c @@ -212,8 +212,8 @@ int main(int argc, char *argv[]) { filename_remove_path(argv[0]), filename_remove_path(argv[0])); return 0; } - /* decode the command line parameters */ - cov_data.subscriberProcessIdentifier = strtol(argv[1], NULL, 0); + /* decode the command line parameters */ cov_data. + subscriberProcessIdentifier = strtol(argv[1], NULL, 0); cov_data.initiatingDeviceIdentifier = strtol(argv[2], NULL, 0); cov_data.monitoredObjectIdentifier.type = strtol(argv[3], NULL, 0); cov_data.monitoredObjectIdentifier.instance = strtol(argv[4], NULL, 0); diff --git a/bacnet-stack/include/bacenum.h b/bacnet-stack/include/bacenum.h index 3cca74e0..fe71aecf 100644 --- a/bacnet-stack/include/bacenum.h +++ b/bacnet-stack/include/bacenum.h @@ -396,7 +396,7 @@ typedef enum { BINARY_INACTIVE = 0, BINARY_ACTIVE = 1, MAX_BINARY_PV = 1, /* for validating incoming values */ - BINARY_NULL = 255 /* our homemade way of storing this info */ + BINARY_NULL = 255 /* our homemade way of storing this info */ } BACNET_BINARY_PV; typedef enum { diff --git a/bacnet-stack/include/bo.h b/bacnet-stack/include/bo.h index 4cb90c89..a568ff85 100644 --- a/bacnet-stack/include/bo.h +++ b/bacnet-stack/include/bo.h @@ -35,8 +35,9 @@ extern "C" { #endif /* __cplusplus */ - void Binary_Output_Init(void); - + void Binary_Output_Init( + void); + void Binary_Output_Property_Lists( const int **pRequired, const int **pOptional, diff --git a/bacnet-stack/include/device.h b/bacnet-stack/include/device.h index 6421dd6d..f09c9b7f 100644 --- a/bacnet-stack/include/device.h +++ b/bacnet-stack/include/device.h @@ -44,9 +44,10 @@ extern "C" { #endif /* __cplusplus */ - - void Device_Init(void); - + + void Device_Init( + void); + void Device_Property_Lists( const int **pRequired, const int **pOptional, diff --git a/bacnet-stack/ports/at91sam7s/device.c b/bacnet-stack/ports/at91sam7s/device.c index fad48d34..370a4732 100644 --- a/bacnet-stack/ports/at91sam7s/device.c +++ b/bacnet-stack/ports/at91sam7s/device.c @@ -438,7 +438,7 @@ int Device_Encode_Property_APDU( case PROP_UTC_OFFSET: /* Note: BACnet Time Zone is offset of local time and UTC, rather than offset of GMT. It is expressed in minutes */ - apdu_len = encode_application_signed(&apdu[0], 5*60 /* EST */ ); + apdu_len = encode_application_signed(&apdu[0], 5 * 60 /* EST */ ); break; case PROP_LOCAL_DATE: /* FIXME: if you support date */ diff --git a/bacnet-stack/ports/atmega168/stack.c b/bacnet-stack/ports/atmega168/stack.c index 217e3452..006b9fe3 100644 --- a/bacnet-stack/ports/atmega168/stack.c +++ b/bacnet-stack/ports/atmega168/stack.c @@ -1,94 +1,97 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" - -/* stack checking */ -#if defined(__GNUC__) -extern uint8_t _end; -extern uint8_t __stack; -#endif - -#if defined(__GNUC__) -#define STACK_CANARY (0xC5) -void stack_init( - void) __attribute__ ((naked)) __attribute__ ((section(".init1"))); -#endif - -void stack_init( - void) -{ -#if defined(__GNUC__) -#if 0 - uint8_t *p = &_end; - - while (p <= &__stack) { - *p = STACK_CANARY; - p++; - } -#else - __asm volatile ( - " ldi r30,lo8(_end)\n" " ldi r31,hi8(_end)\n" " ldi r24,lo8(0xc5)\n" /* STACK_CANARY = 0xc5 */ - " ldi r25,hi8(__stack)\n" " rjmp .cmp\n" ".loop:\n" - " st Z+,r24\n" ".cmp:\n" " cpi r30,lo8(__stack)\n" - " cpc r31,r25\n" " brlo .loop\n" " breq .loop"::); -#endif -#endif -} - -unsigned stack_size(void) -{ -#if defined(__GNUC__) - return (&__stack) - (&_end); -#else - return 0; -#endif -} - -uint8_t stack_byte(unsigned offset) -{ -#if defined(__GNUC__) - return *(&_end + offset); -#else - offset = offset; - return 0; -#endif -} - -unsigned stack_unused(void) -{ - unsigned count = 0; -#if defined(__GNUC__) - uint8_t *p = &_end; - - while (p <= &__stack) { - if ((*p) != STACK_CANARY) { - count = p - (&_end); - break; - } - p++; - } -#endif - return count; -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" + +/* stack checking */ +#if defined(__GNUC__) +extern uint8_t _end; +extern uint8_t __stack; +#endif + +#if defined(__GNUC__) +#define STACK_CANARY (0xC5) +void stack_init( + void) __attribute__ ((naked)) __attribute__ ((section(".init1"))); +#endif + +void stack_init( + void) +{ +#if defined(__GNUC__) +#if 0 + uint8_t *p = &_end; + + while (p <= &__stack) { + *p = STACK_CANARY; + p++; + } +#else + __asm volatile ( + " ldi r30,lo8(_end)\n" " ldi r31,hi8(_end)\n" " ldi r24,lo8(0xc5)\n" /* STACK_CANARY = 0xc5 */ + " ldi r25,hi8(__stack)\n" " rjmp .cmp\n" ".loop:\n" + " st Z+,r24\n" ".cmp:\n" " cpi r30,lo8(__stack)\n" + " cpc r31,r25\n" " brlo .loop\n" " breq .loop"::); +#endif +#endif +} + +unsigned stack_size( + void) +{ +#if defined(__GNUC__) + return (&__stack) - (&_end); +#else + return 0; +#endif +} + +uint8_t stack_byte( + unsigned offset) +{ +#if defined(__GNUC__) + return *(&_end + offset); +#else + offset = offset; + return 0; +#endif +} + +unsigned stack_unused( + void) +{ + unsigned count = 0; +#if defined(__GNUC__) + uint8_t *p = &_end; + + while (p <= &__stack) { + if ((*p) != STACK_CANARY) { + count = p - (&_end); + break; + } + p++; + } +#endif + return count; +} diff --git a/bacnet-stack/ports/atmega168/stack.h b/bacnet-stack/ports/atmega168/stack.h index cf97bb7f..a306317d 100644 --- a/bacnet-stack/ports/atmega168/stack.h +++ b/bacnet-stack/ports/atmega168/stack.h @@ -1,48 +1,51 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 STACK_H -#define STACK_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - /* C stack checking */ - void stack_init(void); - - unsigned stack_size(void); - - uint8_t stack_byte(unsigned offset); - - unsigned stack_unused(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif - \ No newline at end of file +/************************************************************************** +* +* Copyright (C) 2009 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 STACK_H +#define STACK_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + /* C stack checking */ + void stack_init( + void); + + unsigned stack_size( + void); + + uint8_t stack_byte( + unsigned offset); + + unsigned stack_unused( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/Makefile b/bacnet-stack/ports/bdk-atxx4-mstp/Makefile index cdcfab47..0734334a 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/Makefile +++ b/bacnet-stack/ports/bdk-atxx4-mstp/Makefile @@ -1,229 +1,229 @@ -############################################################################### -# Makefile for LM Room Controller - AVR -############################################################################### - -## General Flags -MCU = atmega644p -AVRDUDE_MCU = m644p -# ATmega644 bootload is at word address 7000h, 7800h, 7C00h, or 7E00h -# Double that value to get the byte address -BOOTLOAD = 0xF800 -TARGET = bacnet -## Tools -CC = avr-gcc -AR = avr-ar -OBJCOPY = avr-objcopy -OBJDUMP = avr-objdump -SIZE = avr-size -AVRDUDE = avrdude -LINT = splint - -# programmer id--check the avrdude for complete list -# of available opts. These should include stk500, -# avr910, avrisp, bsd, pony and more. Set this to -# one of the valid "-c PROGRAMMER-ID" values -# described in the avrdude info page. -# jtag2fast = Atmel JTAG ICE mkII, running at 115200 Bd +############################################################################### +# Makefile for LM Room Controller - AVR +############################################################################### + +## General Flags +MCU = atmega644p +AVRDUDE_MCU = m644p +# ATmega644 bootload is at word address 7000h, 7800h, 7C00h, or 7E00h +# Double that value to get the byte address +BOOTLOAD = 0xF800 +TARGET = bacnet +## Tools +CC = avr-gcc +AR = avr-ar +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AVRDUDE = avrdude +LINT = splint + +# programmer id--check the avrdude for complete list +# of available opts. These should include stk500, +# avr910, avrisp, bsd, pony and more. Set this to +# one of the valid "-c PROGRAMMER-ID" values +# described in the avrdude info page. +# jtag2fast = Atmel JTAG ICE mkII, running at 115200 Bd # jtag2slow = Atmel JTAG ICE mkII, running at 19200 Bd -# avrispmkII = AVR ISP MKII -AVRDUDE_PROGRAMMERID = avrispmkII -# -# # port--serial or parallel port to which your -# # hardware programmer is attached -# # usb can just be usb -AVRDUDE_PORT = usb - -# Source locations -BACNET_CORE = ../../src -BACNET_INCLUDE = ../../include -BACNET_DEMO = ../../demo - -# local files for this project -CSRC = main.c \ - init.c \ - stack.c \ - input.c \ - serial.c \ - rs485.c \ - timer2.c \ - led.c \ - eeprom.c \ - seeprom.c \ - dlmstp.c \ - h_wp.c \ - h_rp.c \ - h_rpm.c \ - h_rd.c \ - device.c \ - ai.c \ - bi.c \ - bo.c - -# common demo files needed -DEMOSRC = $(BACNET_DEMO)/handler/txbuf.c \ - $(BACNET_DEMO)/handler/h_npdu.c \ - $(BACNET_DEMO)/handler/h_whois.c \ - $(BACNET_DEMO)/handler/h_dcc.c \ - $(BACNET_DEMO)/handler/s_iam.c \ - $(BACNET_DEMO)/handler/noserv.c - -# core BACnet stack files -CORESRC = \ - $(BACNET_CORE)/fifo.c \ - $(BACNET_CORE)/memcopy.c \ - $(BACNET_CORE)/crc.c \ - $(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)/iam.c \ - $(BACNET_CORE)/dcc.c \ - $(BACNET_CORE)/rp.c \ - $(BACNET_CORE)/rd.c \ - $(BACNET_CORE)/rpm.c \ - $(BACNET_CORE)/wp.c \ - $(BACNET_CORE)/whois.c \ - $(BACNET_CORE)/bacaddr.c \ - $(BACNET_CORE)/abort.c \ - $(BACNET_CORE)/reject.c \ - $(BACNET_CORE)/bacerror.c \ - $(BACNET_CORE)/bacapp.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)/iam/iam_client.c \ -# $(BACNET_CORE)/ihave.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-called-once -# default optimization is for debugging from AVR Studio -OPTIMIZATION = -O0 -#OPTIMIZATION = -Os $(OPTIMIZE_FLAGS) -DEBUGGING = -g -# define something from the Makefile or batch file -DEFINES = - -## Compile options common for all C compilation units. -BFLAGS = -DBACDL_MSTP -BFLAGS += -DMAX_APDU=128 -BFLAGS += -DBIG_ENDIAN=0 -BFLAGS += -DMAX_TSM_TRANSACTIONS=0 -#BFLAGS += -DCRC_USE_TABLE -BFLAGS += -DBACAPP_BOOLEAN -BFLAGS += -DBACAPP_REAL -BFLAGS += -DBACAPP_OBJECT_ID -BFLAGS += -DBACAPP_UNSIGNED -BFLAGS += -DBACAPP_ENUMERATED -BFLAGS += -DBACAPP_CHARACTER_STRING -BFLAGS += -DWRITE_PROPERTY -CFLAGS = $(COMMON) -CFLAGS += $(DEFINES) -CFLAGS += $(DEBUGGING) -# 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,--section-start=.bootloader=$(BOOTLOAD) -LDFLAGS += -Wl,-Map=$(TARGET).map -LDFLAGS += -Wl,-L=.,-l$(TARGET) - -## Intel Hex file production flags -HEX_FLASH_FLAGS = -R .eeprom -R .fuse -R .lock -R .signature -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) - -## 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) - -%.o: %.c - $(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@ - -size: ${TARGET_ELF} - @echo - @${SIZE} ${TARGET_ELF} - -lint: - $(LINT) $(BFLAGS) $(CSRC) - -install: $(TARGET_ELF) - $(AVRDUDE) -c $(AVRDUDE_PROGRAMMERID) \ - -p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -e \ - -U flash:w:$(TARGET).hex - -## 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/*) +# avrispmkII = AVR ISP MKII +AVRDUDE_PROGRAMMERID = avrispmkII +# +# # port--serial or parallel port to which your +# # hardware programmer is attached +# # usb can just be usb +AVRDUDE_PORT = usb + +# Source locations +BACNET_CORE = ../../src +BACNET_INCLUDE = ../../include +BACNET_DEMO = ../../demo + +# local files for this project +CSRC = main.c \ + init.c \ + stack.c \ + input.c \ + serial.c \ + rs485.c \ + timer2.c \ + led.c \ + eeprom.c \ + seeprom.c \ + dlmstp.c \ + h_wp.c \ + h_rp.c \ + h_rpm.c \ + h_rd.c \ + device.c \ + ai.c \ + bi.c \ + bo.c + +# common demo files needed +DEMOSRC = $(BACNET_DEMO)/handler/txbuf.c \ + $(BACNET_DEMO)/handler/h_npdu.c \ + $(BACNET_DEMO)/handler/h_whois.c \ + $(BACNET_DEMO)/handler/h_dcc.c \ + $(BACNET_DEMO)/handler/s_iam.c \ + $(BACNET_DEMO)/handler/noserv.c + +# core BACnet stack files +CORESRC = \ + $(BACNET_CORE)/fifo.c \ + $(BACNET_CORE)/memcopy.c \ + $(BACNET_CORE)/crc.c \ + $(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)/iam.c \ + $(BACNET_CORE)/dcc.c \ + $(BACNET_CORE)/rp.c \ + $(BACNET_CORE)/rd.c \ + $(BACNET_CORE)/rpm.c \ + $(BACNET_CORE)/wp.c \ + $(BACNET_CORE)/whois.c \ + $(BACNET_CORE)/bacaddr.c \ + $(BACNET_CORE)/abort.c \ + $(BACNET_CORE)/reject.c \ + $(BACNET_CORE)/bacerror.c \ + $(BACNET_CORE)/bacapp.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)/iam/iam_client.c \ +# $(BACNET_CORE)/ihave.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-called-once +# default optimization is for debugging from AVR Studio +OPTIMIZATION = -O0 +#OPTIMIZATION = -Os $(OPTIMIZE_FLAGS) +DEBUGGING = -g +# define something from the Makefile or batch file +DEFINES = + +## Compile options common for all C compilation units. +BFLAGS = -DBACDL_MSTP +BFLAGS += -DMAX_APDU=128 +BFLAGS += -DBIG_ENDIAN=0 +BFLAGS += -DMAX_TSM_TRANSACTIONS=0 +#BFLAGS += -DCRC_USE_TABLE +BFLAGS += -DBACAPP_BOOLEAN +BFLAGS += -DBACAPP_REAL +BFLAGS += -DBACAPP_OBJECT_ID +BFLAGS += -DBACAPP_UNSIGNED +BFLAGS += -DBACAPP_ENUMERATED +BFLAGS += -DBACAPP_CHARACTER_STRING +BFLAGS += -DWRITE_PROPERTY +CFLAGS = $(COMMON) +CFLAGS += $(DEFINES) +CFLAGS += $(DEBUGGING) +# 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,--section-start=.bootloader=$(BOOTLOAD) +LDFLAGS += -Wl,-Map=$(TARGET).map +LDFLAGS += -Wl,-L=.,-l$(TARGET) + +## Intel Hex file production flags +HEX_FLASH_FLAGS = -R .eeprom -R .fuse -R .lock -R .signature +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) + +## 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) + +%.o: %.c + $(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@ + +size: ${TARGET_ELF} + @echo + @${SIZE} ${TARGET_ELF} + +lint: + $(LINT) $(BFLAGS) $(CSRC) + +install: $(TARGET_ELF) + $(AVRDUDE) -c $(AVRDUDE_PROGRAMMERID) \ + -p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -e \ + -U flash:w:$(TARGET).hex + +## 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/bdk-atxx4-mstp/ai.c b/bacnet-stack/ports/bdk-atxx4-mstp/ai.c index b3d36c2b..4edda3a2 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/ai.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/ai.c @@ -1,196 +1,196 @@ -/************************************************************************** -* -* 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 */ -#define MAX_ANALOG_INPUTS 2 -#if (MAX_ANALOG_INPUTS > 9) -#error Modify the Analog_Input_Name to handle multiple digits -#endif - -/* These three arrays are used by the ReadPropertyMultiple handler */ -static const int Analog_Input_Properties_Required[] = { - PROP_OBJECT_IDENTIFIER, - PROP_OBJECT_NAME, - PROP_OBJECT_TYPE, - PROP_PRESENT_VALUE, - PROP_STATUS_FLAGS, - PROP_EVENT_STATE, - PROP_OUT_OF_SERVICE, - PROP_UNITS, - -1 -}; - -static const int Analog_Input_Properties_Optional[] = { - PROP_DESCRIPTION, - -1 -}; - -static const int Analog_Input_Properties_Proprietary[] = { - -1 -}; - -void Analog_Input_Property_Lists( - const int **pRequired, - const int **pOptional, - const int **pProprietary) -{ - if (pRequired) - *pRequired = Analog_Input_Properties_Required; - if (pOptional) - *pOptional = Analog_Input_Properties_Optional; - if (pProprietary) - *pProprietary = Analog_Input_Properties_Proprietary; - - return; -} - -static uint8_t 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; -} - -char *Analog_Input_Name( - uint32_t object_instance) -{ - static char text_string[16] = "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; -} - -static float Analog_Input_Present_Value( - uint32_t object_instance) -{ - float value = 0.0; - - if (object_instance < MAX_ANALOG_INPUTS) - value = Present_Value[object_instance]; - - return value; -} - -/* 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; - - (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 */ - 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: - apdu_len = - encode_application_real(&apdu[0], - Analog_Input_Present_Value(object_instance)); - 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; -} +/************************************************************************** +* +* 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 */ +#define MAX_ANALOG_INPUTS 2 +#if (MAX_ANALOG_INPUTS > 9) +#error Modify the Analog_Input_Name to handle multiple digits +#endif + +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Analog_Input_Properties_Required[] = { + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_UNITS, + -1 +}; + +static const int Analog_Input_Properties_Optional[] = { + PROP_DESCRIPTION, + -1 +}; + +static const int Analog_Input_Properties_Proprietary[] = { + -1 +}; + +void Analog_Input_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (pRequired) + *pRequired = Analog_Input_Properties_Required; + if (pOptional) + *pOptional = Analog_Input_Properties_Optional; + if (pProprietary) + *pProprietary = Analog_Input_Properties_Proprietary; + + return; +} + +static uint8_t 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; +} + +char *Analog_Input_Name( + uint32_t object_instance) +{ + static char text_string[16] = "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; +} + +static float Analog_Input_Present_Value( + uint32_t object_instance) +{ + float value = 0.0; + + if (object_instance < MAX_ANALOG_INPUTS) + value = Present_Value[object_instance]; + + return value; +} + +/* 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; + + (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 */ + 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: + apdu_len = + encode_application_real(&apdu[0], + Analog_Input_Present_Value(object_instance)); + 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/bdk-atxx4-mstp/bi.c b/bacnet-stack/ports/bdk-atxx4-mstp/bi.c index 37421245..876996bb 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bi.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bi.c @@ -1,232 +1,232 @@ -/************************************************************************** -* -* 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 Input Objects customize for your use */ - -#include -#include -#include -#include "bacdef.h" -#include "bacdcode.h" -#include "bacenum.h" -#include "config.h" - -#define MAX_BINARY_INPUTS 8 -#if (MAX_BINARY_INPUTS > 9) -#error Modify the Binary_Input_Name to handle multiple digits -#endif - -static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS]; - -/* These three arrays are used by the ReadPropertyMultiple handler */ -static const int Binary_Input_Properties_Required[] = { - PROP_OBJECT_IDENTIFIER, - PROP_OBJECT_NAME, - PROP_OBJECT_TYPE, - PROP_PRESENT_VALUE, - PROP_STATUS_FLAGS, - PROP_EVENT_STATE, - PROP_OUT_OF_SERVICE, - PROP_POLARITY, - -1 -}; - -static const int Binary_Input_Properties_Optional[] = { - PROP_DESCRIPTION, - -1 -}; - -static const int Binary_Input_Properties_Proprietary[] = { - -1 -}; - -void Binary_Input_Property_Lists( - const int **pRequired, - const int **pOptional, - const int **pProprietary) -{ - if (pRequired) { - *pRequired = Binary_Input_Properties_Required; - } - if (pOptional) { - *pOptional = Binary_Input_Properties_Optional; - } - if (pProprietary) { - *pProprietary = Binary_Input_Properties_Proprietary; - } - - return; -} - -static void Binary_Input_Initialize( - void) -{ - static bool initialized = false; - unsigned i; - - if (!initialized) { - initialized = true; - for (i = 0; i < MAX_BINARY_INPUTS; i++) { - Present_Value[i] = BINARY_INACTIVE; - } - } -} - -/* we simply have 0-n object instances. */ -bool Binary_Input_Valid_Instance( - uint32_t object_instance) -{ - if (object_instance < MAX_BINARY_INPUTS) - return true; - - return false; -} - -/* we simply have 0-n object instances. */ -unsigned Binary_Input_Count( - void) -{ - return MAX_BINARY_INPUTS; -} - -/* we simply have 0-n object instances.*/ -uint32_t Binary_Input_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 Binary_Input_Instance_To_Index( - uint32_t object_instance) -{ - unsigned index = MAX_BINARY_INPUTS; - - if (object_instance < MAX_BINARY_INPUTS) - index = object_instance; - - return index; -} - -static BACNET_BINARY_PV Binary_Input_Present_Value( - uint32_t object_instance) -{ - BACNET_BINARY_PV value = BINARY_INACTIVE; - unsigned index = 0; - - Binary_Input_Initialize(); - index = Binary_Input_Instance_To_Index(object_instance); - if (index < MAX_BINARY_INPUTS) { - value = Present_Value[index]; - } - - return value; -} - -char *Binary_Input_Name( - uint32_t object_instance) -{ - static char text_string[16] = "BI-0"; /* okay for single thread */ - - if (object_instance < MAX_BINARY_INPUTS) { - text_string[3] = '0' + (uint8_t) object_instance; - return text_string; - } - - return NULL; -} - -/* return apdu length, or -1 on error */ -/* assumption - object already exists, and has been bounds checked */ -int Binary_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; - BACNET_POLARITY polarity = POLARITY_NORMAL; - BACNET_BINARY_PV value = BINARY_INACTIVE; - - - (void) array_index; - Binary_Input_Initialize(); - switch (property) { - case PROP_OBJECT_IDENTIFIER: - apdu_len = - encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT, - object_instance); - break; - case PROP_OBJECT_NAME: - case PROP_DESCRIPTION: - /* note: object name must be unique in our device */ - characterstring_init_ansi(&char_string, - Binary_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_BINARY_INPUT); - break; - case PROP_PRESENT_VALUE: - value = Binary_Input_Present_Value(object_instance); - apdu_len = encode_application_enumerated(&apdu[0], 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: - 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; -} +/************************************************************************** +* +* 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 Input Objects customize for your use */ + +#include +#include +#include +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "config.h" + +#define MAX_BINARY_INPUTS 8 +#if (MAX_BINARY_INPUTS > 9) +#error Modify the Binary_Input_Name to handle multiple digits +#endif + +static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS]; + +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Binary_Input_Properties_Required[] = { + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_POLARITY, + -1 +}; + +static const int Binary_Input_Properties_Optional[] = { + PROP_DESCRIPTION, + -1 +}; + +static const int Binary_Input_Properties_Proprietary[] = { + -1 +}; + +void Binary_Input_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (pRequired) { + *pRequired = Binary_Input_Properties_Required; + } + if (pOptional) { + *pOptional = Binary_Input_Properties_Optional; + } + if (pProprietary) { + *pProprietary = Binary_Input_Properties_Proprietary; + } + + return; +} + +static void Binary_Input_Initialize( + void) +{ + static bool initialized = false; + unsigned i; + + if (!initialized) { + initialized = true; + for (i = 0; i < MAX_BINARY_INPUTS; i++) { + Present_Value[i] = BINARY_INACTIVE; + } + } +} + +/* we simply have 0-n object instances. */ +bool Binary_Input_Valid_Instance( + uint32_t object_instance) +{ + if (object_instance < MAX_BINARY_INPUTS) + return true; + + return false; +} + +/* we simply have 0-n object instances. */ +unsigned Binary_Input_Count( + void) +{ + return MAX_BINARY_INPUTS; +} + +/* we simply have 0-n object instances.*/ +uint32_t Binary_Input_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 Binary_Input_Instance_To_Index( + uint32_t object_instance) +{ + unsigned index = MAX_BINARY_INPUTS; + + if (object_instance < MAX_BINARY_INPUTS) + index = object_instance; + + return index; +} + +static BACNET_BINARY_PV Binary_Input_Present_Value( + uint32_t object_instance) +{ + BACNET_BINARY_PV value = BINARY_INACTIVE; + unsigned index = 0; + + Binary_Input_Initialize(); + index = Binary_Input_Instance_To_Index(object_instance); + if (index < MAX_BINARY_INPUTS) { + value = Present_Value[index]; + } + + return value; +} + +char *Binary_Input_Name( + uint32_t object_instance) +{ + static char text_string[16] = "BI-0"; /* okay for single thread */ + + if (object_instance < MAX_BINARY_INPUTS) { + text_string[3] = '0' + (uint8_t) object_instance; + return text_string; + } + + return NULL; +} + +/* return apdu length, or -1 on error */ +/* assumption - object already exists, and has been bounds checked */ +int Binary_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; + BACNET_POLARITY polarity = POLARITY_NORMAL; + BACNET_BINARY_PV value = BINARY_INACTIVE; + + + (void) array_index; + Binary_Input_Initialize(); + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = + encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT, + object_instance); + break; + case PROP_OBJECT_NAME: + case PROP_DESCRIPTION: + /* note: object name must be unique in our device */ + characterstring_init_ansi(&char_string, + Binary_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_BINARY_INPUT); + break; + case PROP_PRESENT_VALUE: + value = Binary_Input_Present_Value(object_instance); + apdu_len = encode_application_enumerated(&apdu[0], 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: + 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; +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bo.c b/bacnet-stack/ports/bdk-atxx4-mstp/bo.c index 1cb91ba8..28171ea2 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bo.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bo.c @@ -1,534 +1,521 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 Output Objects - customize for your use */ - -#include -#include -#include -#include "bacdef.h" -#include "bacdcode.h" -#include "bacenum.h" -#include "config.h" /* the custom stuff */ -#include "wp.h" -#include "led.h" -#include "nvdata.h" - -#define MAX_BINARY_OUTPUTS 2 -#if (MAX_BINARY_OUTPUTS > 9) -#error Modify the Binary_Output_Name to handle multiple digits -#endif - -/* When all the priorities are level null, the present value returns */ -/* the Relinquish Default value */ -#define RELINQUISH_DEFAULT BINARY_INACTIVE -/* Here is our Priority Array.*/ -static uint8_t - Binary_Output_Level[MAX_BINARY_OUTPUTS][BACNET_MAX_PRIORITY]; -/* Writable out-of-service allows others to play with our Present Value */ -/* without changing the physical output */ -static uint8_t Out_Of_Service[MAX_BINARY_OUTPUTS]; -/* polarity - normal or inverse */ -static uint8_t Polarity[MAX_BINARY_OUTPUTS]; - -/* These three arrays are used by the ReadPropertyMultiple handler */ -static const int Binary_Output_Properties_Required[] = { - PROP_OBJECT_IDENTIFIER, - PROP_OBJECT_NAME, - PROP_OBJECT_TYPE, - PROP_PRESENT_VALUE, - PROP_STATUS_FLAGS, - PROP_EVENT_STATE, - PROP_OUT_OF_SERVICE, - PROP_POLARITY, - PROP_PRIORITY_ARRAY, - PROP_RELINQUISH_DEFAULT, - -1 -}; - -static const int Binary_Output_Properties_Optional[] = { - PROP_DESCRIPTION, - PROP_ACTIVE_TEXT, - PROP_INACTIVE_TEXT, - -1 -}; - -static const int Binary_Output_Properties_Proprietary[] = { - -1 -}; - -void Binary_Output_Property_Lists( - const int **pRequired, - const int **pOptional, - const int **pProprietary) -{ - if (pRequired) - *pRequired = Binary_Output_Properties_Required; - if (pOptional) - *pOptional = Binary_Output_Properties_Optional; - if (pProprietary) - *pProprietary = Binary_Output_Properties_Proprietary; - - return; -} - -void Binary_Output_Level_Set( - unsigned int object_index, - unsigned int priority, - BACNET_BINARY_PV level) -{ - if (object_index < MAX_BINARY_OUTPUTS) { - if (priority < BACNET_MAX_PRIORITY) { - Binary_Output_Level[object_index][priority] = (uint8_t)level; - seeprom_bytes_write( - NV_SEEPROM_BINARY_OUTPUT(object_index, - NV_SEEPROM_BO_PRIORITY_ARRAY_1+priority), - &Binary_Output_Level[object_index][priority], - 1); - } - } -} - -void Binary_Output_Polarity_Set( - unsigned int object_index, - BACNET_POLARITY polarity) -{ - if (object_index < MAX_BINARY_OUTPUTS) { - if (polarity < MAX_POLARITY) { - Polarity[object_index] = POLARITY_NORMAL; - seeprom_bytes_write( - NV_SEEPROM_BINARY_OUTPUT(object_index, - NV_SEEPROM_BO_POLARITY), - &Polarity[object_index], - 1); - } - } -} - -void Binary_Output_Out_Of_Service_Set( - unsigned int object_index, - bool flag) -{ - if (object_index < MAX_BINARY_OUTPUTS) { - Out_Of_Service[object_index] = flag; - seeprom_bytes_write( - NV_SEEPROM_BINARY_OUTPUT(object_index, - NV_SEEPROM_BO_OUT_OF_SERVICE), - &Out_Of_Service[object_index], - 1); - } -} - -/* we simply have 0-n object instances. */ -bool Binary_Output_Valid_Instance( - uint32_t object_instance) -{ - if (object_instance < MAX_BINARY_OUTPUTS) - return true; - - return false; -} - -/* we simply have 0-n object instances. */ -unsigned Binary_Output_Count( - void) -{ - return MAX_BINARY_OUTPUTS; -} - -/* we simply have 0-n object instances. */ -uint32_t Binary_Output_Index_To_Instance( - unsigned index) -{ - return index; -} - -/* we simply have 0-n object instances. */ -unsigned Binary_Output_Instance_To_Index( - uint32_t object_instance) -{ - unsigned index = MAX_BINARY_OUTPUTS; - - if (object_instance < MAX_BINARY_OUTPUTS) - index = object_instance; - - return index; -} - -static BACNET_BINARY_PV Binary_Output_Present_Value( - uint32_t object_instance) -{ - BACNET_BINARY_PV value = RELINQUISH_DEFAULT; - BACNET_BINARY_PV current_value = RELINQUISH_DEFAULT; - unsigned index = 0; - unsigned i = 0; - - index = Binary_Output_Instance_To_Index(object_instance); - if (index < MAX_BINARY_OUTPUTS) { - for (i = 0; i < BACNET_MAX_PRIORITY; i++) { - current_value = Binary_Output_Level[index][i]; - if (current_value != BINARY_NULL) { - value = Binary_Output_Level[index][i]; - break; - } - } - } - - return value; -} - -static void Binary_Output_Sync( - uint32_t object_instance) -{ - BACNET_BINARY_PV pv = Binary_Output_Present_Value(object_instance); - unsigned index = Binary_Output_Instance_To_Index(object_instance); - - if (index < MAX_BINARY_OUTPUTS) { - if (Out_Of_Service[index]) { - return; - } - if (Polarity[index] == POLARITY_REVERSE) { - if (pv == BINARY_INACTIVE) { - pv = BINARY_ACTIVE; - } else if (pv == BINARY_ACTIVE) { - pv = BINARY_INACTIVE; - } - } - switch (index) { - case 0: - if (pv == BINARY_INACTIVE) { - led_off(LED_3); - } else if (pv == BINARY_ACTIVE) { - led_on(LED_3); - } - break; - case 1: - if (pv == BINARY_INACTIVE) { - led_off(LED_4); - } else if (pv == BINARY_ACTIVE) { - led_on(LED_4); - } - break; - default: - break; - } - } -} - -/* note: the object name must be unique within this device */ -char *Binary_Output_Name( - uint32_t object_instance) -{ - static char text_string[16] = "BV-0"; /* okay for single thread */ - - if (object_instance < MAX_BINARY_OUTPUTS) { - text_string[3] = '0' + (uint8_t) object_instance; - return text_string; - } - - return NULL; -} - -/* return apdu len, or -1 on error */ -int Binary_Output_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 len = 0; - int apdu_len = 0; /* return value */ - BACNET_BIT_STRING bit_string; - BACNET_CHARACTER_STRING char_string; - BACNET_BINARY_PV present_value = BINARY_INACTIVE; - unsigned object_index = 0; - unsigned i = 0; - bool state = false; - - switch (property) { - case PROP_OBJECT_IDENTIFIER: - apdu_len = - encode_application_object_id(&apdu[0], OBJECT_BINARY_OUTPUT, - 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: - case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string, - Binary_Output_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_OUTPUT); - break; - case PROP_PRESENT_VALUE: - present_value = Binary_Output_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: - object_index = Binary_Output_Instance_To_Index(object_instance); - state = Out_Of_Service[object_index]; - apdu_len = encode_application_boolean(&apdu[0], state); - break; - case PROP_POLARITY: - apdu_len = encode_application_enumerated(&apdu[0], - Polarity[object_index]); - break; - case PROP_PRIORITY_ARRAY: - /* Array element zero is the number of elements in the array */ - if (array_index == 0) - apdu_len = - encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. */ - else if (array_index == BACNET_ARRAY_ALL) { - object_index = - Binary_Output_Instance_To_Index(object_instance); - for (i = 0; i < BACNET_MAX_PRIORITY; i++) { - /* FIXME: check if we have room before adding it to APDU */ - present_value = Binary_Output_Level[object_index][i]; - if (present_value == BINARY_NULL) { - len = encode_application_null(&apdu[apdu_len]); - } else { - len = - encode_application_enumerated(&apdu[apdu_len], - present_value); - } - /* add it if we have room */ - if ((apdu_len + len) < MAX_APDU) - apdu_len += len; - else { - *error_class = ERROR_CLASS_SERVICES; - *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; - apdu_len = -1; - break; - } - } - } else { - object_index = - Binary_Output_Instance_To_Index(object_instance); - if (array_index <= BACNET_MAX_PRIORITY) { - present_value = - Binary_Output_Level[object_index][array_index]; - if (present_value == BINARY_NULL) { - len = encode_application_null(&apdu[apdu_len]); - } else { - len = - encode_application_enumerated(&apdu[apdu_len], - present_value); - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = -1; - } - } - - break; - case PROP_RELINQUISH_DEFAULT: - present_value = RELINQUISH_DEFAULT; - apdu_len = encode_application_enumerated(&apdu[0], present_value); - break; - case PROP_ACTIVE_TEXT: - characterstring_init_ansi(&char_string, "on"); - apdu_len = - encode_application_character_string(&apdu[0], &char_string); - break; - case PROP_INACTIVE_TEXT: - characterstring_init_ansi(&char_string, "off"); - apdu_len = - encode_application_character_string(&apdu[0], &char_string); - 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_Output_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; - unsigned int priority = 0; - BACNET_BINARY_PV level = BINARY_NULL; - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; - - object_index = Binary_Output_Instance_To_Index(wp_data->object_instance); - if (object_index >= MAX_BINARY_OUTPUTS) { - *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) { - priority = wp_data->priority; - /* Command priority 6 is reserved for use by Minimum On/Off - algorithm and may not be used for other purposes in any - object. */ - if (priority && (priority <= BACNET_MAX_PRIORITY) && - (priority != 6 /* reserved */ ) && - (value.type.Enumerated <= MAX_BINARY_PV)) { - level = (BACNET_BINARY_PV) value.type.Enumerated; - priority--; - Binary_Output_Level_Set(object_index, priority,level); - Binary_Output_Sync(wp_data->object_instance); - status = true; - } else if (priority == 6) { - /* Command priority 6 is reserved for use by Minimum On/Off - algorithm and may not be used for other purposes in any - object. */ - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else if (value.tag == BACNET_APPLICATION_TAG_NULL) { - level = BINARY_NULL; - priority = wp_data->priority; - if (priority && (priority <= BACNET_MAX_PRIORITY)) { - priority--; - Binary_Output_Level_Set(object_index, priority,level); - Binary_Output_Sync(wp_data->object_instance); - status = true; - } else if (priority == 6) { - /* Command priority 6 is reserved for use by Minimum On/Off - algorithm and may not be used for other purposes in any - object. */ - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } 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; - case PROP_OUT_OF_SERVICE: - if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { - Binary_Output_Out_Of_Service_Set(object_index, - value.type.Boolean); - Binary_Output_Sync(wp_data->object_instance); - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - case PROP_POLARITY: - if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) { - if (value.type.Enumerated < MAX_POLARITY) { - Binary_Output_Polarity_Set(object_index, - value.type.Enumerated); - Binary_Output_Sync(wp_data->object_instance); - 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; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - break; - } - - return status; -} - -void Binary_Output_Init( - void) -{ - unsigned i, j; - - /* initialize all the analog output priority arrays to NULL */ - for (i = 0; i < MAX_BINARY_OUTPUTS; i++) { - seeprom_bytes_read( - NV_SEEPROM_BINARY_OUTPUT(i,NV_SEEPROM_BO_POLARITY), - &Polarity[i], - 1); - if (Polarity[i] >= MAX_POLARITY) { - Binary_Output_Polarity_Set(i, POLARITY_NORMAL); - } - seeprom_bytes_read( - NV_SEEPROM_BINARY_OUTPUT(i,NV_SEEPROM_BO_OUT_OF_SERVICE), - &Out_Of_Service[i], - 1); - if (Out_Of_Service[i] > 1) { - Binary_Output_Out_Of_Service_Set(i, false); - } - for (j = 0; j < BACNET_MAX_PRIORITY; j++) { - seeprom_bytes_read( - NV_SEEPROM_BINARY_OUTPUT(i, - NV_SEEPROM_BO_PRIORITY_ARRAY_1+j), - &Binary_Output_Level[i][j], - 1); - } - Binary_Output_Sync(i); - } - - return; -} +/************************************************************************** +* +* Copyright (C) 2009 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 Output Objects - customize for your use */ + +#include +#include +#include +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "config.h" /* the custom stuff */ +#include "wp.h" +#include "led.h" +#include "nvdata.h" + +#define MAX_BINARY_OUTPUTS 2 +#if (MAX_BINARY_OUTPUTS > 9) +#error Modify the Binary_Output_Name to handle multiple digits +#endif + +/* When all the priorities are level null, the present value returns */ +/* the Relinquish Default value */ +#define RELINQUISH_DEFAULT BINARY_INACTIVE +/* Here is our Priority Array.*/ +static uint8_t Binary_Output_Level[MAX_BINARY_OUTPUTS][BACNET_MAX_PRIORITY]; +/* Writable out-of-service allows others to play with our Present Value */ +/* without changing the physical output */ +static uint8_t Out_Of_Service[MAX_BINARY_OUTPUTS]; +/* polarity - normal or inverse */ +static uint8_t Polarity[MAX_BINARY_OUTPUTS]; + +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Binary_Output_Properties_Required[] = { + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_POLARITY, + PROP_PRIORITY_ARRAY, + PROP_RELINQUISH_DEFAULT, + -1 +}; + +static const int Binary_Output_Properties_Optional[] = { + PROP_DESCRIPTION, + PROP_ACTIVE_TEXT, + PROP_INACTIVE_TEXT, + -1 +}; + +static const int Binary_Output_Properties_Proprietary[] = { + -1 +}; + +void Binary_Output_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (pRequired) + *pRequired = Binary_Output_Properties_Required; + if (pOptional) + *pOptional = Binary_Output_Properties_Optional; + if (pProprietary) + *pProprietary = Binary_Output_Properties_Proprietary; + + return; +} + +void Binary_Output_Level_Set( + unsigned int object_index, + unsigned int priority, + BACNET_BINARY_PV level) +{ + if (object_index < MAX_BINARY_OUTPUTS) { + if (priority < BACNET_MAX_PRIORITY) { + Binary_Output_Level[object_index][priority] = (uint8_t) level; + seeprom_bytes_write(NV_SEEPROM_BINARY_OUTPUT(object_index, + NV_SEEPROM_BO_PRIORITY_ARRAY_1 + priority), + &Binary_Output_Level[object_index][priority], 1); + } + } +} + +void Binary_Output_Polarity_Set( + unsigned int object_index, + BACNET_POLARITY polarity) +{ + if (object_index < MAX_BINARY_OUTPUTS) { + if (polarity < MAX_POLARITY) { + Polarity[object_index] = POLARITY_NORMAL; + seeprom_bytes_write(NV_SEEPROM_BINARY_OUTPUT(object_index, + NV_SEEPROM_BO_POLARITY), &Polarity[object_index], 1); + } + } +} + +void Binary_Output_Out_Of_Service_Set( + unsigned int object_index, + bool flag) +{ + if (object_index < MAX_BINARY_OUTPUTS) { + Out_Of_Service[object_index] = flag; + seeprom_bytes_write(NV_SEEPROM_BINARY_OUTPUT(object_index, + NV_SEEPROM_BO_OUT_OF_SERVICE), &Out_Of_Service[object_index], + 1); + } +} + +/* we simply have 0-n object instances. */ +bool Binary_Output_Valid_Instance( + uint32_t object_instance) +{ + if (object_instance < MAX_BINARY_OUTPUTS) + return true; + + return false; +} + +/* we simply have 0-n object instances. */ +unsigned Binary_Output_Count( + void) +{ + return MAX_BINARY_OUTPUTS; +} + +/* we simply have 0-n object instances. */ +uint32_t Binary_Output_Index_To_Instance( + unsigned index) +{ + return index; +} + +/* we simply have 0-n object instances. */ +unsigned Binary_Output_Instance_To_Index( + uint32_t object_instance) +{ + unsigned index = MAX_BINARY_OUTPUTS; + + if (object_instance < MAX_BINARY_OUTPUTS) + index = object_instance; + + return index; +} + +static BACNET_BINARY_PV Binary_Output_Present_Value( + uint32_t object_instance) +{ + BACNET_BINARY_PV value = RELINQUISH_DEFAULT; + BACNET_BINARY_PV current_value = RELINQUISH_DEFAULT; + unsigned index = 0; + unsigned i = 0; + + index = Binary_Output_Instance_To_Index(object_instance); + if (index < MAX_BINARY_OUTPUTS) { + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + current_value = Binary_Output_Level[index][i]; + if (current_value != BINARY_NULL) { + value = Binary_Output_Level[index][i]; + break; + } + } + } + + return value; +} + +static void Binary_Output_Sync( + uint32_t object_instance) +{ + BACNET_BINARY_PV pv = Binary_Output_Present_Value(object_instance); + unsigned index = Binary_Output_Instance_To_Index(object_instance); + + if (index < MAX_BINARY_OUTPUTS) { + if (Out_Of_Service[index]) { + return; + } + if (Polarity[index] == POLARITY_REVERSE) { + if (pv == BINARY_INACTIVE) { + pv = BINARY_ACTIVE; + } else if (pv == BINARY_ACTIVE) { + pv = BINARY_INACTIVE; + } + } + switch (index) { + case 0: + if (pv == BINARY_INACTIVE) { + led_off(LED_3); + } else if (pv == BINARY_ACTIVE) { + led_on(LED_3); + } + break; + case 1: + if (pv == BINARY_INACTIVE) { + led_off(LED_4); + } else if (pv == BINARY_ACTIVE) { + led_on(LED_4); + } + break; + default: + break; + } + } +} + +/* note: the object name must be unique within this device */ +char *Binary_Output_Name( + uint32_t object_instance) +{ + static char text_string[16] = "BV-0"; /* okay for single thread */ + + if (object_instance < MAX_BINARY_OUTPUTS) { + text_string[3] = '0' + (uint8_t) object_instance; + return text_string; + } + + return NULL; +} + +/* return apdu len, or -1 on error */ +int Binary_Output_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 len = 0; + int apdu_len = 0; /* return value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + BACNET_BINARY_PV present_value = BINARY_INACTIVE; + unsigned object_index = 0; + unsigned i = 0; + bool state = false; + + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = + encode_application_object_id(&apdu[0], OBJECT_BINARY_OUTPUT, + 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: + case PROP_DESCRIPTION: + characterstring_init_ansi(&char_string, + Binary_Output_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_OUTPUT); + break; + case PROP_PRESENT_VALUE: + present_value = Binary_Output_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: + object_index = Binary_Output_Instance_To_Index(object_instance); + state = Out_Of_Service[object_index]; + apdu_len = encode_application_boolean(&apdu[0], state); + break; + case PROP_POLARITY: + apdu_len = + encode_application_enumerated(&apdu[0], + Polarity[object_index]); + break; + case PROP_PRIORITY_ARRAY: + /* Array element zero is the number of elements in the array */ + if (array_index == 0) + apdu_len = + encode_application_unsigned(&apdu[0], BACNET_MAX_PRIORITY); + /* if no index was specified, then try to encode the entire list */ + /* into one packet. */ + else if (array_index == BACNET_ARRAY_ALL) { + object_index = + Binary_Output_Instance_To_Index(object_instance); + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + /* FIXME: check if we have room before adding it to APDU */ + present_value = Binary_Output_Level[object_index][i]; + if (present_value == BINARY_NULL) { + len = encode_application_null(&apdu[apdu_len]); + } else { + len = + encode_application_enumerated(&apdu[apdu_len], + present_value); + } + /* add it if we have room */ + if ((apdu_len + len) < MAX_APDU) + apdu_len += len; + else { + *error_class = ERROR_CLASS_SERVICES; + *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; + apdu_len = -1; + break; + } + } + } else { + object_index = + Binary_Output_Instance_To_Index(object_instance); + if (array_index <= BACNET_MAX_PRIORITY) { + present_value = + Binary_Output_Level[object_index][array_index]; + if (present_value == BINARY_NULL) { + len = encode_application_null(&apdu[apdu_len]); + } else { + len = + encode_application_enumerated(&apdu[apdu_len], + present_value); + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = -1; + } + } + + break; + case PROP_RELINQUISH_DEFAULT: + present_value = RELINQUISH_DEFAULT; + apdu_len = encode_application_enumerated(&apdu[0], present_value); + break; + case PROP_ACTIVE_TEXT: + characterstring_init_ansi(&char_string, "on"); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_INACTIVE_TEXT: + characterstring_init_ansi(&char_string, "off"); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + 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_Output_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; + unsigned int priority = 0; + BACNET_BINARY_PV level = BINARY_NULL; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + + object_index = Binary_Output_Instance_To_Index(wp_data->object_instance); + if (object_index >= MAX_BINARY_OUTPUTS) { + *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) { + priority = wp_data->priority; + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + if (priority && (priority <= BACNET_MAX_PRIORITY) && + (priority != 6 /* reserved */ ) && + (value.type.Enumerated <= MAX_BINARY_PV)) { + level = (BACNET_BINARY_PV) value.type.Enumerated; + priority--; + Binary_Output_Level_Set(object_index, priority, level); + Binary_Output_Sync(wp_data->object_instance); + status = true; + } else if (priority == 6) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else if (value.tag == BACNET_APPLICATION_TAG_NULL) { + level = BINARY_NULL; + priority = wp_data->priority; + if (priority && (priority <= BACNET_MAX_PRIORITY)) { + priority--; + Binary_Output_Level_Set(object_index, priority, level); + Binary_Output_Sync(wp_data->object_instance); + status = true; + } else if (priority == 6) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } 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; + case PROP_OUT_OF_SERVICE: + if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { + Binary_Output_Out_Of_Service_Set(object_index, + value.type.Boolean); + Binary_Output_Sync(wp_data->object_instance); + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_POLARITY: + if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) { + if (value.type.Enumerated < MAX_POLARITY) { + Binary_Output_Polarity_Set(object_index, + value.type.Enumerated); + Binary_Output_Sync(wp_data->object_instance); + 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; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } + + return status; +} + +void Binary_Output_Init( + void) +{ + unsigned i, j; + + /* initialize all the analog output priority arrays to NULL */ + for (i = 0; i < MAX_BINARY_OUTPUTS; i++) { + seeprom_bytes_read(NV_SEEPROM_BINARY_OUTPUT(i, NV_SEEPROM_BO_POLARITY), + &Polarity[i], 1); + if (Polarity[i] >= MAX_POLARITY) { + Binary_Output_Polarity_Set(i, POLARITY_NORMAL); + } + seeprom_bytes_read(NV_SEEPROM_BINARY_OUTPUT(i, + NV_SEEPROM_BO_OUT_OF_SERVICE), &Out_Of_Service[i], 1); + if (Out_Of_Service[i] > 1) { + Binary_Output_Out_Of_Service_Set(i, false); + } + for (j = 0; j < BACNET_MAX_PRIORITY; j++) { + seeprom_bytes_read(NV_SEEPROM_BINARY_OUTPUT(i, + NV_SEEPROM_BO_PRIORITY_ARRAY_1 + j), + &Binary_Output_Level[i][j], 1); + } + Binary_Output_Sync(i); + } + + return; +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/defines.h b/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/defines.h index 80ccaafd..376feca2 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/defines.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/defines.h @@ -1,46 +1,46 @@ -/* definitions generated by preprocessor, copy into defines.h */ -#ifndef PPINC -#define _ATMEGA644P // device select: _ATMEGAxxxx -#define _B2048 // boot size select: _Bxxxx (words), powers of two only -#ifdef __ICCAVR__ -#include "iom644.h" -#endif -#if __GNUC__ -#include -#endif - -/* define pin for enter-self-prog-mode */ -#define PROGPORT PORTB -#define PROGPIN PINB -#define PROG_NO PB0 - -/* baud rate register value calculation */ -#define CPU_FREQ 18430000 -#define BAUD_RATE 115200 -#define BRREG_VALUE 9 - -/* definitions for UART control */ -#define BAUD_RATE_LOW_REG UBRR1 -#define UART_CONTROL_REG UCSR1B -#define ENABLE_TRANSMITTER_BIT TXEN1 -#define ENABLE_RECEIVER_BIT RXEN1 -#define UART_STATUS_REG UCSR1A -#define TRANSMIT_COMPLETE_BIT TXC1 -#define RECEIVE_COMPLETE_BIT RXC1 -#define UART_DATA_REG UDR1 - -/* definitions for SPM control */ -#define SPMCR_REG SPMCSR -#define PAGESIZE 256 -#define APP_END 61440 -//#define LARGE_MEMORY - -/* definitions for device recognition */ -#define PARTCODE 0 -#define SIGNATURE_BYTE_1 0x1E -#define SIGNATURE_BYTE_2 0x96 -#define SIGNATURE_BYTE_3 0x0A - -/* indicate that preprocessor result is included */ -#define PPINC -#endif +/* definitions generated by preprocessor, copy into defines.h */ +#ifndef PPINC +#define _ATMEGA644P /* device select: _ATMEGAxxxx */ +#define _B2048 /* boot size select: _Bxxxx (words), powers of two only */ +#ifdef __ICCAVR__ +#include "iom644.h" +#endif +#if __GNUC__ +#include +#endif + +/* define pin for enter-self-prog-mode */ +#define PROGPORT PORTB +#define PROGPIN PINB +#define PROG_NO PB0 + +/* baud rate register value calculation */ +#define CPU_FREQ 18430000 +#define BAUD_RATE 115200 +#define BRREG_VALUE 9 + +/* definitions for UART control */ +#define BAUD_RATE_LOW_REG UBRR1 +#define UART_CONTROL_REG UCSR1B +#define ENABLE_TRANSMITTER_BIT TXEN1 +#define ENABLE_RECEIVER_BIT RXEN1 +#define UART_STATUS_REG UCSR1A +#define TRANSMIT_COMPLETE_BIT TXC1 +#define RECEIVE_COMPLETE_BIT RXC1 +#define UART_DATA_REG UDR1 + +/* definitions for SPM control */ +#define SPMCR_REG SPMCSR +#define PAGESIZE 256 +#define APP_END 61440 +/*#define LARGE_MEMORY */ + +/* definitions for device recognition */ +#define PARTCODE 0 +#define SIGNATURE_BYTE_1 0x1E +#define SIGNATURE_BYTE_2 0x96 +#define SIGNATURE_BYTE_3 0x0A + +/* indicate that preprocessor result is included */ +#define PPINC +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/main.c b/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/main.c index f247d973..8872d9b7 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/main.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/main.c @@ -31,11 +31,11 @@ /* Uncomment the following to save code space */ -//#define REMOVE_AVRPROG_SUPPORT -//#define REMOVE_FUSE_AND_LOCK_BIT_SUPPORT -//#define REMOVE_BLOCK_SUPPORT -//#define REMOVE_EEPROM_BYTE_SUPPORT -//#define REMOVE_FLASH_BYTE_SUPPORT +/*#define REMOVE_AVRPROG_SUPPORT */ +/*#define REMOVE_FUSE_AND_LOCK_BIT_SUPPORT */ +/*#define REMOVE_BLOCK_SUPPORT */ +/*#define REMOVE_EEPROM_BYTE_SUPPORT */ +/*#define REMOVE_FLASH_BYTE_SUPPORT */ /* * GCC doesn't optimize long int arithmetics very clever. As the @@ -47,13 +47,19 @@ */ #ifdef LARGE_MEMORY # define ADDR_T unsigned long -#else /* !LARGE_MEMORY */ +#else /* !LARGE_MEMORY */ # define ADDR_T unsigned int #endif /* LARGE_MEMORY */ #ifndef REMOVE_BLOCK_SUPPORT -unsigned char BlockLoad(unsigned int size, unsigned char mem, ADDR_T *address); -void BlockRead(unsigned int size, unsigned char mem, ADDR_T *address); +unsigned char BlockLoad( + unsigned int size, + unsigned char mem, + ADDR_T * address); +void BlockRead( + unsigned int size, + unsigned char mem, + ADDR_T * address); /* BLOCKSIZE should be chosen so that the following holds: BLOCKSIZE*n = PAGESIZE, where n=1,2,3... */ #define BLOCKSIZE PAGESIZE @@ -61,433 +67,398 @@ void BlockRead(unsigned int size, unsigned char mem, ADDR_T *address); #endif /* REMOVE_BLOCK_SUPPORT */ #ifdef __ICCAVR__ -__C_task void main(void) +__C_task void main( + void) #else /* ! __ICCAVR__ */ -int main(void) +int main( + void) #endif /* __ICCAVR__ */ - { ADDR_T address; unsigned int temp_int; unsigned char val; - /* Initialization */ - void (*funcptr)( void ) = 0x0000; // Set up function pointer to RESET vector. - PROGPORT |= (1<>8) & 0xFF); // MSB first. - sendchar(BLOCKSIZE&0xFF); // Report BLOCKSIZE (bytes). - } + /* Check block load support. */ + else if (val == 'b') { + sendchar('Y'); /* Report block load supported. */ + sendchar((BLOCKSIZE >> 8) & 0xFF); /* MSB first. */ + sendchar(BLOCKSIZE & 0xFF); /* Report BLOCKSIZE (bytes). */ + } - // Start block load. - else if(val=='B') - { - temp_int = (recchar()<<8) | recchar(); // Get block size. - val = recchar(); // Get memtype. - sendchar( BlockLoad(temp_int,val,&address) ); // Block load. - } - - - // Start block read. - else if(val=='g') - { - temp_int = (recchar()<<8) | recchar(); // Get block size. - val = recchar(); // Get memtype - BlockRead(temp_int,val,&address); // Block read - } + /* Start block load. */ + else if (val == 'B') { + temp_int = (recchar() << 8) | recchar(); /* Get block size. */ + val = recchar(); /* Get memtype. */ + sendchar(BlockLoad(temp_int, val, &address)); /* Block load. */ + } + + + /* Start block read. */ + else if (val == 'g') { + temp_int = (recchar() << 8) | recchar(); /* Get block size. */ + val = recchar(); /* Get memtype */ + BlockRead(temp_int, val, &address); /* Block read */ + } #endif /* REMOVE_BLOCK_SUPPORT */ -#ifndef REMOVE_FLASH_BYTE_SUPPORT - // Read program memory. - else if(val=='R') - { - // Send high byte, then low byte of flash word. - _WAIT_FOR_SPM(); +#ifndef REMOVE_FLASH_BYTE_SUPPORT + /* Read program memory. */ + else if (val == 'R') { + /* Send high byte, then low byte of flash word. */ + _WAIT_FOR_SPM(); _ENABLE_RWW_SECTION(); #ifdef __ICCAVR__ -#pragma diag_suppress=Pe1053 // Suppress warning for conversion from long-type address to flash ptr. +#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */ #endif - sendchar( _LOAD_PROGRAM_MEMORY( (address << 1)+1 ) ); - sendchar( _LOAD_PROGRAM_MEMORY( (address << 1)+0 ) ); + sendchar(_LOAD_PROGRAM_MEMORY((address << 1) + 1)); + sendchar(_LOAD_PROGRAM_MEMORY((address << 1) + 0)); #ifdef __ICCAVR__ -#pragma diag_default=Pe1053 // Back to default. +#pragma diag_default=Pe1053 /* Back to default. */ #endif - address++; // Auto-advance to next Flash word. + address++; /* Auto-advance to next Flash word. */ } - - // Write program memory, low byte. - else if(val=='c') - { // NOTE: Always use this command before sending high byte. - temp_int=recchar(); // Get low byte for later _FILL_TEMP_WORD. - sendchar('\r'); // Send OK back. + + /* Write program memory, low byte. */ + else if (val == 'c') { /* NOTE: Always use this command before sending high byte. */ + temp_int = recchar(); /* Get low byte for later _FILL_TEMP_WORD. */ + sendchar('\r'); /* Send OK back. */ } - - - // Write program memory, high byte. - else if(val=='C') - { - temp_int |= (recchar()<<8); // Get and insert high byte. + + + /* Write program memory, high byte. */ + else if (val == 'C') { + temp_int |= (recchar() << 8); /* Get and insert high byte. */ _WAIT_FOR_SPM(); #ifdef __ICCAVR__ -#pragma diag_suppress=Pe1053 // Suppress warning for conversion from long-type address to flash ptr. +#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */ #endif - _FILL_TEMP_WORD( (address << 1), temp_int ); // Convert word-address to byte-address and fill. + _FILL_TEMP_WORD((address << 1), temp_int); /* Convert word-address to byte-address and fill. */ #ifdef __ICCAVR__ -#pragma diag_default=Pe1053 // Back to default. +#pragma diag_default=Pe1053 /* Back to default. */ #endif - address++; // Auto-advance to next Flash word. - sendchar('\r'); // Send OK back. + address++; /* Auto-advance to next Flash word. */ + sendchar('\r'); /* Send OK back. */ } - - - // Write page. - else if(val== 'm') - { - if( address >= (APP_END>>1) ) // Protect bootloader area. - { + + + /* Write page. */ + else if (val == 'm') { + if (address >= (APP_END >> 1)) { /* Protect bootloader area. */ sendchar('?'); - } else - { - _WAIT_FOR_SPM(); + } else { + _WAIT_FOR_SPM(); #ifdef __ICCAVR__ -#pragma diag_suppress=Pe1053 // Suppress warning for conversion from long-type address to flash ptr. +#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */ #endif - _PAGE_WRITE( address << 1 ); // Convert word-address to byte-address and write. + _PAGE_WRITE(address << 1); /* Convert word-address to byte-address and write. */ #ifdef __ICCAVR__ -#pragma diag_default=Pe1053 // Back to default. +#pragma diag_default=Pe1053 /* Back to default. */ #endif } - sendchar('\r'); // Send OK back. + sendchar('\r'); /* Send OK back. */ } #endif /* REMOVE_FLASH_BYTE_SUPPORT */ #ifndef REMOVE_EEPROM_BYTE_SUPPORT - // Write EEPROM memory. - else if (val == 'D') - { - _WAIT_FOR_SPM(); - EEARL = address; // Setup EEPROM address. + /* Write EEPROM memory. */ + else if (val == 'D') { + _WAIT_FOR_SPM(); + EEARL = address; /* Setup EEPROM address. */ EEARH = (address >> 8); - EEDR = recchar(); // Get byte. - EECR |= (1<> 8); - EECR |= (1< 0 - sendchar( PARTCODE ); // Supports only this device, of course. + sendchar(PARTCODE); /* Supports only this device, of course. */ #endif /* PARTCODE */ - sendchar( 0 ); // Send list terminator. + sendchar(0); /* Send list terminator. */ } - - - // Set LED, clear LED and set device type. - else if((val=='x')||(val=='y')||(val=='T')) - { - recchar(); // Ignore the command and it's parameter. - sendchar('\r'); // Send OK back. + + + /* Set LED, clear LED and set device type. */ + else if ((val == 'x') || (val == 'y') || (val == 'T')) { + recchar(); /* Ignore the command and it's parameter. */ + sendchar('\r'); /* Send OK back. */ } #endif /* REMOVE_AVRPROG_SUPPORT */ - - // Return programmer identifier. - else if(val=='S') - { - sendchar('A'); // Return 'AVRBOOT'. - sendchar('V'); // Software identifier (aka programmer signature) is always 7 characters. + + /* Return programmer identifier. */ + else if (val == 'S') { + sendchar('A'); /* Return 'AVRBOOT'. */ + sendchar('V'); /* Software identifier (aka programmer signature) is always 7 characters. */ sendchar('R'); sendchar('B'); sendchar('O'); sendchar('O'); sendchar('T'); } - - - // Return software version. - else if(val=='V') - { + + + /* Return software version. */ + else if (val == 'V') { sendchar('1'); sendchar('5'); - } + } - // Return signature bytes. - else if(val=='s') - { - sendchar( SIGNATURE_BYTE_3 ); - sendchar( SIGNATURE_BYTE_2 ); - sendchar( SIGNATURE_BYTE_1 ); - } + /* Return signature bytes. */ + else if (val == 's') { + sendchar(SIGNATURE_BYTE_3); + sendchar(SIGNATURE_BYTE_2); + sendchar(SIGNATURE_BYTE_1); + } - // The last command to accept is ESC (synchronization). - else if(val!=0x1b) // If not ESC, then it is unrecognized... - { + /* The last command to accept is ESC (synchronization). */ + else if (val != 0x1b) { /* If not ESC, then it is unrecognized... */ sendchar('?'); } - } // end: for(;;) - } - else - { - _WAIT_FOR_SPM(); + } /* end: for(;;) */ + } else { + _WAIT_FOR_SPM(); _ENABLE_RWW_SECTION(); - funcptr(); // Jump to Reset vector 0x0000 in Application Section. + funcptr(); /* Jump to Reset vector 0x0000 in Application Section. */ } -} // end: main +} /* end: main */ #ifndef REMOVE_BLOCK_SUPPORT -unsigned char BlockLoad(unsigned int size, unsigned char mem, ADDR_T *address) +unsigned char BlockLoad( + unsigned int size, + unsigned char mem, + ADDR_T * address) { unsigned char buffer[BLOCKSIZE]; unsigned int data; ADDR_T tempaddress; - - // EEPROM memory type. - if(mem=='E') - { + + /* EEPROM memory type. */ + if (mem == 'E') { /* Fill buffer first, as EEPROM is too slow to copy with UART speed */ - for(tempaddress=0;tempaddress> 8); - EEDR = buffer[tempaddress]; // Get byte. - EECR |= (1<>= 1; // Convert address back to Flash words again. - return '\r'; // Report programming OK + (*address) >>= 1; /* Convert address back to Flash words again. */ + return '\r'; /* Report programming OK */ } - - // Invalid memory type? - else - { + + /* Invalid memory type? */ + else { return '?'; } } -void BlockRead(unsigned int size, unsigned char mem, ADDR_T *address) +void BlockRead( + unsigned int size, + unsigned char mem, + ADDR_T * address) { - // EEPROM memory type. - if (mem=='E') // Read EEPROM - { - do - { - EEARL = *address; // Setup EEPROM address + /* EEPROM memory type. */ + if (mem == 'E') { /* Read EEPROM */ + do { + EEARL = *address; /* Setup EEPROM address */ EEARH = ((*address) >> 8); - (*address)++; // Select next EEPROM byte - EECR |= (1<>= 1; // Convert address back to Flash words again. + /* Flash memory type. */ + else if (mem == 'F') { + (*address) <<= 1; /* Convert address to bytes temporarily. */ + + do { +#ifdef __ICCAVR__ +#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */ +#endif + sendchar(_LOAD_PROGRAM_MEMORY(*address)); + sendchar(_LOAD_PROGRAM_MEMORY((*address) + 1)); +#ifdef __ICCAVR__ +#pragma diag_default=Pe1053 /* Back to default. */ +#endif + (*address) += 2; /* Select next word in memory. */ + size -= 2; /* Subtract two bytes from number of bytes to read */ + } while (size); /* Repeat until all block has been read */ + + (*address) >>= 1; /* Convert address back to Flash words again. */ } } #endif /* REMOVE_BLOCK_SUPPORT */ diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/serial.c b/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/serial.c index 59b0c8b3..3d8ec5db 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/serial.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/serial.c @@ -19,24 +19,26 @@ #include "defines.h" -void initbootuart(void) +void initbootuart( + void) { - BAUD_RATE_LOW_REG = BRREG_VALUE; - UART_CONTROL_REG = (1 << ENABLE_RECEIVER_BIT) | - (1 << ENABLE_TRANSMITTER_BIT); // enable receive and transmit + BAUD_RATE_LOW_REG = BRREG_VALUE; + UART_CONTROL_REG = (1 << ENABLE_RECEIVER_BIT) | (1 << ENABLE_TRANSMITTER_BIT); /* enable receive and transmit */ } -void sendchar(unsigned char c) +void sendchar( + unsigned char c) { - UART_DATA_REG = c; // prepare transmission - while (!(UART_STATUS_REG & (1 << TRANSMIT_COMPLETE_BIT)));// wait until byte sendt - UART_STATUS_REG |= (1 << TRANSMIT_COMPLETE_BIT); // delete TXCflag + UART_DATA_REG = c; /* prepare transmission */ + while (!(UART_STATUS_REG & (1 << TRANSMIT_COMPLETE_BIT))); /* wait until byte sendt */ + UART_STATUS_REG |= (1 << TRANSMIT_COMPLETE_BIT); /* delete TXCflag */ } -unsigned char recchar(void) +unsigned char recchar( + void) { - while(!(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT))); // wait for data - return UART_DATA_REG; + while (!(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT))); /* wait for data */ + return UART_DATA_REG; } diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/serial.h b/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/serial.h index c7a78aa7..6a298658 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/serial.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bootloader/serial.h @@ -17,6 +17,9 @@ * Description : Header file for serial.c ****************************************************************************/ -void initbootuart( void ); -void sendchar( unsigned char ); -unsigned char recchar( void ); +void initbootuart( + void); +void sendchar( + unsigned char); +unsigned char recchar( + void); diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/device.c b/bacnet-stack/ports/bdk-atxx4-mstp/device.c index 1c01d890..cd9a3586 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/device.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/device.c @@ -1,645 +1,623 @@ -/************************************************************************** -* -* 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 "datalink.h" -#include "rs485.h" -#include "version.h" -#include "nvdata.h" -#include "stack.h" -/* objects */ -#include "device.h" -#include "ai.h" -#include "bi.h" -#include "bo.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; -static uint8_t Object_Name[NV_EEPROM_DEVICE_NAME_SIZE]; -static uint8_t Object_Name_Encoding; -static uint8_t Object_Name_Length; -static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; - -static BACNET_REINITIALIZED_STATE_OF_DEVICE Reinitialize_State = - REINITIALIZED_STATE_IDLE; - -/* These three arrays are used by the ReadPropertyMultiple handler */ -static const int Device_Properties_Required[] = { - PROP_OBJECT_IDENTIFIER, - PROP_OBJECT_NAME, - PROP_OBJECT_TYPE, - PROP_SYSTEM_STATUS, - PROP_VENDOR_NAME, - PROP_VENDOR_IDENTIFIER, - PROP_MODEL_NAME, - PROP_FIRMWARE_REVISION, - PROP_APPLICATION_SOFTWARE_VERSION, - PROP_PROTOCOL_VERSION, - PROP_PROTOCOL_REVISION, - PROP_PROTOCOL_SERVICES_SUPPORTED, - PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, - PROP_OBJECT_LIST, - PROP_MAX_APDU_LENGTH_ACCEPTED, - PROP_SEGMENTATION_SUPPORTED, - PROP_APDU_TIMEOUT, - PROP_NUMBER_OF_APDU_RETRIES, -#if defined(BACDL_MSTP) - PROP_MAX_MASTER, - PROP_MAX_INFO_FRAMES, -#endif - PROP_DEVICE_ADDRESS_BINDING, - PROP_DATABASE_REVISION, - -1 -}; - -static const int Device_Properties_Optional[] = { - PROP_DESCRIPTION, - PROP_PROTOCOL_CONFORMANCE_CLASS, - -1 -}; - -static const int Device_Properties_Proprietary[] = { - -1 -}; - -void Device_Property_Lists( - const int **pRequired, - const int **pOptional, - const int **pProprietary) -{ - if (pRequired) - *pRequired = Device_Properties_Required; - if (pOptional) - *pOptional = Device_Properties_Optional; - if (pProprietary) - *pProprietary = Device_Properties_Proprietary; - - return; -} - -void Device_Reinit( - void) -{ - dcc_set_status_duration(COMMUNICATION_ENABLE, 0); - Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); -} - -void Device_Init( - void) -{ - Reinitialize_State = REINITIALIZED_STATE_IDLE; - dcc_set_status_duration(COMMUNICATION_ENABLE, 0); - /* Get the data from the eeprom */ - eeprom_bytes_read( - NV_EEPROM_DEVICE_0, - (uint8_t *)&Object_Instance_Number, - sizeof(Object_Instance_Number)); - if (Object_Instance_Number >= BACNET_MAX_INSTANCE) { - Object_Instance_Number = 0; - eeprom_bytes_write( - NV_EEPROM_DEVICE_0, - (uint8_t *)&Object_Instance_Number, - sizeof(Object_Instance_Number)); - } - eeprom_bytes_read( - NV_EEPROM_DEVICE_NAME_ENCODING, - &Object_Name_Encoding, - 1); - eeprom_bytes_read( - NV_EEPROM_DEVICE_NAME_LENGTH, - &Object_Name_Length, - 1); - eeprom_bytes_read( - NV_EEPROM_DEVICE_NAME_0, - (uint8_t *)&Object_Name[0], - NV_EEPROM_DEVICE_NAME_SIZE); - if ((Object_Name_Encoding >= MAX_CHARACTER_STRING_ENCODING) || - (Object_Name_Length > NV_EEPROM_DEVICE_NAME_SIZE)) { - Object_Name_Encoding = CHARACTER_ANSI_X34; - Object_Name_Length = 0; - eeprom_bytes_write( - NV_EEPROM_DEVICE_NAME_ENCODING, - &Object_Name_Encoding, - 1); - eeprom_bytes_write( - NV_EEPROM_DEVICE_NAME_LENGTH, - &Object_Name_Length, - 1); - } -} - -/* 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; - eeprom_bytes_write( - NV_EEPROM_DEVICE_0, - (uint8_t *)&Object_Instance_Number, - sizeof(Object_Instance_Number)); - } 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)); -} - -BACNET_DEVICE_STATUS Device_System_Status( - void) -{ - return System_Status; -} - -void Device_Set_System_Status( - BACNET_DEVICE_STATUS status) -{ - if (status < MAX_DEVICE_STATUS) - System_Status = status; -} - -uint16_t Device_Vendor_Identifier( - void) -{ - return BACNET_VENDOR_ID; -} - -uint8_t Device_Protocol_Version( - void) -{ - return 1; -} - -uint8_t Device_Protocol_Revision( - void) -{ - return 5; -} - -BACNET_SEGMENTATION Device_Segmentation_Supported( - void) -{ - return SEGMENTATION_NONE; -} - -uint8_t Device_Database_Revision( - void) -{ - return 0; -} - -unsigned Device_Object_List_Count( - void) -{ - unsigned count = 1; /* at least 1 for device object */ - - /* FIXME: add objects as needed */ - count += Binary_Input_Count(); - count += Binary_Output_Count(); - count += Analog_Input_Count(); - - 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 */ - /* binary value objects */ - if (!status) { - object_index -= object_count; - object_count = Binary_Output_Count(); - /* is it a valid index for this object? */ - if (object_index < object_count) { - *object_type = OBJECT_BINARY_OUTPUT; - *instance = Binary_Output_Index_To_Instance(object_index); - status = true; - } - } - /* analog input objects */ - if (!status) { - /* array index starts at 1, and 1 for the device object */ - object_index -= object_count; - object_count = Analog_Input_Count(); - if (object_index < object_count) { - *object_type = OBJECT_ANALOG_INPUT; - *instance = Analog_Input_Index_To_Instance(object_index); - status = true; - } - } - /* binary input objects */ - if (!status) { - /* normalize the index since - we know it is not the previous objects */ - object_index -= object_count; - object_count = Binary_Input_Count(); - /* is it a valid index for this object? */ - if (object_index < object_count) { - *object_type = OBJECT_BINARY_INPUT; - *instance = Binary_Input_Index_To_Instance(object_index); - status = true; - } - } - - 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(&char_string, - Object_Name_Encoding, - (char *)&Object_Name[0], - Object_Name_Length); - 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_DESCRIPTION: - characterstring_init_ansi(&char_string, "BACnet Development Kit"); - apdu_len = - encode_application_character_string(&apdu[0], &char_string); - break; - case PROP_SYSTEM_STATUS: - apdu_len = - encode_application_enumerated(&apdu[0], - Device_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, "bdk-atxx4-mstp"); - apdu_len = - encode_application_character_string(&apdu[0], &char_string); - break; - case PROP_FIRMWARE_REVISION: - characterstring_init_ansi(&char_string, BACnet_Version); - 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], - Device_Protocol_Version()); - break; - case PROP_PROTOCOL_REVISION: - apdu_len = - encode_application_unsigned(&apdu[0], - Device_Protocol_Revision()); - break; - /* BACnet Legacy Support */ - case PROP_PROTOCOL_CONFORMANCE_CLASS: - apdu_len = encode_application_unsigned(&apdu[0], 1); - 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(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); - for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { - /* FIXME: if ReadProperty used an array of Functions... */ - /* 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); - bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true); - bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true); - bitstring_set_bit(&bit_string, OBJECT_BINARY_OUTPUT, true); - 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++) { - if (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 { - /* error: internal error? */ - *error_class = ERROR_CLASS_SERVICES; - *error_code = ERROR_CODE_OTHER; - 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], - Device_Segmentation_Supported()); - break; - case PROP_APDU_TIMEOUT: - apdu_len = encode_application_unsigned(&apdu[0], apdu_timeout()); - break; - case PROP_NUMBER_OF_APDU_RETRIES: - apdu_len = encode_application_unsigned(&apdu[0], apdu_retries()); - 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], - Device_Database_Revision()); - break; - case PROP_MAX_INFO_FRAMES: - apdu_len = - encode_application_unsigned(&apdu[0], - dlmstp_max_info_frames()); - break; - case PROP_MAX_MASTER: - apdu_len = - encode_application_unsigned(&apdu[0], dlmstp_max_master()); - break; - case 512: - apdu_len = encode_application_unsigned(&apdu[0], stack_size()); - break; - case 513: - apdu_len = encode_application_unsigned(&apdu[0], stack_unused()); - break; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_UNKNOWN_PROPERTY; - apdu_len = -1; - break; - } - - return apdu_len; -} - -bool Device_Write_Property( - BACNET_WRITE_PROPERTY_DATA * wp_data, - BACNET_ERROR_CLASS * error_class, - BACNET_ERROR_CODE * error_code) -{ - bool status = false; /* return value */ - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; - - if (!Device_Valid_Object_Instance_Number(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_OBJECT_IDENTIFIER: - if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) { - if ((value.type.Object_Id.type == OBJECT_DEVICE) && - (Device_Set_Object_Instance_Number(value.type.Object_Id. - instance))) { - /* we could send an I-Am broadcast to let the world know */ - 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; - case PROP_MAX_INFO_FRAMES: - if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - if (value.type.Unsigned_Int <= 255) { - dlmstp_set_max_info_frames(value.type.Unsigned_Int); - 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; - case PROP_MAX_MASTER: - if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - if ((value.type.Unsigned_Int > 0) && - (value.type.Unsigned_Int <= 127)) { - dlmstp_set_max_master(value.type.Unsigned_Int); - 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; - case PROP_OBJECT_NAME: - if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { - size_t length = - characterstring_length(&value.type.Character_String); - if (length < NV_EEPROM_DEVICE_NAME_SIZE) { - uint8_t encoding = - characterstring_encoding(&value.type.Character_String); - if (encoding < MAX_CHARACTER_STRING_ENCODING) { - uint8_t i; - char *pCharString; - Object_Name_Encoding = encoding; - Object_Name_Length = length; - eeprom_bytes_write( - NV_EEPROM_DEVICE_NAME_ENCODING, - &Object_Name_Encoding, - 1); - eeprom_bytes_write( - NV_EEPROM_DEVICE_NAME_LENGTH, - &Object_Name_Length, - 1); - pCharString = - characterstring_value(&value.type.Character_String); - for (i = 0; i < Object_Name_Length; i++) { - Object_Name[i] = pCharString[i]; - } - eeprom_bytes_write( - NV_EEPROM_DEVICE_NAME_0, - (uint8_t *)&Object_Name[0], - length); - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - case 9600: - if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - if ((value.type.Unsigned_Int > 115200) && - (rs485_baud_rate_set(value.type.Unsigned_Int))) { - 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; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - break; - } - - return status; -} +/************************************************************************** +* +* 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 "datalink.h" +#include "rs485.h" +#include "version.h" +#include "nvdata.h" +#include "stack.h" +/* objects */ +#include "device.h" +#include "ai.h" +#include "bi.h" +#include "bo.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; +static uint8_t Object_Name[NV_EEPROM_DEVICE_NAME_SIZE]; +static uint8_t Object_Name_Encoding; +static uint8_t Object_Name_Length; +static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; + +static BACNET_REINITIALIZED_STATE_OF_DEVICE Reinitialize_State = + REINITIALIZED_STATE_IDLE; + +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Device_Properties_Required[] = { + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_SYSTEM_STATUS, + PROP_VENDOR_NAME, + PROP_VENDOR_IDENTIFIER, + PROP_MODEL_NAME, + PROP_FIRMWARE_REVISION, + PROP_APPLICATION_SOFTWARE_VERSION, + PROP_PROTOCOL_VERSION, + PROP_PROTOCOL_REVISION, + PROP_PROTOCOL_SERVICES_SUPPORTED, + PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, + PROP_OBJECT_LIST, + PROP_MAX_APDU_LENGTH_ACCEPTED, + PROP_SEGMENTATION_SUPPORTED, + PROP_APDU_TIMEOUT, + PROP_NUMBER_OF_APDU_RETRIES, +#if defined(BACDL_MSTP) + PROP_MAX_MASTER, + PROP_MAX_INFO_FRAMES, +#endif + PROP_DEVICE_ADDRESS_BINDING, + PROP_DATABASE_REVISION, + -1 +}; + +static const int Device_Properties_Optional[] = { + PROP_DESCRIPTION, + PROP_PROTOCOL_CONFORMANCE_CLASS, + -1 +}; + +static const int Device_Properties_Proprietary[] = { + -1 +}; + +void Device_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (pRequired) + *pRequired = Device_Properties_Required; + if (pOptional) + *pOptional = Device_Properties_Optional; + if (pProprietary) + *pProprietary = Device_Properties_Proprietary; + + return; +} + +void Device_Reinit( + void) +{ + dcc_set_status_duration(COMMUNICATION_ENABLE, 0); + Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); +} + +void Device_Init( + void) +{ + Reinitialize_State = REINITIALIZED_STATE_IDLE; + dcc_set_status_duration(COMMUNICATION_ENABLE, 0); + /* Get the data from the eeprom */ + eeprom_bytes_read(NV_EEPROM_DEVICE_0, (uint8_t *) & Object_Instance_Number, + sizeof(Object_Instance_Number)); + if (Object_Instance_Number >= BACNET_MAX_INSTANCE) { + Object_Instance_Number = 0; + eeprom_bytes_write(NV_EEPROM_DEVICE_0, + (uint8_t *) & Object_Instance_Number, + sizeof(Object_Instance_Number)); + } + eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_ENCODING, &Object_Name_Encoding, + 1); + eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_LENGTH, &Object_Name_Length, 1); + eeprom_bytes_read(NV_EEPROM_DEVICE_NAME_0, (uint8_t *) & Object_Name[0], + NV_EEPROM_DEVICE_NAME_SIZE); + if ((Object_Name_Encoding >= MAX_CHARACTER_STRING_ENCODING) || + (Object_Name_Length > NV_EEPROM_DEVICE_NAME_SIZE)) { + Object_Name_Encoding = CHARACTER_ANSI_X34; + Object_Name_Length = 0; + eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_ENCODING, + &Object_Name_Encoding, 1); + eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_LENGTH, &Object_Name_Length, + 1); + } +} + +/* 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; + eeprom_bytes_write(NV_EEPROM_DEVICE_0, + (uint8_t *) & Object_Instance_Number, + sizeof(Object_Instance_Number)); + } 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)); +} + +BACNET_DEVICE_STATUS Device_System_Status( + void) +{ + return System_Status; +} + +void Device_Set_System_Status( + BACNET_DEVICE_STATUS status) +{ + if (status < MAX_DEVICE_STATUS) + System_Status = status; +} + +uint16_t Device_Vendor_Identifier( + void) +{ + return BACNET_VENDOR_ID; +} + +uint8_t Device_Protocol_Version( + void) +{ + return 1; +} + +uint8_t Device_Protocol_Revision( + void) +{ + return 5; +} + +BACNET_SEGMENTATION Device_Segmentation_Supported( + void) +{ + return SEGMENTATION_NONE; +} + +uint8_t Device_Database_Revision( + void) +{ + return 0; +} + +unsigned Device_Object_List_Count( + void) +{ + unsigned count = 1; /* at least 1 for device object */ + + /* FIXME: add objects as needed */ + count += Binary_Input_Count(); + count += Binary_Output_Count(); + count += Analog_Input_Count(); + + 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 */ + /* binary value objects */ + if (!status) { + object_index -= object_count; + object_count = Binary_Output_Count(); + /* is it a valid index for this object? */ + if (object_index < object_count) { + *object_type = OBJECT_BINARY_OUTPUT; + *instance = Binary_Output_Index_To_Instance(object_index); + status = true; + } + } + /* analog input objects */ + if (!status) { + /* array index starts at 1, and 1 for the device object */ + object_index -= object_count; + object_count = Analog_Input_Count(); + if (object_index < object_count) { + *object_type = OBJECT_ANALOG_INPUT; + *instance = Analog_Input_Index_To_Instance(object_index); + status = true; + } + } + /* binary input objects */ + if (!status) { + /* normalize the index since + we know it is not the previous objects */ + object_index -= object_count; + object_count = Binary_Input_Count(); + /* is it a valid index for this object? */ + if (object_index < object_count) { + *object_type = OBJECT_BINARY_INPUT; + *instance = Binary_Input_Index_To_Instance(object_index); + status = true; + } + } + + 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(&char_string, Object_Name_Encoding, + (char *) &Object_Name[0], Object_Name_Length); + 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_DESCRIPTION: + characterstring_init_ansi(&char_string, "BACnet Development Kit"); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_SYSTEM_STATUS: + apdu_len = + encode_application_enumerated(&apdu[0], + Device_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, "bdk-atxx4-mstp"); + apdu_len = + encode_application_character_string(&apdu[0], &char_string); + break; + case PROP_FIRMWARE_REVISION: + characterstring_init_ansi(&char_string, BACnet_Version); + 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], + Device_Protocol_Version()); + break; + case PROP_PROTOCOL_REVISION: + apdu_len = + encode_application_unsigned(&apdu[0], + Device_Protocol_Revision()); + break; + /* BACnet Legacy Support */ + case PROP_PROTOCOL_CONFORMANCE_CLASS: + apdu_len = encode_application_unsigned(&apdu[0], 1); + 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(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); + for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { + /* FIXME: if ReadProperty used an array of Functions... */ + /* 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); + bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true); + bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true); + bitstring_set_bit(&bit_string, OBJECT_BINARY_OUTPUT, true); + 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++) { + if (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 { + /* error: internal error? */ + *error_class = ERROR_CLASS_SERVICES; + *error_code = ERROR_CODE_OTHER; + 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], + Device_Segmentation_Supported()); + break; + case PROP_APDU_TIMEOUT: + apdu_len = encode_application_unsigned(&apdu[0], apdu_timeout()); + break; + case PROP_NUMBER_OF_APDU_RETRIES: + apdu_len = encode_application_unsigned(&apdu[0], apdu_retries()); + 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], + Device_Database_Revision()); + break; + case PROP_MAX_INFO_FRAMES: + apdu_len = + encode_application_unsigned(&apdu[0], + dlmstp_max_info_frames()); + break; + case PROP_MAX_MASTER: + apdu_len = + encode_application_unsigned(&apdu[0], dlmstp_max_master()); + break; + case 512: + apdu_len = encode_application_unsigned(&apdu[0], stack_size()); + break; + case 513: + apdu_len = encode_application_unsigned(&apdu[0], stack_unused()); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + +bool Device_Write_Property( + BACNET_WRITE_PROPERTY_DATA * wp_data, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + bool status = false; /* return value */ + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + + if (!Device_Valid_Object_Instance_Number(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_OBJECT_IDENTIFIER: + if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) { + if ((value.type.Object_Id.type == OBJECT_DEVICE) && + (Device_Set_Object_Instance_Number(value.type.Object_Id. + instance))) { + /* we could send an I-Am broadcast to let the world know */ + 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; + case PROP_MAX_INFO_FRAMES: + if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { + if (value.type.Unsigned_Int <= 255) { + dlmstp_set_max_info_frames(value.type.Unsigned_Int); + 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; + case PROP_MAX_MASTER: + if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { + if ((value.type.Unsigned_Int > 0) && + (value.type.Unsigned_Int <= 127)) { + dlmstp_set_max_master(value.type.Unsigned_Int); + 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; + case PROP_OBJECT_NAME: + if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { + size_t length = + characterstring_length(&value.type.Character_String); + if (length < NV_EEPROM_DEVICE_NAME_SIZE) { + uint8_t encoding = + characterstring_encoding(&value.type.Character_String); + if (encoding < MAX_CHARACTER_STRING_ENCODING) { + uint8_t i; + char *pCharString; + Object_Name_Encoding = encoding; + Object_Name_Length = length; + eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_ENCODING, + &Object_Name_Encoding, 1); + eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_LENGTH, + &Object_Name_Length, 1); + pCharString = + characterstring_value(&value.type. + Character_String); + for (i = 0; i < Object_Name_Length; i++) { + Object_Name[i] = pCharString[i]; + } + eeprom_bytes_write(NV_EEPROM_DEVICE_NAME_0, + (uint8_t *) & Object_Name[0], length); + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case 9600: + if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { + if ((value.type.Unsigned_Int > 115200) && + (rs485_baud_rate_set(value.type.Unsigned_Int))) { + 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; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } + + return status; +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/dlmstp.c b/bacnet-stack/ports/bdk-atxx4-mstp/dlmstp.c index 62af6916..5ec9e4cb 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/dlmstp.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/dlmstp.c @@ -1,1342 +1,1342 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2009 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 "timer.h" - -/* This file has been customized for use with small microprocessors */ -/* Assumptions: - Only one MS/TP datalink layer -*/ - -/* 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; - -/* master node FSM states */ -typedef enum { - MSTP_MASTER_STATE_INITIALIZE = 0, - MSTP_MASTER_STATE_IDLE = 1, - MSTP_MASTER_STATE_USE_TOKEN = 2, - MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3, - MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4, - MSTP_MASTER_STATE_PASS_TOKEN = 5, - MSTP_MASTER_STATE_NO_TOKEN = 6, - MSTP_MASTER_STATE_POLL_FOR_MASTER = 7, - MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8 -} MSTP_MASTER_STATE; - -/* The state of the Receive State Machine */ -static MSTP_RECEIVE_STATE Receive_State; -/* When a master node is powered up or reset, */ -/* it shall unconditionally enter the INITIALIZE state. */ -static MSTP_MASTER_STATE Master_State; -/* bit-sized boolean flags */ -static struct mstp_flag_t { - /* A Boolean flag set to TRUE by the Receive State Machine */ - /* if an invalid frame is received. */ - /* Set to FALSE by the main state machine. */ - unsigned ReceivedInvalidFrame:1; - /* A Boolean flag set to TRUE by the Receive State Machine */ - /* if a valid frame is received. */ - /* Set to FALSE by the main state machine. */ - unsigned ReceivedValidFrame:1; - /* A Boolean flag set to TRUE by the master machine if this node is the */ - /* only known master node. */ - unsigned SoleMaster: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; - -/* 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 count the number of received octets or errors. */ -/* This is used in the detection of link activity. */ -/* Compared to Nmin_octets */ -static uint8_t EventCount; -/* 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; -/* This parameter represents the value of the Max_Info_Frames property of */ -/* the node's Device object. The value of Max_Info_Frames specifies the */ -/* maximum number of information frames the node may send before it must */ -/* pass the token. Max_Info_Frames may have different values on different */ -/* nodes. This may be used to allocate more or less of the available link */ -/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ -/* node, its value shall be 1. */ -static uint8_t Nmax_info_frames = 1; -/* This parameter represents the value of the Max_Master property of the */ -/* node's Device object. The value of Max_Master specifies the highest */ -/* allowable address for master nodes. The value of Max_Master shall be */ -/* less than or equal to 127. If Max_Master is not writable in a node, */ -/* its value shall be 127. */ -static uint8_t Nmax_master = 127; -/* 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 time without a DataAvailable or ReceiveError event before declaration */ -/* of loss of token: 500 milliseconds. */ -#define Tno_token 500 - -/* The minimum time without a DataAvailable or ReceiveError event */ -/* that a node must wait for a station to begin replying to a */ -/* confirmed request: 255 milliseconds. (Implementations may use */ -/* larger values for this timeout, not to exceed 300 milliseconds.) */ -#define Treply_timeout 260 - -/* The minimum time without a DataAvailable or ReceiveError event that a */ -/* node must wait for a remote node to begin using a token or replying to */ -/* a Poll For Master frame: 20 milliseconds. (Implementations may use */ -/* larger values for this timeout, not to exceed 100 milliseconds.) */ -#define Tusage_timeout 25 - -/* The number of tokens received or used before a Poll For Master cycle */ -/* is executed: 50. */ -#define Npoll 50 - -/* The number of retries on sending Token: 1. */ -#define Nretry_token 1 - -/* The minimum number of DataAvailable or ReceiveError events that must be */ -/* seen by a receiving node in order to declare the line "active": 4. */ -#define Nmin_octets 4 - -/* 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 after the end of the stop bit of the final */ -/* octet of a transmitted frame before a node must disable its */ -/* EIA-485 driver: 15 bit times. */ -#define Tpostdrive 15 - -/* 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; - - 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; - } -} - -static bool dlmstp_compare_data_expecting_reply( - uint8_t * request_pdu, - uint16_t request_pdu_len, - uint8_t src_address, - uint8_t * reply_pdu, - uint16_t reply_pdu_len, - uint8_t dest_address) -{ - uint16_t offset; - /* One way to check the message is to compare NPDU - src, dest, along with the APDU type, invoke id. - Seems a bit overkill */ - struct DER_compare_t { - BACNET_NPDU_DATA npdu_data; - BACNET_ADDRESS address; - uint8_t pdu_type; - uint8_t invoke_id; - uint8_t service_choice; - }; - struct DER_compare_t request; - struct DER_compare_t reply; - - /* decode the request data */ - request.address.mac[0] = src_address; - request.address.mac_len = 1; - offset = - npdu_decode(&request_pdu[0], NULL, &request.address, - &request.npdu_data); - if (request.npdu_data.network_layer_message) { - return false; - } - request.pdu_type = request_pdu[offset] & 0xF0; - if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { - return false; - } - request.invoke_id = request_pdu[offset + 2]; - /* segmented message? */ - if (request_pdu[offset] & BIT3) - request.service_choice = request_pdu[offset + 5]; - else - request.service_choice = request_pdu[offset + 3]; - /* decode the reply data */ - reply.address.mac[0] = dest_address; - reply.address.mac_len = 1; - offset = - npdu_decode(&reply_pdu[0], &reply.address, NULL, &reply.npdu_data); - if (reply.npdu_data.network_layer_message) { - return false; - } - /* reply could be a lot of things: - confirmed, simple ack, abort, reject, error */ - reply.pdu_type = reply_pdu[offset] & 0xF0; - switch (reply.pdu_type) { - case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: - reply.invoke_id = reply_pdu[offset + 2]; - /* segmented message? */ - if (reply_pdu[offset] & BIT3) - reply.service_choice = reply_pdu[offset + 5]; - else - reply.service_choice = reply_pdu[offset + 3]; - break; - case PDU_TYPE_SIMPLE_ACK: - reply.invoke_id = reply_pdu[offset + 1]; - reply.service_choice = reply_pdu[offset + 2]; - break; - case PDU_TYPE_COMPLEX_ACK: - reply.invoke_id = reply_pdu[offset + 1]; - /* segmented message? */ - if (reply_pdu[offset] & BIT3) - reply.service_choice = reply_pdu[offset + 4]; - else - reply.service_choice = reply_pdu[offset + 2]; - break; - case PDU_TYPE_ERROR: - reply.invoke_id = reply_pdu[offset + 1]; - reply.service_choice = reply_pdu[offset + 2]; - break; - case PDU_TYPE_REJECT: - case PDU_TYPE_ABORT: - reply.invoke_id = reply_pdu[offset + 1]; - break; - default: - return false; - } - if (request.invoke_id != reply.invoke_id) { - return false; - } - /* these services don't have service choice included */ - if ((reply.pdu_type != PDU_TYPE_REJECT) && - (reply.pdu_type != PDU_TYPE_ABORT)) { - if (request.service_choice != reply.service_choice) { - return false; - } - } - if (request.npdu_data.protocol_version != reply.npdu_data.protocol_version) { - return false; - } - if (request.npdu_data.priority != reply.npdu_data.priority) { - return false; - } - if (!bacnet_address_same(&request.address, &reply.address)) { - return false; - } - - return true; -} - -/* 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 * data, /* any data to be sent - may be null */ - uint16_t data_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 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] = data_len / 256; - crc8 = CRC_Calc_Header(buffer[5], crc8); - buffer[6] = data_len % 256; - crc8 = CRC_Calc_Header(buffer[6], crc8); - buffer[7] = ~crc8; - rs485_turnaround_delay(); - rs485_rts_enable(true); - rs485_bytes_send(buffer, 8); - /* send any data */ - if (data_len) { - /* calculate CRC for any data */ - for (i = 0; i < data_len; i++) { - crc16 = CRC_Calc_Data(data[i], crc16); - } - crc16 = ~crc16; - buffer[0] = (crc16 & 0x00FF); - buffer[1] = ((crc16 & 0xFF00) >> 8); - rs485_bytes_send(data, data_len); - rs485_bytes_send(buffer, 2); - } - rs485_rts_enable(false); -} - -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 uint16_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_receive_error()) { - /* EatAnError */ - timer_reset(TIMER_SILENCE); - INCREMENT_AND_LIMIT_UINT8(EventCount); - } else if (rs485_byte_available(&DataRegister)) { - timer_reset(TIMER_SILENCE); - INCREMENT_AND_LIMIT_UINT8(EventCount); - 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_elapsed_milliseconds(TIMER_SILENCE, 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_receive_error()) { - /* Error */ - timer_reset(TIMER_SILENCE); - INCREMENT_AND_LIMIT_UINT8(EventCount); - /* wait for the start of a frame. */ - Receive_State = MSTP_RECEIVE_STATE_IDLE; - } else if (rs485_byte_available(&DataRegister)) { - timer_reset(TIMER_SILENCE); - INCREMENT_AND_LIMIT_UINT8(EventCount); - 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_elapsed_milliseconds(TIMER_SILENCE, 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_receive_error()) { - /* Error */ - timer_reset(TIMER_SILENCE); - INCREMENT_AND_LIMIT_UINT8(EventCount); - /* 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_byte_available(&DataRegister)) { - timer_reset(TIMER_SILENCE); - INCREMENT_AND_LIMIT_UINT8(EventCount); - 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_elapsed_milliseconds(TIMER_SILENCE, 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_receive_error()) { - /* Error */ - timer_reset(TIMER_SILENCE); - INCREMENT_AND_LIMIT_UINT8(EventCount); - /* 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_byte_available(&DataRegister)) { - timer_reset(TIMER_SILENCE); - INCREMENT_AND_LIMIT_UINT8(EventCount); - 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; -} - -/* returns true if we need to transition immediately */ -static bool MSTP_Master_Node_FSM( - void) -{ - /* The number of frames sent by this node during a single token hold. */ - /* When this counter reaches the value Nmax_info_frames, the node must */ - /* pass the token. */ - static uint8_t FrameCount; - /* "Next Station," the MAC address of the node to which This Station - passes the token. If the Next_Station is unknown, Next_Station shall - be equal to This_Station. */ - static uint8_t Next_Station; - /* "Poll Station," the MAC address of the node to which This Station last */ - /* sent a Poll For Master. This is used during token maintenance. */ - static uint8_t Poll_Station; - /* A counter of transmission retries used for Token and Poll For Master */ - /* transmission. */ - static unsigned RetryCount; - /* The number of tokens received by this node. When this counter reaches */ - /* the value Npoll, the node polls the address range between TS and NS */ - /* for additional master nodes. TokenCount is set to zero at the end of */ - /* the polling process. */ - static unsigned TokenCount; - /* next-x-station calculations */ - uint8_t next_poll_station = 0; - uint8_t next_this_station = 0; - uint8_t next_next_station = 0; - /* timeout values */ - uint16_t my_timeout = 10, ns_timeout = 0; - bool matched = false; - /* transition immediately to the next state */ - bool transition_now = false; - - /* some calculations that several states need */ - next_poll_station = (Poll_Station + 1) % (Nmax_master + 1); - next_this_station = (This_Station + 1) % (Nmax_master + 1); - next_next_station = (Next_Station + 1) % (Nmax_master + 1); - switch (Master_State) { - case MSTP_MASTER_STATE_INITIALIZE: - /* DoneInitializing */ - /* indicate that the next station is unknown */ - Next_Station = This_Station; - Poll_Station = This_Station; - /* cause a Poll For Master to be sent when this node first */ - /* receives the token */ - TokenCount = Npoll; - MSTP_Flag.SoleMaster = false; - Master_State = MSTP_MASTER_STATE_IDLE; - transition_now = true; - break; - case MSTP_MASTER_STATE_IDLE: - /* In the IDLE state, the node waits for a frame. */ - if (timer_elapsed_milliseconds(TIMER_SILENCE, Tno_token)) { - /* LostToken */ - /* assume that the token has been lost */ - EventCount = 0; /* Addendum 135-2004d-8 */ - Master_State = MSTP_MASTER_STATE_NO_TOKEN; - transition_now = true; - } else if (MSTP_Flag.ReceivedInvalidFrame == true) { - /* ReceivedInvalidFrame */ - /* invalid frame was received */ - MSTP_Flag.ReceivedInvalidFrame = false; - /* wait for the next frame - remain in IDLE */ - } else if (MSTP_Flag.ReceivedValidFrame == true) { - switch (FrameType) { - case FRAME_TYPE_TOKEN: - /* ReceivedToken */ - /* tokens can't be broadcast */ - if (DestinationAddress == MSTP_BROADCAST_ADDRESS) - break; - MSTP_Flag.ReceivedValidFrame = false; - FrameCount = 0; - MSTP_Flag.SoleMaster = false; - Master_State = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - break; - case FRAME_TYPE_POLL_FOR_MASTER: - /* ReceivedPFM */ - MSTP_Send_Frame(FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, - SourceAddress, This_Station, NULL, 0); - break; - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - /* indicate successful reception to the higher layers */ - MSTP_Flag.ReceivePacketPending = true; - break; - case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - /* indicate successful reception to higher layers */ - MSTP_Flag.ReceivePacketPending = true; - /* broadcast DER just remains IDLE */ - if (DestinationAddress != MSTP_BROADCAST_ADDRESS) { - Master_State = - MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; - } - 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; - } - /* For DATA_EXPECTING_REPLY, we will keep the Rx Frame for - reference, and the flag will be cleared in the next state */ - if (Master_State != MSTP_MASTER_STATE_ANSWER_DATA_REQUEST) { - MSTP_Flag.ReceivedValidFrame = false; - } - } - break; - /* In the USE_TOKEN state, the node is allowed to send one or */ - /* more data frames. These may be BACnet Data frames or */ - /* proprietary frames. */ - case MSTP_MASTER_STATE_USE_TOKEN: - /* Note: We could wait for up to Tusage_delay */ - if (!MSTP_Flag.TransmitPacketPending) { - /* NothingToSend */ - FrameCount = Nmax_info_frames; - Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; - transition_now = true; - } else { - uint8_t frame_type; - if (MSTP_Flag.TransmitPacketDER) { - frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; - } else { - frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; - } - MSTP_Send_Frame(frame_type, TransmitPacketDest, This_Station, - (uint8_t *) & TransmitPacket[0], TransmitPacketLen); - MSTP_Flag.TransmitPacketPending = false; - FrameCount++; - switch (frame_type) { - case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - /* SendAndWait */ - if (TransmitPacketDest == MSTP_BROADCAST_ADDRESS) - Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; - else - Master_State = MSTP_MASTER_STATE_WAIT_FOR_REPLY; - break; - case FRAME_TYPE_TEST_REQUEST: - Master_State = MSTP_MASTER_STATE_WAIT_FOR_REPLY; - break; - case FRAME_TYPE_TEST_RESPONSE: - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - default: - /* SendNoWait */ - Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; - break; - } - } - break; - case MSTP_MASTER_STATE_WAIT_FOR_REPLY: - /* In the WAIT_FOR_REPLY state, the node waits for */ - /* a reply from another node. */ - if (timer_elapsed_milliseconds(TIMER_SILENCE, Treply_timeout)) { - /* ReplyTimeout */ - /* assume that the request has failed */ - FrameCount = Nmax_info_frames; - Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; - /* Any retry of the data frame shall await the next entry */ - /* to the USE_TOKEN state. */ - /* (Because of the length of the timeout, */ - /* this transition will cause the token to be */ - /* passed regardless */ - /* of the initial value of FrameCount.) */ - transition_now = true; - } else { - if (MSTP_Flag.ReceivedInvalidFrame == true) { - /* InvalidFrame */ - /* error in frame reception */ - MSTP_Flag.ReceivedInvalidFrame = false; - Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; - transition_now = true; - } else if (MSTP_Flag.ReceivedValidFrame == true) { - if (DestinationAddress == This_Station) { - /* What did we receive? */ - switch (FrameType) { - case FRAME_TYPE_REPLY_POSTPONED: - /* ReceivedReplyPostponed */ - Master_State = - MSTP_MASTER_STATE_DONE_WITH_TOKEN; - break; - case FRAME_TYPE_TEST_RESPONSE: - Master_State = MSTP_MASTER_STATE_IDLE; - break; - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - /* ReceivedReply */ - /* or a proprietary type that indicates - a reply */ - /* indicate successful reception to - the higher layers */ - MSTP_Flag.ReceivePacketPending = true; - Master_State = - MSTP_MASTER_STATE_DONE_WITH_TOKEN; - break; - default: - /* if proprietary frame was expected, you might - need to transition to DONE WITH TOKEN */ - Master_State = MSTP_MASTER_STATE_IDLE; - break; - } - } else { - /* ReceivedUnexpectedFrame */ - /* an unexpected frame was received */ - /* This may indicate the presence of multiple tokens */ - /* or a device that didn't see activity after passing */ - /* a token (how lame!). */ - /* Synchronize with the network. */ - /* This action drops the token. */ - Master_State = MSTP_MASTER_STATE_IDLE; - } - MSTP_Flag.ReceivedValidFrame = false; - transition_now = true; - } - } - break; - /* The DONE_WITH_TOKEN state either sends another data frame, */ - /* passes the token, or initiates a Poll For Master cycle. */ - case MSTP_MASTER_STATE_DONE_WITH_TOKEN: - /* SendAnotherFrame */ - if (FrameCount < Nmax_info_frames) { - /* then this node may send another information frame */ - /* before passing the token. */ - Master_State = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - } - /* Npoll changed in Errata SSPC-135-2004 */ - else if (TokenCount < (Npoll - 1)) { - if ((MSTP_Flag.SoleMaster == true) && - (Next_Station != next_this_station)) { - /* SoleMaster */ - /* there are no other known master nodes to */ - /* which the token may be sent - (true master-slave operation). */ - FrameCount = 0; - TokenCount++; - Master_State = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - } else { - /* SendToken */ - /* Npoll changed in Errata SSPC-135-2004 */ - /* The comparison of NS and TS+1 - eliminates the Poll For Master - if there are no addresses between - TS and NS, since there is no - address at which a new master node - may be found in that case. */ - TokenCount++; - /* transmit a Token frame to NS */ - MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, - This_Station, NULL, 0); - RetryCount = 0; - EventCount = 0; - Master_State = MSTP_MASTER_STATE_PASS_TOKEN; - } - } else if (next_poll_station == Next_Station) { - if (MSTP_Flag.SoleMaster == true) { - /* SoleMasterRestartMaintenancePFM */ - Poll_Station = next_next_station; - MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, - This_Station, NULL, 0); - /* no known successor node */ - Next_Station = This_Station; - RetryCount = 0; - TokenCount = 1; /* changed in Errata SSPC-135-2004 */ - /* EventCount = 0; removed in Addendum 135-2004d-8 */ - /* find a new successor to TS */ - Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; - } else { - /* ResetMaintenancePFM */ - Poll_Station = This_Station; - /* transmit a Token frame to NS */ - MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, - This_Station, NULL, 0); - RetryCount = 0; - TokenCount = 1; /* changed in Errata SSPC-135-2004 */ - EventCount = 0; - Master_State = MSTP_MASTER_STATE_PASS_TOKEN; - } - } else { - /* SendMaintenancePFM */ - Poll_Station = next_poll_station; - MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, - This_Station, NULL, 0); - RetryCount = 0; - Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; - } - break; - /* The PASS_TOKEN state listens for a successor to begin using */ - /* the token that this node has just attempted to pass. */ - case MSTP_MASTER_STATE_PASS_TOKEN: - if (timer_elapsed_milliseconds(TIMER_SILENCE, Tusage_timeout)) { - if (RetryCount < Nretry_token) { - /* RetrySendToken */ - RetryCount++; - /* Transmit a Token frame to NS */ - MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, - This_Station, NULL, 0); - EventCount = 0; - /* re-enter the current state to listen for NS */ - /* to begin using the token. */ - } else { - /* FindNewSuccessor */ - /* Assume that NS has failed. */ - Poll_Station = next_next_station; - /* Transmit a Poll For Master frame to PS. */ - MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, - This_Station, NULL, 0); - /* no known successor node */ - Next_Station = This_Station; - RetryCount = 0; - TokenCount = 0; - /* EventCount = 0; removed in Addendum 135-2004d-8 */ - /* find a new successor to TS */ - Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; - } - } else { - if (EventCount > Nmin_octets) { - /* SawTokenUser */ - /* Assume that a frame has been sent by - the new token user. */ - /* Enter the IDLE state to process the frame. */ - Master_State = MSTP_MASTER_STATE_IDLE; - transition_now = true; - } - } - break; - /* The NO_TOKEN state is entered if Silence Timer - becomes greater than Tno_token, indicating that - there has been no network activity for that period - of time. The timeout is continued to determine - whether or not this node may create a token. */ - case MSTP_MASTER_STATE_NO_TOKEN: - my_timeout = Tno_token + (Tslot * This_Station); - if (timer_elapsed_milliseconds(TIMER_SILENCE, my_timeout)) { - ns_timeout = Tno_token + (Tslot * (This_Station + 1)); - if (timer_elapsed_milliseconds(TIMER_SILENCE, ns_timeout)) { - /* should never get here unless timer resolution is bad */ - timer_reset(TIMER_SILENCE); - Master_State = MSTP_MASTER_STATE_IDLE; - } else { - /* GenerateToken */ - /* Assume that this node is the lowest numerical address */ - /* on the network and is empowered to create a token. */ - Poll_Station = next_this_station; - /* Transmit a Poll For Master frame to PS. */ - MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, - This_Station, NULL, 0); - /* indicate that the next station is unknown */ - Next_Station = This_Station; - RetryCount = 0; - TokenCount = 0; - /* EventCount = 0; removed Addendum 135-2004d-8 */ - /* enter the POLL_FOR_MASTER state - to find a new successor to TS. */ - Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; - } - } else { - if (EventCount > Nmin_octets) { - /* SawFrame */ - /* Some other node exists at a lower address. */ - /* Enter the IDLE state to receive and - process the incoming frame. */ - Master_State = MSTP_MASTER_STATE_IDLE; - transition_now = true; - } - } - break; - /* In the POLL_FOR_MASTER state, the node listens for a reply to */ - /* a previously sent Poll For Master frame in order to find */ - /* a successor node. */ - case MSTP_MASTER_STATE_POLL_FOR_MASTER: - if (MSTP_Flag.ReceivedValidFrame == true) { - if ((DestinationAddress == This_Station) - && (FrameType == FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER)) { - /* ReceivedReplyToPFM */ - MSTP_Flag.SoleMaster = false; - Next_Station = SourceAddress; - EventCount = 0; - /* Transmit a Token frame to NS */ - MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, - This_Station, NULL, 0); - Poll_Station = This_Station; - TokenCount = 0; - RetryCount = 0; - Master_State = MSTP_MASTER_STATE_PASS_TOKEN; - } else { - /* ReceivedUnexpectedFrame */ - /* An unexpected frame was received. */ - /* This may indicate the presence of multiple tokens. */ - /* enter the IDLE state to synchronize with the network. */ - /* This action drops the token. */ - Master_State = MSTP_MASTER_STATE_IDLE; - transition_now = true; - } - MSTP_Flag.ReceivedValidFrame = false; - } else if ((timer_elapsed_milliseconds(TIMER_SILENCE, - Tusage_timeout)) || - (MSTP_Flag.ReceivedInvalidFrame == true)) { - if (MSTP_Flag.SoleMaster == true) { - /* SoleMaster */ - /* There was no valid reply to the periodic poll */ - /* by the sole known master for other masters. */ - FrameCount = 0; - /* TokenCount++; removed in 2004 */ - Master_State = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - } else { - if (Next_Station != This_Station) { - /* DoneWithPFM */ - /* There was no valid reply to the maintenance */ - /* poll for a master at address PS. */ - EventCount = 0; - /* transmit a Token frame to NS */ - MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, - This_Station, NULL, 0); - RetryCount = 0; - Master_State = MSTP_MASTER_STATE_PASS_TOKEN; - } else { - if (next_poll_station != This_Station) { - /* SendNextPFM */ - Poll_Station = next_poll_station; - /* Transmit a Poll For Master frame to PS. */ - MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, - Poll_Station, This_Station, NULL, 0); - RetryCount = 0; - /* Re-enter the current state. */ - } else { - /* DeclareSoleMaster */ - /* to indicate that this station - is the only master */ - MSTP_Flag.SoleMaster = true; - FrameCount = 0; - Master_State = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - } - } - } - MSTP_Flag.ReceivedInvalidFrame = false; - } - break; - /* The ANSWER_DATA_REQUEST state is entered when a */ - /* BACnet Data Expecting Reply, a Test_Request, or */ - /* a proprietary frame that expects a reply is received. */ - case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: - /* Note: we could wait for up to Treply_delay */ - if (MSTP_Flag.TransmitPacketPending) { - matched = - dlmstp_compare_data_expecting_reply(&InputBuffer[0], - DataLength, SourceAddress, &TransmitPacket[0], - TransmitPacketLen, TransmitPacketDest); - } - if (MSTP_Flag.TransmitPacketPending && matched) { - /* 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. */ - uint8_t frame_type; - if (MSTP_Flag.TransmitPacketDER) { - frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; - } else { - frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; - } - MSTP_Send_Frame(frame_type, TransmitPacketDest, This_Station, - (uint8_t *) & TransmitPacket[0], TransmitPacketLen); - MSTP_Flag.TransmitPacketPending = false; - Master_State = MSTP_MASTER_STATE_IDLE; - } else { - /* DeferredReply */ - /* If no reply will be 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 an immediate reply is not possible. */ - /* Any reply shall wait until this node receives the token. */ - /* Call MSTP_Send_Frame to transmit a Reply Postponed frame, */ - /* and enter the IDLE state. */ - MSTP_Send_Frame(FRAME_TYPE_REPLY_POSTPONED, SourceAddress, - This_Station, NULL, 0); - Master_State = MSTP_MASTER_STATE_IDLE; - } - /* clear our flag we were holding for comparison */ - MSTP_Flag.ReceivedValidFrame = false; - break; - default: - Master_State = MSTP_MASTER_STATE_IDLE; - break; - } - - return transition_now; -} - -/* 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 */ - - /* 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)) { - 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) { - while (MSTP_Master_Node_FSM()) { - /* do nothing while some states fast transition */ - }; - } - /* 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); */ - if (mac_address > Nmax_master) - dlmstp_set_max_master(mac_address); - } - - return; -} - -uint8_t dlmstp_mac_address( - void) -{ - return This_Station; -} - -/* This parameter represents the value of the Max_Info_Frames property of */ -/* the node's Device object. The value of Max_Info_Frames specifies the */ -/* maximum number of information frames the node may send before it must */ -/* pass the token. Max_Info_Frames may have different values on different */ -/* nodes. This may be used to allocate more or less of the available link */ -/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ -/* node, its value shall be 1. */ -void dlmstp_set_max_info_frames( - uint8_t max_info_frames) -{ - if (max_info_frames >= 1) { - Nmax_info_frames = max_info_frames; - /* FIXME: implement your data storage */ - /* I2C_Write_Byte( - EEPROM_DEVICE_ADDRESS, - (uint8_t)max_info_frames, - EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */ - } - - return; -} - -uint8_t dlmstp_max_info_frames( - void) -{ - return Nmax_info_frames; -} - -/* This parameter represents the value of the Max_Master property of the */ -/* node's Device object. The value of Max_Master specifies the highest */ -/* allowable address for master nodes. The value of Max_Master shall be */ -/* less than or equal to 127. If Max_Master is not writable in a node, */ -/* its value shall be 127. */ -void dlmstp_set_max_master( - uint8_t max_master) -{ - if (max_master <= 127) { - if (This_Station <= max_master) { - Nmax_master = max_master; - /* FIXME: implement your data storage */ - /* I2C_Write_Byte( - EEPROM_DEVICE_ADDRESS, - max_master, - EEPROM_MSTP_MAX_MASTER_ADDR); */ - } - } - - return; -} - -uint8_t dlmstp_max_master( - void) -{ - return Nmax_master; -} - -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; -} +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2009 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 "timer.h" + +/* This file has been customized for use with small microprocessors */ +/* Assumptions: + Only one MS/TP datalink layer +*/ + +/* 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; + +/* master node FSM states */ +typedef enum { + MSTP_MASTER_STATE_INITIALIZE = 0, + MSTP_MASTER_STATE_IDLE = 1, + MSTP_MASTER_STATE_USE_TOKEN = 2, + MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3, + MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4, + MSTP_MASTER_STATE_PASS_TOKEN = 5, + MSTP_MASTER_STATE_NO_TOKEN = 6, + MSTP_MASTER_STATE_POLL_FOR_MASTER = 7, + MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8 +} MSTP_MASTER_STATE; + +/* The state of the Receive State Machine */ +static MSTP_RECEIVE_STATE Receive_State; +/* When a master node is powered up or reset, */ +/* it shall unconditionally enter the INITIALIZE state. */ +static MSTP_MASTER_STATE Master_State; +/* bit-sized boolean flags */ +static struct mstp_flag_t { + /* A Boolean flag set to TRUE by the Receive State Machine */ + /* if an invalid frame is received. */ + /* Set to FALSE by the main state machine. */ + unsigned ReceivedInvalidFrame:1; + /* A Boolean flag set to TRUE by the Receive State Machine */ + /* if a valid frame is received. */ + /* Set to FALSE by the main state machine. */ + unsigned ReceivedValidFrame:1; + /* A Boolean flag set to TRUE by the master machine if this node is the */ + /* only known master node. */ + unsigned SoleMaster: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; + +/* 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 count the number of received octets or errors. */ +/* This is used in the detection of link activity. */ +/* Compared to Nmin_octets */ +static uint8_t EventCount; +/* 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; +/* This parameter represents the value of the Max_Info_Frames property of */ +/* the node's Device object. The value of Max_Info_Frames specifies the */ +/* maximum number of information frames the node may send before it must */ +/* pass the token. Max_Info_Frames may have different values on different */ +/* nodes. This may be used to allocate more or less of the available link */ +/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ +/* node, its value shall be 1. */ +static uint8_t Nmax_info_frames = 1; +/* This parameter represents the value of the Max_Master property of the */ +/* node's Device object. The value of Max_Master specifies the highest */ +/* allowable address for master nodes. The value of Max_Master shall be */ +/* less than or equal to 127. If Max_Master is not writable in a node, */ +/* its value shall be 127. */ +static uint8_t Nmax_master = 127; +/* 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 time without a DataAvailable or ReceiveError event before declaration */ +/* of loss of token: 500 milliseconds. */ +#define Tno_token 500 + +/* The minimum time without a DataAvailable or ReceiveError event */ +/* that a node must wait for a station to begin replying to a */ +/* confirmed request: 255 milliseconds. (Implementations may use */ +/* larger values for this timeout, not to exceed 300 milliseconds.) */ +#define Treply_timeout 260 + +/* The minimum time without a DataAvailable or ReceiveError event that a */ +/* node must wait for a remote node to begin using a token or replying to */ +/* a Poll For Master frame: 20 milliseconds. (Implementations may use */ +/* larger values for this timeout, not to exceed 100 milliseconds.) */ +#define Tusage_timeout 25 + +/* The number of tokens received or used before a Poll For Master cycle */ +/* is executed: 50. */ +#define Npoll 50 + +/* The number of retries on sending Token: 1. */ +#define Nretry_token 1 + +/* The minimum number of DataAvailable or ReceiveError events that must be */ +/* seen by a receiving node in order to declare the line "active": 4. */ +#define Nmin_octets 4 + +/* 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 after the end of the stop bit of the final */ +/* octet of a transmitted frame before a node must disable its */ +/* EIA-485 driver: 15 bit times. */ +#define Tpostdrive 15 + +/* 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; + + 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; + } +} + +static bool dlmstp_compare_data_expecting_reply( + uint8_t * request_pdu, + uint16_t request_pdu_len, + uint8_t src_address, + uint8_t * reply_pdu, + uint16_t reply_pdu_len, + uint8_t dest_address) +{ + uint16_t offset; + /* One way to check the message is to compare NPDU + src, dest, along with the APDU type, invoke id. + Seems a bit overkill */ + struct DER_compare_t { + BACNET_NPDU_DATA npdu_data; + BACNET_ADDRESS address; + uint8_t pdu_type; + uint8_t invoke_id; + uint8_t service_choice; + }; + struct DER_compare_t request; + struct DER_compare_t reply; + + /* decode the request data */ + request.address.mac[0] = src_address; + request.address.mac_len = 1; + offset = + npdu_decode(&request_pdu[0], NULL, &request.address, + &request.npdu_data); + if (request.npdu_data.network_layer_message) { + return false; + } + request.pdu_type = request_pdu[offset] & 0xF0; + if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { + return false; + } + request.invoke_id = request_pdu[offset + 2]; + /* segmented message? */ + if (request_pdu[offset] & BIT3) + request.service_choice = request_pdu[offset + 5]; + else + request.service_choice = request_pdu[offset + 3]; + /* decode the reply data */ + reply.address.mac[0] = dest_address; + reply.address.mac_len = 1; + offset = + npdu_decode(&reply_pdu[0], &reply.address, NULL, &reply.npdu_data); + if (reply.npdu_data.network_layer_message) { + return false; + } + /* reply could be a lot of things: + confirmed, simple ack, abort, reject, error */ + reply.pdu_type = reply_pdu[offset] & 0xF0; + switch (reply.pdu_type) { + case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: + reply.invoke_id = reply_pdu[offset + 2]; + /* segmented message? */ + if (reply_pdu[offset] & BIT3) + reply.service_choice = reply_pdu[offset + 5]; + else + reply.service_choice = reply_pdu[offset + 3]; + break; + case PDU_TYPE_SIMPLE_ACK: + reply.invoke_id = reply_pdu[offset + 1]; + reply.service_choice = reply_pdu[offset + 2]; + break; + case PDU_TYPE_COMPLEX_ACK: + reply.invoke_id = reply_pdu[offset + 1]; + /* segmented message? */ + if (reply_pdu[offset] & BIT3) + reply.service_choice = reply_pdu[offset + 4]; + else + reply.service_choice = reply_pdu[offset + 2]; + break; + case PDU_TYPE_ERROR: + reply.invoke_id = reply_pdu[offset + 1]; + reply.service_choice = reply_pdu[offset + 2]; + break; + case PDU_TYPE_REJECT: + case PDU_TYPE_ABORT: + reply.invoke_id = reply_pdu[offset + 1]; + break; + default: + return false; + } + if (request.invoke_id != reply.invoke_id) { + return false; + } + /* these services don't have service choice included */ + if ((reply.pdu_type != PDU_TYPE_REJECT) && + (reply.pdu_type != PDU_TYPE_ABORT)) { + if (request.service_choice != reply.service_choice) { + return false; + } + } + if (request.npdu_data.protocol_version != reply.npdu_data.protocol_version) { + return false; + } + if (request.npdu_data.priority != reply.npdu_data.priority) { + return false; + } + if (!bacnet_address_same(&request.address, &reply.address)) { + return false; + } + + return true; +} + +/* 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 * data, /* any data to be sent - may be null */ + uint16_t data_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 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] = data_len / 256; + crc8 = CRC_Calc_Header(buffer[5], crc8); + buffer[6] = data_len % 256; + crc8 = CRC_Calc_Header(buffer[6], crc8); + buffer[7] = ~crc8; + rs485_turnaround_delay(); + rs485_rts_enable(true); + rs485_bytes_send(buffer, 8); + /* send any data */ + if (data_len) { + /* calculate CRC for any data */ + for (i = 0; i < data_len; i++) { + crc16 = CRC_Calc_Data(data[i], crc16); + } + crc16 = ~crc16; + buffer[0] = (crc16 & 0x00FF); + buffer[1] = ((crc16 & 0xFF00) >> 8); + rs485_bytes_send(data, data_len); + rs485_bytes_send(buffer, 2); + } + rs485_rts_enable(false); +} + +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 uint16_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_receive_error()) { + /* EatAnError */ + timer_reset(TIMER_SILENCE); + INCREMENT_AND_LIMIT_UINT8(EventCount); + } else if (rs485_byte_available(&DataRegister)) { + timer_reset(TIMER_SILENCE); + INCREMENT_AND_LIMIT_UINT8(EventCount); + 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_elapsed_milliseconds(TIMER_SILENCE, 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_receive_error()) { + /* Error */ + timer_reset(TIMER_SILENCE); + INCREMENT_AND_LIMIT_UINT8(EventCount); + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (rs485_byte_available(&DataRegister)) { + timer_reset(TIMER_SILENCE); + INCREMENT_AND_LIMIT_UINT8(EventCount); + 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_elapsed_milliseconds(TIMER_SILENCE, 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_receive_error()) { + /* Error */ + timer_reset(TIMER_SILENCE); + INCREMENT_AND_LIMIT_UINT8(EventCount); + /* 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_byte_available(&DataRegister)) { + timer_reset(TIMER_SILENCE); + INCREMENT_AND_LIMIT_UINT8(EventCount); + 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_elapsed_milliseconds(TIMER_SILENCE, 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_receive_error()) { + /* Error */ + timer_reset(TIMER_SILENCE); + INCREMENT_AND_LIMIT_UINT8(EventCount); + /* 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_byte_available(&DataRegister)) { + timer_reset(TIMER_SILENCE); + INCREMENT_AND_LIMIT_UINT8(EventCount); + 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; +} + +/* returns true if we need to transition immediately */ +static bool MSTP_Master_Node_FSM( + void) +{ + /* The number of frames sent by this node during a single token hold. */ + /* When this counter reaches the value Nmax_info_frames, the node must */ + /* pass the token. */ + static uint8_t FrameCount; + /* "Next Station," the MAC address of the node to which This Station + passes the token. If the Next_Station is unknown, Next_Station shall + be equal to This_Station. */ + static uint8_t Next_Station; + /* "Poll Station," the MAC address of the node to which This Station last */ + /* sent a Poll For Master. This is used during token maintenance. */ + static uint8_t Poll_Station; + /* A counter of transmission retries used for Token and Poll For Master */ + /* transmission. */ + static unsigned RetryCount; + /* The number of tokens received by this node. When this counter reaches */ + /* the value Npoll, the node polls the address range between TS and NS */ + /* for additional master nodes. TokenCount is set to zero at the end of */ + /* the polling process. */ + static unsigned TokenCount; + /* next-x-station calculations */ + uint8_t next_poll_station = 0; + uint8_t next_this_station = 0; + uint8_t next_next_station = 0; + /* timeout values */ + uint16_t my_timeout = 10, ns_timeout = 0; + bool matched = false; + /* transition immediately to the next state */ + bool transition_now = false; + + /* some calculations that several states need */ + next_poll_station = (Poll_Station + 1) % (Nmax_master + 1); + next_this_station = (This_Station + 1) % (Nmax_master + 1); + next_next_station = (Next_Station + 1) % (Nmax_master + 1); + switch (Master_State) { + case MSTP_MASTER_STATE_INITIALIZE: + /* DoneInitializing */ + /* indicate that the next station is unknown */ + Next_Station = This_Station; + Poll_Station = This_Station; + /* cause a Poll For Master to be sent when this node first */ + /* receives the token */ + TokenCount = Npoll; + MSTP_Flag.SoleMaster = false; + Master_State = MSTP_MASTER_STATE_IDLE; + transition_now = true; + break; + case MSTP_MASTER_STATE_IDLE: + /* In the IDLE state, the node waits for a frame. */ + if (timer_elapsed_milliseconds(TIMER_SILENCE, Tno_token)) { + /* LostToken */ + /* assume that the token has been lost */ + EventCount = 0; /* Addendum 135-2004d-8 */ + Master_State = MSTP_MASTER_STATE_NO_TOKEN; + transition_now = true; + } else if (MSTP_Flag.ReceivedInvalidFrame == true) { + /* ReceivedInvalidFrame */ + /* invalid frame was received */ + MSTP_Flag.ReceivedInvalidFrame = false; + /* wait for the next frame - remain in IDLE */ + } else if (MSTP_Flag.ReceivedValidFrame == true) { + switch (FrameType) { + case FRAME_TYPE_TOKEN: + /* ReceivedToken */ + /* tokens can't be broadcast */ + if (DestinationAddress == MSTP_BROADCAST_ADDRESS) + break; + MSTP_Flag.ReceivedValidFrame = false; + FrameCount = 0; + MSTP_Flag.SoleMaster = false; + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + break; + case FRAME_TYPE_POLL_FOR_MASTER: + /* ReceivedPFM */ + MSTP_Send_Frame(FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, + SourceAddress, This_Station, NULL, 0); + break; + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + /* indicate successful reception to the higher layers */ + MSTP_Flag.ReceivePacketPending = true; + break; + case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: + /* indicate successful reception to higher layers */ + MSTP_Flag.ReceivePacketPending = true; + /* broadcast DER just remains IDLE */ + if (DestinationAddress != MSTP_BROADCAST_ADDRESS) { + Master_State = + MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; + } + 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; + } + /* For DATA_EXPECTING_REPLY, we will keep the Rx Frame for + reference, and the flag will be cleared in the next state */ + if (Master_State != MSTP_MASTER_STATE_ANSWER_DATA_REQUEST) { + MSTP_Flag.ReceivedValidFrame = false; + } + } + break; + /* In the USE_TOKEN state, the node is allowed to send one or */ + /* more data frames. These may be BACnet Data frames or */ + /* proprietary frames. */ + case MSTP_MASTER_STATE_USE_TOKEN: + /* Note: We could wait for up to Tusage_delay */ + if (!MSTP_Flag.TransmitPacketPending) { + /* NothingToSend */ + FrameCount = Nmax_info_frames; + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + transition_now = true; + } else { + uint8_t frame_type; + if (MSTP_Flag.TransmitPacketDER) { + frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; + } else { + frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; + } + MSTP_Send_Frame(frame_type, TransmitPacketDest, This_Station, + (uint8_t *) & TransmitPacket[0], TransmitPacketLen); + MSTP_Flag.TransmitPacketPending = false; + FrameCount++; + switch (frame_type) { + case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: + /* SendAndWait */ + if (TransmitPacketDest == MSTP_BROADCAST_ADDRESS) + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + else + Master_State = MSTP_MASTER_STATE_WAIT_FOR_REPLY; + break; + case FRAME_TYPE_TEST_REQUEST: + Master_State = MSTP_MASTER_STATE_WAIT_FOR_REPLY; + break; + case FRAME_TYPE_TEST_RESPONSE: + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + default: + /* SendNoWait */ + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + } + } + break; + case MSTP_MASTER_STATE_WAIT_FOR_REPLY: + /* In the WAIT_FOR_REPLY state, the node waits for */ + /* a reply from another node. */ + if (timer_elapsed_milliseconds(TIMER_SILENCE, Treply_timeout)) { + /* ReplyTimeout */ + /* assume that the request has failed */ + FrameCount = Nmax_info_frames; + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + /* Any retry of the data frame shall await the next entry */ + /* to the USE_TOKEN state. */ + /* (Because of the length of the timeout, */ + /* this transition will cause the token to be */ + /* passed regardless */ + /* of the initial value of FrameCount.) */ + transition_now = true; + } else { + if (MSTP_Flag.ReceivedInvalidFrame == true) { + /* InvalidFrame */ + /* error in frame reception */ + MSTP_Flag.ReceivedInvalidFrame = false; + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + transition_now = true; + } else if (MSTP_Flag.ReceivedValidFrame == true) { + if (DestinationAddress == This_Station) { + /* What did we receive? */ + switch (FrameType) { + case FRAME_TYPE_REPLY_POSTPONED: + /* ReceivedReplyPostponed */ + Master_State = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + case FRAME_TYPE_TEST_RESPONSE: + Master_State = MSTP_MASTER_STATE_IDLE; + break; + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + /* ReceivedReply */ + /* or a proprietary type that indicates + a reply */ + /* indicate successful reception to + the higher layers */ + MSTP_Flag.ReceivePacketPending = true; + Master_State = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + default: + /* if proprietary frame was expected, you might + need to transition to DONE WITH TOKEN */ + Master_State = MSTP_MASTER_STATE_IDLE; + break; + } + } else { + /* ReceivedUnexpectedFrame */ + /* an unexpected frame was received */ + /* This may indicate the presence of multiple tokens */ + /* or a device that didn't see activity after passing */ + /* a token (how lame!). */ + /* Synchronize with the network. */ + /* This action drops the token. */ + Master_State = MSTP_MASTER_STATE_IDLE; + } + MSTP_Flag.ReceivedValidFrame = false; + transition_now = true; + } + } + break; + /* The DONE_WITH_TOKEN state either sends another data frame, */ + /* passes the token, or initiates a Poll For Master cycle. */ + case MSTP_MASTER_STATE_DONE_WITH_TOKEN: + /* SendAnotherFrame */ + if (FrameCount < Nmax_info_frames) { + /* then this node may send another information frame */ + /* before passing the token. */ + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } + /* Npoll changed in Errata SSPC-135-2004 */ + else if (TokenCount < (Npoll - 1)) { + if ((MSTP_Flag.SoleMaster == true) && + (Next_Station != next_this_station)) { + /* SoleMaster */ + /* there are no other known master nodes to */ + /* which the token may be sent + (true master-slave operation). */ + FrameCount = 0; + TokenCount++; + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } else { + /* SendToken */ + /* Npoll changed in Errata SSPC-135-2004 */ + /* The comparison of NS and TS+1 + eliminates the Poll For Master + if there are no addresses between + TS and NS, since there is no + address at which a new master node + may be found in that case. */ + TokenCount++; + /* transmit a Token frame to NS */ + MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, + This_Station, NULL, 0); + RetryCount = 0; + EventCount = 0; + Master_State = MSTP_MASTER_STATE_PASS_TOKEN; + } + } else if (next_poll_station == Next_Station) { + if (MSTP_Flag.SoleMaster == true) { + /* SoleMasterRestartMaintenancePFM */ + Poll_Station = next_next_station; + MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, + This_Station, NULL, 0); + /* no known successor node */ + Next_Station = This_Station; + RetryCount = 0; + TokenCount = 1; /* changed in Errata SSPC-135-2004 */ + /* EventCount = 0; removed in Addendum 135-2004d-8 */ + /* find a new successor to TS */ + Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } else { + /* ResetMaintenancePFM */ + Poll_Station = This_Station; + /* transmit a Token frame to NS */ + MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, + This_Station, NULL, 0); + RetryCount = 0; + TokenCount = 1; /* changed in Errata SSPC-135-2004 */ + EventCount = 0; + Master_State = MSTP_MASTER_STATE_PASS_TOKEN; + } + } else { + /* SendMaintenancePFM */ + Poll_Station = next_poll_station; + MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, + This_Station, NULL, 0); + RetryCount = 0; + Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + break; + /* The PASS_TOKEN state listens for a successor to begin using */ + /* the token that this node has just attempted to pass. */ + case MSTP_MASTER_STATE_PASS_TOKEN: + if (timer_elapsed_milliseconds(TIMER_SILENCE, Tusage_timeout)) { + if (RetryCount < Nretry_token) { + /* RetrySendToken */ + RetryCount++; + /* Transmit a Token frame to NS */ + MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, + This_Station, NULL, 0); + EventCount = 0; + /* re-enter the current state to listen for NS */ + /* to begin using the token. */ + } else { + /* FindNewSuccessor */ + /* Assume that NS has failed. */ + Poll_Station = next_next_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, + This_Station, NULL, 0); + /* no known successor node */ + Next_Station = This_Station; + RetryCount = 0; + TokenCount = 0; + /* EventCount = 0; removed in Addendum 135-2004d-8 */ + /* find a new successor to TS */ + Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + } else { + if (EventCount > Nmin_octets) { + /* SawTokenUser */ + /* Assume that a frame has been sent by + the new token user. */ + /* Enter the IDLE state to process the frame. */ + Master_State = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + } + break; + /* The NO_TOKEN state is entered if Silence Timer + becomes greater than Tno_token, indicating that + there has been no network activity for that period + of time. The timeout is continued to determine + whether or not this node may create a token. */ + case MSTP_MASTER_STATE_NO_TOKEN: + my_timeout = Tno_token + (Tslot * This_Station); + if (timer_elapsed_milliseconds(TIMER_SILENCE, my_timeout)) { + ns_timeout = Tno_token + (Tslot * (This_Station + 1)); + if (timer_elapsed_milliseconds(TIMER_SILENCE, ns_timeout)) { + /* should never get here unless timer resolution is bad */ + timer_reset(TIMER_SILENCE); + Master_State = MSTP_MASTER_STATE_IDLE; + } else { + /* GenerateToken */ + /* Assume that this node is the lowest numerical address */ + /* on the network and is empowered to create a token. */ + Poll_Station = next_this_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, + This_Station, NULL, 0); + /* indicate that the next station is unknown */ + Next_Station = This_Station; + RetryCount = 0; + TokenCount = 0; + /* EventCount = 0; removed Addendum 135-2004d-8 */ + /* enter the POLL_FOR_MASTER state + to find a new successor to TS. */ + Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + } else { + if (EventCount > Nmin_octets) { + /* SawFrame */ + /* Some other node exists at a lower address. */ + /* Enter the IDLE state to receive and + process the incoming frame. */ + Master_State = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + } + break; + /* In the POLL_FOR_MASTER state, the node listens for a reply to */ + /* a previously sent Poll For Master frame in order to find */ + /* a successor node. */ + case MSTP_MASTER_STATE_POLL_FOR_MASTER: + if (MSTP_Flag.ReceivedValidFrame == true) { + if ((DestinationAddress == This_Station) + && (FrameType == FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER)) { + /* ReceivedReplyToPFM */ + MSTP_Flag.SoleMaster = false; + Next_Station = SourceAddress; + EventCount = 0; + /* Transmit a Token frame to NS */ + MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, + This_Station, NULL, 0); + Poll_Station = This_Station; + TokenCount = 0; + RetryCount = 0; + Master_State = MSTP_MASTER_STATE_PASS_TOKEN; + } else { + /* ReceivedUnexpectedFrame */ + /* An unexpected frame was received. */ + /* This may indicate the presence of multiple tokens. */ + /* enter the IDLE state to synchronize with the network. */ + /* This action drops the token. */ + Master_State = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + MSTP_Flag.ReceivedValidFrame = false; + } else if ((timer_elapsed_milliseconds(TIMER_SILENCE, + Tusage_timeout)) || + (MSTP_Flag.ReceivedInvalidFrame == true)) { + if (MSTP_Flag.SoleMaster == true) { + /* SoleMaster */ + /* There was no valid reply to the periodic poll */ + /* by the sole known master for other masters. */ + FrameCount = 0; + /* TokenCount++; removed in 2004 */ + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } else { + if (Next_Station != This_Station) { + /* DoneWithPFM */ + /* There was no valid reply to the maintenance */ + /* poll for a master at address PS. */ + EventCount = 0; + /* transmit a Token frame to NS */ + MSTP_Send_Frame(FRAME_TYPE_TOKEN, Next_Station, + This_Station, NULL, 0); + RetryCount = 0; + Master_State = MSTP_MASTER_STATE_PASS_TOKEN; + } else { + if (next_poll_station != This_Station) { + /* SendNextPFM */ + Poll_Station = next_poll_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Send_Frame(FRAME_TYPE_POLL_FOR_MASTER, + Poll_Station, This_Station, NULL, 0); + RetryCount = 0; + /* Re-enter the current state. */ + } else { + /* DeclareSoleMaster */ + /* to indicate that this station + is the only master */ + MSTP_Flag.SoleMaster = true; + FrameCount = 0; + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } + } + } + MSTP_Flag.ReceivedInvalidFrame = false; + } + break; + /* The ANSWER_DATA_REQUEST state is entered when a */ + /* BACnet Data Expecting Reply, a Test_Request, or */ + /* a proprietary frame that expects a reply is received. */ + case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: + /* Note: we could wait for up to Treply_delay */ + if (MSTP_Flag.TransmitPacketPending) { + matched = + dlmstp_compare_data_expecting_reply(&InputBuffer[0], + DataLength, SourceAddress, &TransmitPacket[0], + TransmitPacketLen, TransmitPacketDest); + } + if (MSTP_Flag.TransmitPacketPending && matched) { + /* 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. */ + uint8_t frame_type; + if (MSTP_Flag.TransmitPacketDER) { + frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; + } else { + frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; + } + MSTP_Send_Frame(frame_type, TransmitPacketDest, This_Station, + (uint8_t *) & TransmitPacket[0], TransmitPacketLen); + MSTP_Flag.TransmitPacketPending = false; + Master_State = MSTP_MASTER_STATE_IDLE; + } else { + /* DeferredReply */ + /* If no reply will be 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 an immediate reply is not possible. */ + /* Any reply shall wait until this node receives the token. */ + /* Call MSTP_Send_Frame to transmit a Reply Postponed frame, */ + /* and enter the IDLE state. */ + MSTP_Send_Frame(FRAME_TYPE_REPLY_POSTPONED, SourceAddress, + This_Station, NULL, 0); + Master_State = MSTP_MASTER_STATE_IDLE; + } + /* clear our flag we were holding for comparison */ + MSTP_Flag.ReceivedValidFrame = false; + break; + default: + Master_State = MSTP_MASTER_STATE_IDLE; + break; + } + + return transition_now; +} + +/* 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 */ + + /* 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)) { + 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) { + while (MSTP_Master_Node_FSM()) { + /* do nothing while some states fast transition */ + }; + } + /* 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); */ + if (mac_address > Nmax_master) + dlmstp_set_max_master(mac_address); + } + + return; +} + +uint8_t dlmstp_mac_address( + void) +{ + return This_Station; +} + +/* This parameter represents the value of the Max_Info_Frames property of */ +/* the node's Device object. The value of Max_Info_Frames specifies the */ +/* maximum number of information frames the node may send before it must */ +/* pass the token. Max_Info_Frames may have different values on different */ +/* nodes. This may be used to allocate more or less of the available link */ +/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ +/* node, its value shall be 1. */ +void dlmstp_set_max_info_frames( + uint8_t max_info_frames) +{ + if (max_info_frames >= 1) { + Nmax_info_frames = max_info_frames; + /* FIXME: implement your data storage */ + /* I2C_Write_Byte( + EEPROM_DEVICE_ADDRESS, + (uint8_t)max_info_frames, + EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */ + } + + return; +} + +uint8_t dlmstp_max_info_frames( + void) +{ + return Nmax_info_frames; +} + +/* This parameter represents the value of the Max_Master property of the */ +/* node's Device object. The value of Max_Master specifies the highest */ +/* allowable address for master nodes. The value of Max_Master shall be */ +/* less than or equal to 127. If Max_Master is not writable in a node, */ +/* its value shall be 127. */ +void dlmstp_set_max_master( + uint8_t max_master) +{ + if (max_master <= 127) { + if (This_Station <= max_master) { + Nmax_master = max_master; + /* FIXME: implement your data storage */ + /* I2C_Write_Byte( + EEPROM_DEVICE_ADDRESS, + max_master, + EEPROM_MSTP_MAX_MASTER_ADDR); */ + } + } + + return; +} + +uint8_t dlmstp_max_master( + void) +{ + return Nmax_master; +} + +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/bdk-atxx4-mstp/eeprom.c b/bacnet-stack/ports/bdk-atxx4-mstp/eeprom.c index 5351139e..af33e1bb 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/eeprom.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/eeprom.c @@ -1,70 +1,70 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" -#include "eeprom.h" - -/* Internal EEPROM of the AVR - http://supp.iar.com/Support/?note=45745 */ - -#if defined(__GNUC__) - /* bug in WinAVR - not quite IAR compatible */ - #define __EEPUT _EEPUT - #define __EEGET _EEGET -#endif - -int eeprom_bytes_read( - uint16_t eeaddr, /* EEPROM starting memory address (offset of zero) */ - uint8_t * buf, /* data to store */ - int len) /* number of bytes of data to read */ -{ - int count = 0; /* return value */ - - while (len) { - __EEGET(buf[count], eeaddr); - count++; - eeaddr++; - len--; - } - - return count; -} - -int eeprom_bytes_write( - uint16_t eeaddr, /* EEPROM starting memory address */ - uint8_t * buf, /* data to send */ - int len) /* number of bytes of data */ -{ - int count = 0; - - while (len) { - __EEPUT(eeaddr, buf[count]); - count++; - eeaddr++; - len--; - } - - return count; -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" +#include "eeprom.h" + +/* Internal EEPROM of the AVR - http://supp.iar.com/Support/?note=45745 */ + +#if defined(__GNUC__) + /* bug in WinAVR - not quite IAR compatible */ +#define __EEPUT _EEPUT +#define __EEGET _EEGET +#endif + +int eeprom_bytes_read( + uint16_t eeaddr, /* EEPROM starting memory address (offset of zero) */ + uint8_t * buf, /* data to store */ + int len) +{ /* number of bytes of data to read */ + int count = 0; /* return value */ + + while (len) { + __EEGET(buf[count], eeaddr); + count++; + eeaddr++; + len--; + } + + return count; +} + +int eeprom_bytes_write( + uint16_t eeaddr, /* EEPROM starting memory address */ + uint8_t * buf, /* data to send */ + int len) +{ /* number of bytes of data */ + int count = 0; + + while (len) { + __EEPUT(eeaddr, buf[count]); + count++; + eeaddr++; + len--; + } + + return count; +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/eeprom.h b/bacnet-stack/ports/bdk-atxx4-mstp/eeprom.h index 59fc61f7..3bb51a8f 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/eeprom.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/eeprom.h @@ -1,46 +1,46 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 EEPROM_H -#define EEPROM_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -int eeprom_bytes_read( - uint16_t ee_address, /* EEPROM starting memory address */ - uint8_t * buffer, /* data to store */ - int nbytes); /* number of bytes of data to read */ -int eeprom_bytes_write( - uint16_t ee_address, /* EEPROM starting memory address */ - uint8_t * buffer, /* data to send */ - int nbytes); /* number of bytes of data */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif +/************************************************************************** +* +* Copyright (C) 2009 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 EEPROM_H +#define EEPROM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + int eeprom_bytes_read( + uint16_t ee_address, /* EEPROM starting memory address */ + uint8_t * buffer, /* data to store */ + int nbytes); /* number of bytes of data to read */ + int eeprom_bytes_write( + uint16_t ee_address, /* EEPROM starting memory address */ + uint8_t * buffer, /* data to send */ + int nbytes); /* number of bytes of data */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/h_rd.c b/bacnet-stack/ports/bdk-atxx4-mstp/h_rd.c index b26d3edc..9f948918 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/h_rd.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/h_rd.c @@ -1,113 +1,113 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "reject.h" -#include "rd.h" - -static char *Password = "rehmite"; -static BACNET_CHARACTER_STRING My_Password; - -void handler_reinitialize_device( - uint8_t * service_request, - uint16_t service_len, - BACNET_ADDRESS * src, - BACNET_CONFIRMED_SERVICE_DATA * service_data) -{ - BACNET_REINITIALIZED_STATE state; - BACNET_CHARACTER_STRING their_password; - int len = 0; - int pdu_len = 0; - BACNET_NPDU_DATA npdu_data; - int bytes_sent = 0; - BACNET_ADDRESS my_address; - - /* encode the NPDU portion of the packet */ - datalink_get_my_address(&my_address); - npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); - pdu_len = - npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, - &npdu_data); - if (service_data->segmented_message) { - len = - abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, - true); - goto RD_ABORT; - } - /* decode the service request only */ - len = - rd_decode_service_request(service_request, service_len, &state, - &their_password); - /* 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); - goto RD_ABORT; - } - /* check the data from the request */ - if (state >= MAX_BACNET_REINITIALIZED_STATE) { - len = - reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION); - } else { - characterstring_init_ansi(&My_Password, Password); - if (characterstring_same(&their_password, &My_Password)) { - len = - encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, - SERVICE_CONFIRMED_REINITIALIZE_DEVICE); - /* FIXME: now you can reboot, restart, quit, or something clever */ - /* Note: you can use a mix of state and password to do specific stuff */ - /* Note: if you don't do something clever like actually restart, - you probably should clear any DCC status and timeouts */ - /* Note: you probably need to send the reply BEFORE restarting */ - } else { - len = - bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, SERVICE_CONFIRMED_REINITIALIZE_DEVICE, - ERROR_CLASS_SERVICES, ERROR_CODE_PASSWORD_FAILURE); - } - } -RD_ABORT: - pdu_len += len; - bytes_sent = - datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], - pdu_len); - - return; -} +/************************************************************************** +* +* Copyright (C) 2009 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 "reject.h" +#include "rd.h" + +static char *Password = "rehmite"; +static BACNET_CHARACTER_STRING My_Password; + +void handler_reinitialize_device( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src, + BACNET_CONFIRMED_SERVICE_DATA * service_data) +{ + BACNET_REINITIALIZED_STATE state; + BACNET_CHARACTER_STRING their_password; + int len = 0; + int pdu_len = 0; + BACNET_NPDU_DATA npdu_data; + int bytes_sent = 0; + BACNET_ADDRESS my_address; + + /* encode the NPDU portion of the packet */ + datalink_get_my_address(&my_address); + npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); + pdu_len = + npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, + &npdu_data); + if (service_data->segmented_message) { + len = + abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, + true); + goto RD_ABORT; + } + /* decode the service request only */ + len = + rd_decode_service_request(service_request, service_len, &state, + &their_password); + /* 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); + goto RD_ABORT; + } + /* check the data from the request */ + if (state >= MAX_BACNET_REINITIALIZED_STATE) { + len = + reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION); + } else { + characterstring_init_ansi(&My_Password, Password); + if (characterstring_same(&their_password, &My_Password)) { + len = + encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + SERVICE_CONFIRMED_REINITIALIZE_DEVICE); + /* FIXME: now you can reboot, restart, quit, or something clever */ + /* Note: you can use a mix of state and password to do specific stuff */ + /* Note: if you don't do something clever like actually restart, + you probably should clear any DCC status and timeouts */ + /* Note: you probably need to send the reply BEFORE restarting */ + } else { + len = + bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, SERVICE_CONFIRMED_REINITIALIZE_DEVICE, + ERROR_CLASS_SERVICES, ERROR_CODE_PASSWORD_FAILURE); + } + } + RD_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/bdk-atxx4-mstp/h_rp.c b/bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c index 740625e3..4bf50ef1 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c @@ -1,180 +1,180 @@ -/************************************************************************** -* -* 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" -#include "ai.h" -#include "bi.h" -#include "bo.h" - -static uint8_t Temp_Buf[MAX_APDU] = { 0 }; - -/* Encodes the property APDU and returns the length, - or sets the error, and returns -1 */ -int Encode_Property_APDU( - uint8_t * apdu, - BACNET_OBJECT_TYPE object_type, - 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 = -1; - - /* initialize the default return values */ - *error_class = ERROR_CLASS_OBJECT; - *error_code = ERROR_CODE_UNKNOWN_OBJECT; - /* handle each object type */ - switch (object_type) { - case OBJECT_DEVICE: - if (Device_Valid_Object_Instance_Number(object_instance)) { - apdu_len = - Device_Encode_Property_APDU(&apdu[0], property, - array_index, error_class, error_code); - } - break; - case OBJECT_ANALOG_INPUT: - if (Analog_Input_Valid_Instance(object_instance)) { - apdu_len = - Analog_Input_Encode_Property_APDU(&apdu[0], - object_instance, property, array_index, error_class, - error_code); - } - break; - case OBJECT_BINARY_INPUT: - if (Binary_Input_Valid_Instance(object_instance)) { - apdu_len = - Binary_Input_Encode_Property_APDU(&apdu[0], - object_instance, property, array_index, error_class, - error_code); - } - break; - case OBJECT_BINARY_OUTPUT: - if (Binary_Output_Valid_Instance(object_instance)) { - apdu_len = - Binary_Output_Encode_Property_APDU(&apdu[0], - object_instance, property, array_index, error_class, - error_code); - } - break; - 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 pdu_len = 0; - BACNET_NPDU_DATA npdu_data; - bool error = false; - 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 */ - error = true; - len = - Encode_Property_APDU(&Temp_Buf[0], data.object_type, - data.object_instance, data.object_property, data.array_index, - &error_class, &error_code); - if (len >= 0) { - /* encode the APDU portion of the packet */ - data.application_data = &Temp_Buf[0]; - data.application_data_len = len; - /* FIXME: probably need a length limitation sent with encode */ - len = - rp_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, &data); - error = false; - } - if (error) { - if (len == -2) { - /* BACnet APDU too small to fit data, so proper response is Abort */ - len = - abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, - ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); - goto RP_ABORT; - } - len = - bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY, - error_class, error_code); - } - RP_ABORT: - pdu_len += len; - bytes_sent = - datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], - pdu_len); - - return; -} +/************************************************************************** +* +* 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" +#include "ai.h" +#include "bi.h" +#include "bo.h" + +static uint8_t Temp_Buf[MAX_APDU] = { 0 }; + +/* Encodes the property APDU and returns the length, + or sets the error, and returns -1 */ +int Encode_Property_APDU( + uint8_t * apdu, + BACNET_OBJECT_TYPE object_type, + 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 = -1; + + /* initialize the default return values */ + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + /* handle each object type */ + switch (object_type) { + case OBJECT_DEVICE: + if (Device_Valid_Object_Instance_Number(object_instance)) { + apdu_len = + Device_Encode_Property_APDU(&apdu[0], property, + array_index, error_class, error_code); + } + break; + case OBJECT_ANALOG_INPUT: + if (Analog_Input_Valid_Instance(object_instance)) { + apdu_len = + Analog_Input_Encode_Property_APDU(&apdu[0], + object_instance, property, array_index, error_class, + error_code); + } + break; + case OBJECT_BINARY_INPUT: + if (Binary_Input_Valid_Instance(object_instance)) { + apdu_len = + Binary_Input_Encode_Property_APDU(&apdu[0], + object_instance, property, array_index, error_class, + error_code); + } + break; + case OBJECT_BINARY_OUTPUT: + if (Binary_Output_Valid_Instance(object_instance)) { + apdu_len = + Binary_Output_Encode_Property_APDU(&apdu[0], + object_instance, property, array_index, error_class, + error_code); + } + break; + 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 pdu_len = 0; + BACNET_NPDU_DATA npdu_data; + bool error = false; + 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 */ + error = true; + len = + Encode_Property_APDU(&Temp_Buf[0], data.object_type, + data.object_instance, data.object_property, data.array_index, + &error_class, &error_code); + if (len >= 0) { + /* encode the APDU portion of the packet */ + data.application_data = &Temp_Buf[0]; + data.application_data_len = len; + /* FIXME: probably need a length limitation sent with encode */ + len = + rp_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, &data); + error = false; + } + if (error) { + if (len == -2) { + /* BACnet APDU too small to fit data, so proper response is Abort */ + len = + abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, + ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); + goto RP_ABORT; + } + len = + bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY, + error_class, error_code); + } + 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/bdk-atxx4-mstp/h_wp.c b/bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c index a3580fa3..98a67308 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c @@ -1,134 +1,134 @@ -/************************************************************************** -* -* 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 "ai.h" -#include "bi.h" -#include "bo.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; - - /* 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) { - len = - abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], - service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, - true); - goto WP_ABORT; - } - /* decode the service request only */ - len = wp_decode_service_request(service_request, service_len, &wp_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); - goto WP_ABORT; - } - /* handle the object type */ - 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_INPUT: - case OBJECT_BINARY_INPUT: - error_class = ERROR_CLASS_PROPERTY; - error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - 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_OUTPUT: - if (Binary_Output_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; - } - WP_ABORT: - pdu_len += len; - bytes_sent = - datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], - pdu_len); - - return; -} +/************************************************************************** +* +* 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 "ai.h" +#include "bi.h" +#include "bo.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; + + /* 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) { + len = + abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], + service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, + true); + goto WP_ABORT; + } + /* decode the service request only */ + len = wp_decode_service_request(service_request, service_len, &wp_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); + goto WP_ABORT; + } + /* handle the object type */ + 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_INPUT: + case OBJECT_BINARY_INPUT: + error_class = ERROR_CLASS_PROPERTY; + error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + 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_OUTPUT: + if (Binary_Output_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; + } + WP_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/bdk-atxx4-mstp/hardware.h b/bacnet-stack/ports/bdk-atxx4-mstp/hardware.h index ff2a68c2..927524bc 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/hardware.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/hardware.h @@ -1,55 +1,55 @@ -/************************************************************************** -* -* 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 18430000UL -#endif - -#if defined(__ICCAVR__) -#include -#endif - -#if defined(__GNUC__) - #if !defined(__AVR_ATmega644P__) - #error Firmware is configured for ATmega644P only (-mmcu=atmega644p) - #endif - /* GCC specific configuration */ - #include -#endif - -#include "iar2gcc.h" -#include "bits.h" - -/* SEEPROM is 24LC128 */ -//#define SEEPROM_PAGE_SIZE 128 -//#define SEEPROM_WORD_ADDRESS_16BIT 1 -/* SEEPROM is 24C16 */ -#define SEEPROM_PAGE_SIZE 16 -#define SEEPROM_WORD_ADDRESS_16BIT 0 - -#endif +/************************************************************************** +* +* 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 18430000UL +#endif + +#if defined(__ICCAVR__) +#include +#endif + +#if defined(__GNUC__) +#if !defined(__AVR_ATmega644P__) +#error Firmware is configured for ATmega644P only (-mmcu=atmega644p) +#endif + /* GCC specific configuration */ +#include +#endif + +#include "iar2gcc.h" +#include "bits.h" + +/* SEEPROM is 24LC128 */ +/*#define SEEPROM_PAGE_SIZE 128 */ +/*#define SEEPROM_WORD_ADDRESS_16BIT 1 */ +/* SEEPROM is 24C16 */ +#define SEEPROM_PAGE_SIZE 16 +#define SEEPROM_WORD_ADDRESS_16BIT 0 + +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/iar2gcc.h b/bacnet-stack/ports/bdk-atxx4-mstp/iar2gcc.h index 10a97aa0..eea2a3ec 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/iar2gcc.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/iar2gcc.h @@ -1,239 +1,239 @@ -/*####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(__ICCAVR__) -#include -#include - -/* 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 - - -/* watchdog */ -#if defined(__ICCAVR__) - #include - #define watchdog_reset __watchdog_reset - #define WDTO_15MS 0 - #define WDTO_30MS 1 - #define WDTO_60MS 2 - #define WDTO_120MS 3 - #define WDTO_250MS 4 - #define WDTO_500MS 5 - #define WDTO_1S 6 - #define WDTO_2S 7 -#endif - -#endif +/*####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(__ICCAVR__) +#include +#include + +/* 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 + + +/* watchdog */ +#if defined(__ICCAVR__) +#include +#define watchdog_reset __watchdog_reset +#define WDTO_15MS 0 +#define WDTO_30MS 1 +#define WDTO_60MS 2 +#define WDTO_120MS 3 +#define WDTO_250MS 4 +#define WDTO_500MS 5 +#define WDTO_1S 6 +#define WDTO_2S 7 +#endif + +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/init.c b/bacnet-stack/ports/bdk-atxx4-mstp/init.c index 29345819..d762aa36 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/init.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/init.c @@ -1,63 +1,63 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" - -void init( - void) -{ - /* Initialize the Clock Prescaler for ATmega48/88/168 */ - /* 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; - /* Initialize I/O ports */ - /* For Port DDRx (Data Direction) Input=0, Output=1 */ - /* For Port PORTx (Bit Value) TriState=0, High=1 */ - DDRA = 0; - PORTA = 0; - DDRB = 0; - PORTB = 0; - DDRC = 0; - PORTC = 0; - DDRD = 0; - PORTD = 0; - /* Configure the watchdog timer - Disabled for testing */ - BIT_CLEAR(MCUSR, WDRF); - WDTCSR = 0; -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" + +void init( + void) +{ + /* Initialize the Clock Prescaler for ATmega48/88/168 */ + /* 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; + /* Initialize I/O ports */ + /* For Port DDRx (Data Direction) Input=0, Output=1 */ + /* For Port PORTx (Bit Value) TriState=0, High=1 */ + DDRA = 0; + PORTA = 0; + DDRB = 0; + PORTB = 0; + DDRC = 0; + PORTC = 0; + DDRD = 0; + PORTD = 0; + /* Configure the watchdog timer - Disabled for testing */ + BIT_CLEAR(MCUSR, WDRF); + WDTCSR = 0; +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/init.h b/bacnet-stack/ports/bdk-atxx4-mstp/init.h index 1ab5cc2e..c6b79d18 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/init.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/init.h @@ -1,39 +1,39 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 INIT_H -#define INIT_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -void init(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/************************************************************************** +* +* Copyright (C) 2009 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 INIT_H +#define INIT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void init( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/input.c b/bacnet-stack/ports/bdk-atxx4-mstp/input.c index 6c401668..1a85cb71 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/input.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/input.c @@ -1,62 +1,59 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" - -static uint8_t Address_Switch; - -void input_task( - void) -{ - uint8_t value; - static uint8_t old_value = 0; - - value = BITMASK_CHECK(PINA, 0x7F); - if (value != old_value) { - old_value = value; - } else { - if (old_value != Address_Switch) { - Address_Switch = old_value; - } - } -} - -uint8_t input_address(void) -{ - return Address_Switch; -} - -void input_init(void) -{ - /* configure the port pins */ - BITMASK_CLEAR(DDRA, - _BV(DDA0) | - _BV(DDA1) | - _BV(DDA2) | - _BV(DDA3) | - _BV(DDA4) | - _BV(DDA5) | - _BV(DDA6) - ); -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" + +static uint8_t Address_Switch; + +void input_task( + void) +{ + uint8_t value; + static uint8_t old_value = 0; + + value = BITMASK_CHECK(PINA, 0x7F); + if (value != old_value) { + old_value = value; + } else { + if (old_value != Address_Switch) { + Address_Switch = old_value; + } + } +} + +uint8_t input_address( + void) +{ + return Address_Switch; +} + +void input_init( + void) +{ + /* configure the port pins */ + BITMASK_CLEAR(DDRA, + _BV(DDA0) | _BV(DDA1) | _BV(DDA2) | _BV(DDA3) | _BV(DDA4) | _BV(DDA5) | + _BV(DDA6) + ); +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/input.h b/bacnet-stack/ports/bdk-atxx4-mstp/input.h index 1bea5cb8..89008ca1 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/input.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/input.h @@ -1,41 +1,43 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 INPUT_H -#define INPUT_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -void input_init(void); -void input_task(void); -uint8_t input_address(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/************************************************************************** +* +* Copyright (C) 2009 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 INPUT_H +#define INPUT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void input_init( + void); + void input_task( + void); + uint8_t input_address( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/led.c b/bacnet-stack/ports/bdk-atxx4-mstp/led.c index cf3f25e0..7ece96ca 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/led.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/led.c @@ -1,211 +1,211 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" -#include "timer.h" -#include "led.h" - -static uint32_t Off_Delay_Milliseconds_1; -static uint32_t Off_Delay_Milliseconds_2; -static uint32_t Off_Delay_Milliseconds_3; -static uint32_t Off_Delay_Milliseconds_4; - -/************************************************************************* -* Description: Turn on an LED -* Returns: none -* Notes: none -*************************************************************************/ -void led_on(uint8_t index) -{ - switch (index) { - case LED_1: - BIT_SET(PORTD, PD7); - break; - case LED_2: - BIT_SET(PORTD, PD6); - break; - case LED_3: - BIT_SET(PORTC, PC7); - break; - case LED_4: - BIT_SET(PORTC, PC6); - break; - default: - break; - } -} - -/************************************************************************* -* Description: Turn off an LED -* Returns: none -* Notes: none -*************************************************************************/ -void led_off(uint8_t index) -{ - switch (index) { - case LED_1: - BIT_CLEAR(PORTD, PD7); - break; - case LED_2: - BIT_CLEAR(PORTD, PD6); - break; - case LED_3: - BIT_CLEAR(PORTC, PC7); - break; - case LED_4: - BIT_CLEAR(PORTC, PC6); - break; - default: - break; - } -} - -/************************************************************************* -* Description: Get the state of the LED -* Returns: true if on, false if off. -* Notes: none -*************************************************************************/ -bool led_state(uint8_t index) -{ - switch (index) { - case LED_1: - return (BIT_CHECK(PIND, PD7)); - break; - case LED_2: - return (BIT_CHECK(PIND, PD6)); - break; - case LED_3: - return (BIT_CHECK(PINC, PC7)); - break; - case LED_4: - return (BIT_CHECK(PINC, PC6)); - break; - default: - break; - } - - return false; -} - -/************************************************************************* -* Description: Toggle the state of the setup LED -* Returns: none -* Notes: none -*************************************************************************/ -void led_toggle(uint8_t index) -{ - if (led_state(index)) { - led_off(index); - } else { - led_on(index); - } -} - -/************************************************************************* -* Description: Delay before going off to give minimum brightness. -* Returns: none -* Notes: none -*************************************************************************/ -void led_off_delay(uint8_t index, uint32_t delay_ms) -{ - switch (index) { - case LED_1: - Off_Delay_Milliseconds_1 = delay_ms; - timer_reset(TIMER_LED_1); - break; - case LED_2: - Off_Delay_Milliseconds_2 = delay_ms; - timer_reset(TIMER_LED_2); - break; - case LED_3: - Off_Delay_Milliseconds_3 = delay_ms; - timer_reset(TIMER_LED_3); - break; - case LED_4: - Off_Delay_Milliseconds_4 = delay_ms; - timer_reset(TIMER_LED_4); - break; - default: - break; - } -} - -/************************************************************************* -* Description: Task for blinking LED -* Returns: none -* Notes: none -*************************************************************************/ -void led_task(void) -{ - if (Off_Delay_Milliseconds_1) { - if (timer_elapsed_milliseconds( - TIMER_LED_1, - Off_Delay_Milliseconds_1)) { - Off_Delay_Milliseconds_1 = 0; - led_off(LED_1); - } - } - if (Off_Delay_Milliseconds_2) { - if (timer_elapsed_milliseconds( - TIMER_LED_2, - Off_Delay_Milliseconds_2)) { - Off_Delay_Milliseconds_2 = 0; - led_off(LED_2); - } - } - if (Off_Delay_Milliseconds_3) { - if (timer_elapsed_milliseconds( - TIMER_LED_3, - Off_Delay_Milliseconds_3)) { - Off_Delay_Milliseconds_3 = 0; - led_off(LED_3); - } - } - if (Off_Delay_Milliseconds_4) { - if (timer_elapsed_milliseconds( - TIMER_LED_4, - Off_Delay_Milliseconds_4)) { - Off_Delay_Milliseconds_4 = 0; - led_off(LED_4); - } - } -} - -/************************************************************************* -* Description: Initialize the LED hardware -* Returns: none -* Notes: none -*************************************************************************/ -void led_init(void) -{ - /* configure the port pins as outputs */ - BIT_SET(DDRC, DDC7); - BIT_SET(DDRC, DDC6); - BIT_SET(DDRD, DDD7); - BIT_SET(DDRD, DDD6); - led_off(LED_1); - led_off(LED_2); - led_off(LED_3); - led_off(LED_4); -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" +#include "timer.h" +#include "led.h" + +static uint32_t Off_Delay_Milliseconds_1; +static uint32_t Off_Delay_Milliseconds_2; +static uint32_t Off_Delay_Milliseconds_3; +static uint32_t Off_Delay_Milliseconds_4; + +/************************************************************************* +* Description: Turn on an LED +* Returns: none +* Notes: none +*************************************************************************/ +void led_on( + uint8_t index) +{ + switch (index) { + case LED_1: + BIT_SET(PORTD, PD7); + break; + case LED_2: + BIT_SET(PORTD, PD6); + break; + case LED_3: + BIT_SET(PORTC, PC7); + break; + case LED_4: + BIT_SET(PORTC, PC6); + break; + default: + break; + } +} + +/************************************************************************* +* Description: Turn off an LED +* Returns: none +* Notes: none +*************************************************************************/ +void led_off( + uint8_t index) +{ + switch (index) { + case LED_1: + BIT_CLEAR(PORTD, PD7); + break; + case LED_2: + BIT_CLEAR(PORTD, PD6); + break; + case LED_3: + BIT_CLEAR(PORTC, PC7); + break; + case LED_4: + BIT_CLEAR(PORTC, PC6); + break; + default: + break; + } +} + +/************************************************************************* +* Description: Get the state of the LED +* Returns: true if on, false if off. +* Notes: none +*************************************************************************/ +bool led_state( + uint8_t index) +{ + switch (index) { + case LED_1: + return (BIT_CHECK(PIND, PD7)); + break; + case LED_2: + return (BIT_CHECK(PIND, PD6)); + break; + case LED_3: + return (BIT_CHECK(PINC, PC7)); + break; + case LED_4: + return (BIT_CHECK(PINC, PC6)); + break; + default: + break; + } + + return false; +} + +/************************************************************************* +* Description: Toggle the state of the setup LED +* Returns: none +* Notes: none +*************************************************************************/ +void led_toggle( + uint8_t index) +{ + if (led_state(index)) { + led_off(index); + } else { + led_on(index); + } +} + +/************************************************************************* +* Description: Delay before going off to give minimum brightness. +* Returns: none +* Notes: none +*************************************************************************/ +void led_off_delay( + uint8_t index, + uint32_t delay_ms) +{ + switch (index) { + case LED_1: + Off_Delay_Milliseconds_1 = delay_ms; + timer_reset(TIMER_LED_1); + break; + case LED_2: + Off_Delay_Milliseconds_2 = delay_ms; + timer_reset(TIMER_LED_2); + break; + case LED_3: + Off_Delay_Milliseconds_3 = delay_ms; + timer_reset(TIMER_LED_3); + break; + case LED_4: + Off_Delay_Milliseconds_4 = delay_ms; + timer_reset(TIMER_LED_4); + break; + default: + break; + } +} + +/************************************************************************* +* Description: Task for blinking LED +* Returns: none +* Notes: none +*************************************************************************/ +void led_task( + void) +{ + if (Off_Delay_Milliseconds_1) { + if (timer_elapsed_milliseconds(TIMER_LED_1, Off_Delay_Milliseconds_1)) { + Off_Delay_Milliseconds_1 = 0; + led_off(LED_1); + } + } + if (Off_Delay_Milliseconds_2) { + if (timer_elapsed_milliseconds(TIMER_LED_2, Off_Delay_Milliseconds_2)) { + Off_Delay_Milliseconds_2 = 0; + led_off(LED_2); + } + } + if (Off_Delay_Milliseconds_3) { + if (timer_elapsed_milliseconds(TIMER_LED_3, Off_Delay_Milliseconds_3)) { + Off_Delay_Milliseconds_3 = 0; + led_off(LED_3); + } + } + if (Off_Delay_Milliseconds_4) { + if (timer_elapsed_milliseconds(TIMER_LED_4, Off_Delay_Milliseconds_4)) { + Off_Delay_Milliseconds_4 = 0; + led_off(LED_4); + } + } +} + +/************************************************************************* +* Description: Initialize the LED hardware +* Returns: none +* Notes: none +*************************************************************************/ +void led_init( + void) +{ + /* configure the port pins as outputs */ + BIT_SET(DDRC, DDC7); + BIT_SET(DDRC, DDC6); + BIT_SET(DDRD, DDD7); + BIT_SET(DDRD, DDD6); + led_off(LED_1); + led_off(LED_2); + led_off(LED_3); + led_off(LED_4); +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/led.h b/bacnet-stack/ports/bdk-atxx4-mstp/led.h index a2b66df4..bf899a80 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/led.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/led.h @@ -1,52 +1,59 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 LED_H -#define LED_H - -#include -#include - -#define LED_1 0 -#define LED_2 1 -#define LED_3 2 -#define LED_4 3 -#define MAX_LEDS 4 - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -void led_on(uint8_t index); -void led_off(uint8_t index); -void led_off_delay(uint8_t index, uint32_t delay_ms); -void led_toggle(uint8_t index); -bool led_state(uint8_t index); -void led_task(void); -void led_init(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/************************************************************************** +* +* Copyright (C) 2009 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 LED_H +#define LED_H + +#include +#include + +#define LED_1 0 +#define LED_2 1 +#define LED_3 2 +#define LED_4 3 +#define MAX_LEDS 4 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void led_on( + uint8_t index); + void led_off( + uint8_t index); + void led_off_delay( + uint8_t index, + uint32_t delay_ms); + void led_toggle( + uint8_t index); + bool led_state( + uint8_t index); + void led_task( + void); + void led_init( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/main.c b/bacnet-stack/ports/bdk-atxx4-mstp/main.c index f7d2e615..8aff7a82 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/main.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/main.c @@ -1,222 +1,217 @@ -/************************************************************************ -* -* Copyright (C) 2009 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 "init.h" -#include "stack.h" -#include "timer.h" -#include "input.h" -#include "led.h" -#include "nvdata.h" -#include "timer.h" -#include "dcc.h" -#include "rs485.h" -#include "serial.h" -#include "datalink.h" -#include "npdu.h" -#include "handlers.h" -#include "client.h" -#include "txbuf.h" -#include "iam.h" -#include "device.h" -#include "ai.h" -#include "bi.h" -#include "bo.h" - -/* local version override */ -const char *BACnet_Version = "1.0"; -/* MAC Address of MS/TP */ -static uint8_t MSTP_MAC_Address; - -/* For porting to IAR, see: - http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/ - -#if defined(__GNUC__) && (__GNUC__ > 4) -/* AVR fuse settings */ -FUSES = -{ - /* External Ceramic Resonator - configuration */ - /* Full Swing Crystal Oscillator Clock Selection */ - /* Ceramic resonator, slowly rising power 1K CK 14CK + 65 ms */ - /* note: fuses are enabled by clearing the bit, so - any fuses listed below are cleared fuses. */ - .low = (FUSE_CKSEL3 & - FUSE_SUT0 & - FUSE_SUT1), - - /* BOOTSZ configuration: - BOOTSZ1 BOOTSZ0 Boot Size - ------- ------- --------- - 1 1 512 - 1 0 1024 - 0 1 2048 - 0 0 4096 - */ - /* note: fuses are enabled by clearing the bit, so - any fuses listed below are cleared fuses. */ - .high = ( - FUSE_BOOTSZ1 & - FUSE_BOOTRST & - FUSE_EESAVE & - FUSE_SPIEN & - FUSE_JTAGEN), - - /* Brown-out detection VCC=2.7V */ - /* BODLEVEL configuration - BODLEVEL2 BODLEVEL1 BODLEVEL0 Voltage - --------- --------- --------- -------- - 1 1 1 disabled - 1 1 0 1.8V - 1 0 1 2.7V - 1 0 0 4.3V - */ - /* note: fuses are enabled by clearing the bit, so - any fuses listed below are cleared fuses. */ - .extended = (FUSE_BODLEVEL1 & FUSE_BODLEVEL0), -}; -/* AVR lock bits - unlocked */ -LOCKBITS = LOCKBITS_DEFAULT; -#endif - -bool seeprom_version_test(void) -{ - uint16_t version = 0; - uint16_t id = 0; - bool status = false; - - seeprom_bytes_read(NV_SEEPROM_TYPE_0, (uint8_t *)&id, 2); - seeprom_bytes_read(NV_SEEPROM_VERSION_0, (uint8_t *)&version, 2); - - if ((id == SEEPROM_ID) && (version == SEEPROM_VERSION)) { - status = true; - } else { - version = SEEPROM_VERSION; - id = SEEPROM_ID; - seeprom_bytes_write(NV_SEEPROM_TYPE_0, (uint8_t *)&id, 2); - seeprom_bytes_write(NV_SEEPROM_VERSION_0, (uint8_t *)&version, 2); - } - - return status; -} - -static void bacnet_init( - void) -{ - MSTP_MAC_Address = input_address(); - dlmstp_set_mac_address(MSTP_MAC_Address); - dlmstp_init(NULL); - - if (!seeprom_version_test()) { - /* invalid version data */ - } - /* initialize objects */ - Device_Init(); - Binary_Output_Init(); - - /* we need to handle who-is to support dynamic device binding */ - apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); - /* Set the handlers for any confirmed services that we support. */ - /* We must implement read property - it's required! */ - apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, - handler_read_property); - apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROP_MULTIPLE, - handler_read_property_multiple); - apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE, - handler_reinitialize_device); - apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, - handler_write_property); - /* handle communication so we can shutup when asked */ - apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, - handler_device_communication_control); - - Send_I_Am(&Handler_Transmit_Buffer[0]); -} - -static uint8_t PDUBuffer[MAX_MPDU]; -static void bacnet_task(void) -{ - uint8_t mstp_mac_address = 0; - uint16_t pdu_len = 0; - BACNET_ADDRESS src; /* source address */ - - mstp_mac_address = input_address(); - if (MSTP_MAC_Address != mstp_mac_address) { - MSTP_MAC_Address = mstp_mac_address; - dlmstp_set_mac_address(MSTP_MAC_Address); - Send_I_Am(&Handler_Transmit_Buffer[0]); - } - if (timer_elapsed_seconds(TIMER_DCC, 1)) { - dcc_timer_seconds(1); - } - pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0); - if (pdu_len) { - npdu_handler(&src, &PDUBuffer[0], pdu_len); - } -} - -void idle_init(void) -{ - timer_reset(TIMER_LED_3); - timer_reset(TIMER_LED_4); -} - -void idle_task(void) -{ -#if 0 - /* blink the leds */ - if (timer_elapsed_seconds(TIMER_LED_3, 1)) { - timer_reset(TIMER_LED_3); - led_toggle(LED_3); - } - if (timer_elapsed_milliseconds(TIMER_LED_4, 125)) { - timer_reset(TIMER_LED_4); - led_toggle(LED_4); - } -#endif -} - -int main( - void) -{ - init(); - led_init(); - input_init(); - timer_init(); - seeprom_init(); - rs485_init(); - serial_init(); - bacnet_init(); - idle_init(); - /* Enable global interrupts */ - __enable_interrupt(); - for (;;) { - input_task(); - bacnet_task(); - led_task(); - idle_task(); - } -} +/************************************************************************ +* +* Copyright (C) 2009 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 "init.h" +#include "stack.h" +#include "timer.h" +#include "input.h" +#include "led.h" +#include "nvdata.h" +#include "timer.h" +#include "dcc.h" +#include "rs485.h" +#include "serial.h" +#include "datalink.h" +#include "npdu.h" +#include "handlers.h" +#include "client.h" +#include "txbuf.h" +#include "iam.h" +#include "device.h" +#include "ai.h" +#include "bi.h" +#include "bo.h" + +/* local version override */ +const char *BACnet_Version = "1.0"; +/* MAC Address of MS/TP */ +static uint8_t MSTP_MAC_Address; + +/* For porting to IAR, see: + http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/ + +#if defined(__GNUC__) && (__GNUC__ > 4) +/* AVR fuse settings */ +FUSES = { + /* External Ceramic Resonator - configuration */ + /* Full Swing Crystal Oscillator Clock Selection */ + /* Ceramic resonator, slowly rising power 1K CK 14CK + 65 ms */ + /* note: fuses are enabled by clearing the bit, so + any fuses listed below are cleared fuses. */ + .low = (FUSE_CKSEL3 & FUSE_SUT0 & FUSE_SUT1), + /* BOOTSZ configuration: + BOOTSZ1 BOOTSZ0 Boot Size + ------- ------- --------- + 1 1 512 + 1 0 1024 + 0 1 2048 + 0 0 4096 + */ + /* note: fuses are enabled by clearing the bit, so + any fuses listed below are cleared fuses. */ + .high = + (FUSE_BOOTSZ1 & FUSE_BOOTRST & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN), + /* Brown-out detection VCC=2.7V */ + /* BODLEVEL configuration + BODLEVEL2 BODLEVEL1 BODLEVEL0 Voltage + --------- --------- --------- -------- + 1 1 1 disabled + 1 1 0 1.8V + 1 0 1 2.7V + 1 0 0 4.3V + */ + /* note: fuses are enabled by clearing the bit, so + any fuses listed below are cleared fuses. */ +.extended = (FUSE_BODLEVEL1 & FUSE_BODLEVEL0),}; + +/* AVR lock bits - unlocked */ +LOCKBITS = LOCKBITS_DEFAULT; +#endif + +bool seeprom_version_test( + void) +{ + uint16_t version = 0; + uint16_t id = 0; + bool status = false; + + seeprom_bytes_read(NV_SEEPROM_TYPE_0, (uint8_t *) & id, 2); + seeprom_bytes_read(NV_SEEPROM_VERSION_0, (uint8_t *) & version, 2); + + if ((id == SEEPROM_ID) && (version == SEEPROM_VERSION)) { + status = true; + } else { + version = SEEPROM_VERSION; + id = SEEPROM_ID; + seeprom_bytes_write(NV_SEEPROM_TYPE_0, (uint8_t *) & id, 2); + seeprom_bytes_write(NV_SEEPROM_VERSION_0, (uint8_t *) & version, 2); + } + + return status; +} + +static void bacnet_init( + void) +{ + MSTP_MAC_Address = input_address(); + dlmstp_set_mac_address(MSTP_MAC_Address); + dlmstp_init(NULL); + + if (!seeprom_version_test()) { + /* invalid version data */ + } + /* initialize objects */ + Device_Init(); + Binary_Output_Init(); + + /* we need to handle who-is to support dynamic device binding */ + apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); + /* Set the handlers for any confirmed services that we support. */ + /* We must implement read property - it's required! */ + apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, + handler_read_property); + apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROP_MULTIPLE, + handler_read_property_multiple); + apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE, + handler_reinitialize_device); + apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, + handler_write_property); + /* handle communication so we can shutup when asked */ + apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, + handler_device_communication_control); + + Send_I_Am(&Handler_Transmit_Buffer[0]); +} + +static uint8_t PDUBuffer[MAX_MPDU]; +static void bacnet_task( + void) +{ + uint8_t mstp_mac_address = 0; + uint16_t pdu_len = 0; + BACNET_ADDRESS src; /* source address */ + + mstp_mac_address = input_address(); + if (MSTP_MAC_Address != mstp_mac_address) { + MSTP_MAC_Address = mstp_mac_address; + dlmstp_set_mac_address(MSTP_MAC_Address); + Send_I_Am(&Handler_Transmit_Buffer[0]); + } + if (timer_elapsed_seconds(TIMER_DCC, 1)) { + dcc_timer_seconds(1); + } + pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0); + if (pdu_len) { + npdu_handler(&src, &PDUBuffer[0], pdu_len); + } +} + +void idle_init( + void) +{ + timer_reset(TIMER_LED_3); + timer_reset(TIMER_LED_4); +} + +void idle_task( + void) +{ +#if 0 + /* blink the leds */ + if (timer_elapsed_seconds(TIMER_LED_3, 1)) { + timer_reset(TIMER_LED_3); + led_toggle(LED_3); + } + if (timer_elapsed_milliseconds(TIMER_LED_4, 125)) { + timer_reset(TIMER_LED_4); + led_toggle(LED_4); + } +#endif +} + +int main( + void) +{ + init(); + led_init(); + input_init(); + timer_init(); + seeprom_init(); + rs485_init(); + serial_init(); + bacnet_init(); + idle_init(); + /* Enable global interrupts */ + __enable_interrupt(); + for (;;) { + input_task(); + bacnet_task(); + led_task(); + idle_task(); + } +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h b/bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h index 518c3288..9ae1fc06 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/nvdata.h @@ -1,132 +1,132 @@ -/************************************************************************ -* -* Copyright (C) 2009 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 NVDATA_H -#define NVDATA_H - -#include "seeprom.h" -#include "eeprom.h" - -/* data version - use to check valid version */ -#define SEEPROM_ID 0xBAC0 -#define SEEPROM_VERSION 0x0001 - -#define SEEPROM_BYTES_MAX (2*1024) - -/* list of SEEPROM addresses */ -/* note to developers: define each byte, - even if they are not used explicitly */ -#define NV_SEEPROM_TYPE_0 0 -#define NV_SEEPROM_TYPE_1 1 -#define NV_SEEPROM_VERSION_0 2 -#define NV_SEEPROM_VERSION_1 3 -/* --- */ -/* define the MAC, BAUD, MAX Master, Device Instance internal - so that bootloader *could* use them. */ -/* note: MAC could come from DIP switch, or be in non-volatile memory */ -#define NV_EEPROM_MAC 0 -/* 9=9.6k, 19=19.2k, 38=38.4k, 57=57.6k, 76=76.8k, 115=115.2k */ -#define NV_EEPROM_BAUD_K 1 -#define NV_EEPROM_MAX_MASTER 2 -/* device instance is only 22 bits - easier if we use 32 bits */ -#define NV_EEPROM_DEVICE_0 3 -#define NV_EEPROM_DEVICE_1 4 -#define NV_EEPROM_DEVICE_2 5 -#define NV_EEPROM_DEVICE_3 6 -/* Device Name */ -#define NV_EEPROM_DEVICE_NAME_LENGTH 8 -#define NV_EEPROM_DEVICE_NAME_ENCODING 9 -#define NV_EEPROM_DEVICE_NAME_0 10 -#define NV_EEPROM_DEVICE_NAME_1 11 -#define NV_EEPROM_DEVICE_NAME_2 12 -#define NV_EEPROM_DEVICE_NAME_3 13 -#define NV_EEPROM_DEVICE_NAME_4 14 -#define NV_EEPROM_DEVICE_NAME_5 15 -#define NV_EEPROM_DEVICE_NAME_6 16 -#define NV_EEPROM_DEVICE_NAME_7 17 -#define NV_EEPROM_DEVICE_NAME_8 18 -#define NV_EEPROM_DEVICE_NAME_9 19 -#define NV_EEPROM_DEVICE_NAME_10 20 -#define NV_EEPROM_DEVICE_NAME_11 21 -#define NV_EEPROM_DEVICE_NAME_12 22 -#define NV_EEPROM_DEVICE_NAME_13 23 -#define NV_EEPROM_DEVICE_NAME_14 24 -#define NV_EEPROM_DEVICE_NAME_15 25 -#define NV_EEPROM_DEVICE_NAME_16 26 -#define NV_EEPROM_DEVICE_NAME_17 27 -#define NV_EEPROM_DEVICE_NAME_18 28 -#define NV_EEPROM_DEVICE_NAME_19 29 -#define NV_EEPROM_DEVICE_NAME_20 30 -#define NV_EEPROM_DEVICE_NAME_21 31 -#define NV_EEPROM_DEVICE_NAME_22 32 -#define NV_EEPROM_DEVICE_NAME_23 33 -#define NV_EEPROM_DEVICE_NAME_24 34 -#define NV_EEPROM_DEVICE_NAME_25 35 -#define NV_EEPROM_DEVICE_NAME_26 36 -#define NV_EEPROM_DEVICE_NAME_27 37 -#define NV_EEPROM_DEVICE_NAME_28 38 -#define NV_EEPROM_DEVICE_NAME_29 39 -#define NV_EEPROM_DEVICE_NAME_30 40 -#define NV_EEPROM_DEVICE_NAME_31 41 -#define NV_EEPROM_DEVICE_NAME_SIZE 32 - -/*=============== SEEPROM ================*/ -#define NV_SEEPROM_BINARY_OUTPUT_OFFSET 32 -#define NV_SEEPROM_BINARY_OUTPUT_0 10 -#define NV_SEEPROM_BINARY_OUTPUT(n,p) \ - (NV_SEEPROM_BINARY_OUTPUT_0 + \ - (NV_SEEPROM_BINARY_OUTPUT_OFFSET * (n)) + (p)) -/* BO properties */ -#define NV_SEEPROM_BO_POLARITY 0 -#define NV_SEEPROM_BO_OUT_OF_SERVICE 1 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_1 2 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_2 3 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_3 4 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_4 5 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_5 6 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_6 7 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_7 8 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_8 9 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_9 10 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_10 11 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_11 12 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_12 13 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_13 14 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_14 15 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_15 16 -#define NV_SEEPROM_BO_PRIORITY_ARRAY_16 17 - - - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif +/************************************************************************ +* +* Copyright (C) 2009 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 NVDATA_H +#define NVDATA_H + +#include "seeprom.h" +#include "eeprom.h" + +/* data version - use to check valid version */ +#define SEEPROM_ID 0xBAC0 +#define SEEPROM_VERSION 0x0001 + +#define SEEPROM_BYTES_MAX (2*1024) + +/* list of SEEPROM addresses */ +/* note to developers: define each byte, + even if they are not used explicitly */ +#define NV_SEEPROM_TYPE_0 0 +#define NV_SEEPROM_TYPE_1 1 +#define NV_SEEPROM_VERSION_0 2 +#define NV_SEEPROM_VERSION_1 3 +/* --- */ +/* define the MAC, BAUD, MAX Master, Device Instance internal + so that bootloader *could* use them. */ +/* note: MAC could come from DIP switch, or be in non-volatile memory */ +#define NV_EEPROM_MAC 0 +/* 9=9.6k, 19=19.2k, 38=38.4k, 57=57.6k, 76=76.8k, 115=115.2k */ +#define NV_EEPROM_BAUD_K 1 +#define NV_EEPROM_MAX_MASTER 2 +/* device instance is only 22 bits - easier if we use 32 bits */ +#define NV_EEPROM_DEVICE_0 3 +#define NV_EEPROM_DEVICE_1 4 +#define NV_EEPROM_DEVICE_2 5 +#define NV_EEPROM_DEVICE_3 6 +/* Device Name */ +#define NV_EEPROM_DEVICE_NAME_LENGTH 8 +#define NV_EEPROM_DEVICE_NAME_ENCODING 9 +#define NV_EEPROM_DEVICE_NAME_0 10 +#define NV_EEPROM_DEVICE_NAME_1 11 +#define NV_EEPROM_DEVICE_NAME_2 12 +#define NV_EEPROM_DEVICE_NAME_3 13 +#define NV_EEPROM_DEVICE_NAME_4 14 +#define NV_EEPROM_DEVICE_NAME_5 15 +#define NV_EEPROM_DEVICE_NAME_6 16 +#define NV_EEPROM_DEVICE_NAME_7 17 +#define NV_EEPROM_DEVICE_NAME_8 18 +#define NV_EEPROM_DEVICE_NAME_9 19 +#define NV_EEPROM_DEVICE_NAME_10 20 +#define NV_EEPROM_DEVICE_NAME_11 21 +#define NV_EEPROM_DEVICE_NAME_12 22 +#define NV_EEPROM_DEVICE_NAME_13 23 +#define NV_EEPROM_DEVICE_NAME_14 24 +#define NV_EEPROM_DEVICE_NAME_15 25 +#define NV_EEPROM_DEVICE_NAME_16 26 +#define NV_EEPROM_DEVICE_NAME_17 27 +#define NV_EEPROM_DEVICE_NAME_18 28 +#define NV_EEPROM_DEVICE_NAME_19 29 +#define NV_EEPROM_DEVICE_NAME_20 30 +#define NV_EEPROM_DEVICE_NAME_21 31 +#define NV_EEPROM_DEVICE_NAME_22 32 +#define NV_EEPROM_DEVICE_NAME_23 33 +#define NV_EEPROM_DEVICE_NAME_24 34 +#define NV_EEPROM_DEVICE_NAME_25 35 +#define NV_EEPROM_DEVICE_NAME_26 36 +#define NV_EEPROM_DEVICE_NAME_27 37 +#define NV_EEPROM_DEVICE_NAME_28 38 +#define NV_EEPROM_DEVICE_NAME_29 39 +#define NV_EEPROM_DEVICE_NAME_30 40 +#define NV_EEPROM_DEVICE_NAME_31 41 +#define NV_EEPROM_DEVICE_NAME_SIZE 32 + +/*=============== SEEPROM ================*/ +#define NV_SEEPROM_BINARY_OUTPUT_OFFSET 32 +#define NV_SEEPROM_BINARY_OUTPUT_0 10 +#define NV_SEEPROM_BINARY_OUTPUT(n,p) \ + (NV_SEEPROM_BINARY_OUTPUT_0 + \ + (NV_SEEPROM_BINARY_OUTPUT_OFFSET * (n)) + (p)) +/* BO properties */ +#define NV_SEEPROM_BO_POLARITY 0 +#define NV_SEEPROM_BO_OUT_OF_SERVICE 1 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_1 2 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_2 3 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_3 4 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_4 5 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_5 6 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_6 7 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_7 8 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_8 9 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_9 10 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_10 11 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_11 12 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_12 13 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_13 14 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_14 15 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_15 16 +#define NV_SEEPROM_BO_PRIORITY_ARRAY_16 17 + + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/rs485.c b/bacnet-stack/ports/bdk-atxx4-mstp/rs485.c index 7fadea85..5ba58cc6 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/rs485.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/rs485.c @@ -1,259 +1,257 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" -#include "fifo.h" -#include "timer.h" -#include "led.h" -#include "nvdata.h" - -/* baud rate */ -static uint32_t Baud_Rate = 9600; - -/* 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)/Baud_Rate; */ - -/* buffer for storing received bytes - size must be power of two */ -static uint8_t Receive_Buffer_Data[128]; -static FIFO_BUFFER Receive_Buffer; - -static void rs485_rts_init(void) -{ - /* configure the port pin as an output */ - BIT_SET(DDRD, DDD4); -} - -/* enable the transmit-enable line on the RS-485 transceiver */ -void rs485_rts_enable( - bool enable) -{ - if (enable) { - BIT_SET(PORTD, PD4); - } else { - BIT_CLEAR(PORTD, PD4); - } -} - -static void rs485_receiver_enable(void) -{ - UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(RXCIE0); -} - -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) / Baud_Rate); - while (!timer_elapsed_milliseconds(TIMER_SILENCE, turnaround_time)) { - /* do nothing - wait for timer to increment */ - }; -} - -ISR(USART0_RX_vect) -{ - uint8_t data_byte; - - if (BIT_CHECK(UCSR0A, RXC0)) { - /* data is available */ - data_byte = UDR0; - (void)FIFO_Put(&Receive_Buffer, data_byte); - timer_reset(TIMER_SILENCE); - } -} - -bool rs485_byte_available( - uint8_t * data_register) -{ - bool data_available = false; /* return value */ - - if (!FIFO_Empty(&Receive_Buffer)) { - led_on(LED_1); - *data_register = FIFO_Get(&Receive_Buffer); - data_available = true; - led_off_delay(LED_1, 10); - } - - return data_available; -} - -bool rs485_receive_error(void) -{ - return false; -} - -void rs485_bytes_send( - uint8_t * buffer, /* data to send */ - uint16_t nbytes) /* number of bytes of data */ -{ - led_on(LED_2); - while (!BIT_CHECK(UCSR0A, UDRE0)) { - /* do nothing - wait until Tx buffer is empty */ - } - while (nbytes) { - /* Send the data byte */ - UDR0 = *buffer; - while (!BIT_CHECK(UCSR0A, UDRE0)) { - /* do nothing - wait until Tx buffer is empty */ - } - buffer++; - nbytes--; - } - /* was the frame sent? */ - while (!BIT_CHECK(UCSR0A, TXC0)) { - /* 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(UCSR0A, TXC0); - timer_reset(TIMER_SILENCE); - led_off_delay(LED_2, 1); - - return; -} - -uint32_t rs485_baud_rate( - void) -{ - return Baud_Rate; -} - -static void rs485_baud_rate_configure(void) -{ - /* 2x speed mode */ - BIT_SET(UCSR0A, U2X0); - /* configure baud rate */ - UBRR0 = (F_CPU / (8UL * Baud_Rate)) - 1; -} - -bool rs485_baud_rate_set( - uint32_t baud) -{ - bool valid = true; - uint8_t baud_k = 0; - - switch (baud) { - case 9600: - case 19200: - case 38400: - case 57600: - case 76800: - case 115200: - Baud_Rate = baud; - rs485_baud_rate_configure(); - /* store the baud rate */ - baud_k = baud/1000; - eeprom_bytes_write( - NV_EEPROM_BAUD_K, - &baud_k, - 1); - break; - default: - valid = false; - break; - } - - return valid; -} - -static void rs485_usart_init(void) -{ - /* enable Transmit and Receive */ - UCSR0B = _BV(TXEN0) | _BV(RXEN0); - /* 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. */ - UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); - /* Clear Power Reduction */ - BIT_CLEAR(PRR, PRUSART0); -} - -static void rs485_init_nvdata(void) -{ - uint8_t baud_k = 9; /* from EEPROM value */ - - eeprom_bytes_read( - NV_EEPROM_BAUD_K, - &baud_k, - 1); - switch (baud_k) { - case 9: - Baud_Rate = 9600; - break; - case 19: - Baud_Rate = 19200; - break; - case 38: - Baud_Rate = 38400; - break; - case 57: - Baud_Rate = 57600; - break; - case 76: - Baud_Rate = 76800; - break; - case 115: - Baud_Rate = 115200; - break; - default: - /* not configured yet */ - Baud_Rate = 38400; - baud_k = 38400/1000; - eeprom_bytes_write( - NV_EEPROM_BAUD_K, - &baud_k, - 1); - break; - } - rs485_baud_rate_configure(); -} - -void rs485_init(void) -{ - FIFO_Init(&Receive_Buffer, &Receive_Buffer_Data[0], - (unsigned)sizeof(Receive_Buffer_Data)); - rs485_rts_init(); - rs485_usart_init(); - rs485_init_nvdata(); - rs485_receiver_enable(); - rs485_rts_enable(false); -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" +#include "fifo.h" +#include "timer.h" +#include "led.h" +#include "nvdata.h" + +/* baud rate */ +static uint32_t Baud_Rate = 9600; + +/* 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)/Baud_Rate; */ + +/* buffer for storing received bytes - size must be power of two */ +static uint8_t Receive_Buffer_Data[128]; +static FIFO_BUFFER Receive_Buffer; + +static void rs485_rts_init( + void) +{ + /* configure the port pin as an output */ + BIT_SET(DDRD, DDD4); +} + +/* enable the transmit-enable line on the RS-485 transceiver */ +void rs485_rts_enable( + bool enable) +{ + if (enable) { + BIT_SET(PORTD, PD4); + } else { + BIT_CLEAR(PORTD, PD4); + } +} + +static void rs485_receiver_enable( + void) +{ + UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(RXCIE0); +} + +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) / Baud_Rate); + while (!timer_elapsed_milliseconds(TIMER_SILENCE, turnaround_time)) { + /* do nothing - wait for timer to increment */ + }; +} + +ISR(USART0_RX_vect) +{ + uint8_t data_byte; + + if (BIT_CHECK(UCSR0A, RXC0)) { + /* data is available */ + data_byte = UDR0; + (void) FIFO_Put(&Receive_Buffer, data_byte); + timer_reset(TIMER_SILENCE); + } +} + +bool rs485_byte_available( + uint8_t * data_register) +{ + bool data_available = false; /* return value */ + + if (!FIFO_Empty(&Receive_Buffer)) { + led_on(LED_1); + *data_register = FIFO_Get(&Receive_Buffer); + data_available = true; + led_off_delay(LED_1, 10); + } + + return data_available; +} + +bool rs485_receive_error( + void) +{ + return false; +} + +void rs485_bytes_send( + uint8_t * buffer, /* data to send */ + uint16_t nbytes) +{ /* number of bytes of data */ + led_on(LED_2); + while (!BIT_CHECK(UCSR0A, UDRE0)) { + /* do nothing - wait until Tx buffer is empty */ + } + while (nbytes) { + /* Send the data byte */ + UDR0 = *buffer; + while (!BIT_CHECK(UCSR0A, UDRE0)) { + /* do nothing - wait until Tx buffer is empty */ + } + buffer++; + nbytes--; + } + /* was the frame sent? */ + while (!BIT_CHECK(UCSR0A, TXC0)) { + /* 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(UCSR0A, TXC0); + timer_reset(TIMER_SILENCE); + led_off_delay(LED_2, 1); + + return; +} + +uint32_t rs485_baud_rate( + void) +{ + return Baud_Rate; +} + +static void rs485_baud_rate_configure( + void) +{ + /* 2x speed mode */ + BIT_SET(UCSR0A, U2X0); + /* configure baud rate */ + UBRR0 = (F_CPU / (8UL * Baud_Rate)) - 1; +} + +bool rs485_baud_rate_set( + uint32_t baud) +{ + bool valid = true; + uint8_t baud_k = 0; + + switch (baud) { + case 9600: + case 19200: + case 38400: + case 57600: + case 76800: + case 115200: + Baud_Rate = baud; + rs485_baud_rate_configure(); + /* store the baud rate */ + baud_k = baud / 1000; + eeprom_bytes_write(NV_EEPROM_BAUD_K, &baud_k, 1); + break; + default: + valid = false; + break; + } + + return valid; +} + +static void rs485_usart_init( + void) +{ + /* enable Transmit and Receive */ + UCSR0B = _BV(TXEN0) | _BV(RXEN0); + /* 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. */ + UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); + /* Clear Power Reduction */ + BIT_CLEAR(PRR, PRUSART0); +} + +static void rs485_init_nvdata( + void) +{ + uint8_t baud_k = 9; /* from EEPROM value */ + + eeprom_bytes_read(NV_EEPROM_BAUD_K, &baud_k, 1); + switch (baud_k) { + case 9: + Baud_Rate = 9600; + break; + case 19: + Baud_Rate = 19200; + break; + case 38: + Baud_Rate = 38400; + break; + case 57: + Baud_Rate = 57600; + break; + case 76: + Baud_Rate = 76800; + break; + case 115: + Baud_Rate = 115200; + break; + default: + /* not configured yet */ + Baud_Rate = 38400; + baud_k = 38400 / 1000; + eeprom_bytes_write(NV_EEPROM_BAUD_K, &baud_k, 1); + break; + } + rs485_baud_rate_configure(); +} + +void rs485_init( + void) +{ + FIFO_Init(&Receive_Buffer, &Receive_Buffer_Data[0], + (unsigned) sizeof(Receive_Buffer_Data)); + rs485_rts_init(); + rs485_usart_init(); + rs485_init_nvdata(); + rs485_receiver_enable(); + rs485_rts_enable(false); +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/rs485.h b/bacnet-stack/ports/bdk-atxx4-mstp/rs485.h index beaf12d4..6fe90585 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/rs485.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/rs485.h @@ -1,64 +1,67 @@ -/*####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_init(void); - void rs485_rts_enable( - bool enable); - bool rs485_byte_available( - uint8_t * data_register); - bool rs485_receive_error(void); - void rs485_bytes_send( - uint8_t * buffer, /* data to send */ - uint16_t nbytes); /* number of bytes of data */ - uint32_t rs485_baud_rate(void); - bool rs485_baud_rate_set( - uint32_t baud); - - void rs485_turnaround_delay( - void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif +/*####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_init( + void); + void rs485_rts_enable( + bool enable); + bool rs485_byte_available( + uint8_t * data_register); + bool rs485_receive_error( + void); + void rs485_bytes_send( + uint8_t * buffer, /* data to send */ + uint16_t nbytes); /* number of bytes of data */ + uint32_t rs485_baud_rate( + void); + bool rs485_baud_rate_set( + uint32_t baud); + + void rs485_turnaround_delay( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/seeprom.c b/bacnet-stack/ports/bdk-atxx4-mstp/seeprom.c index 8221ef8b..06fa9f71 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/seeprom.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/seeprom.c @@ -1,424 +1,426 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" -#include "seeprom.h" - -/* the SEEPROM chip select bits A2, A1, and A0 are grounded */ -/* control byte is 0xAx */ -#ifndef SEEPROM_I2C_ADDRESS -#define SEEPROM_I2C_ADDRESS 0xA0 -#endif - -/* SEEPROM Clock Frequency */ -#ifndef SEEPROM_I2C_CLOCK -#define SEEPROM_I2C_CLOCK 400000UL -#endif - -/* max number of bytes that can be written in a single write */ -#ifndef SEEPROM_PAGE_SIZE -#define SEEPROM_PAGE_SIZE 128 -#endif - -/* word addressing - is it 8-bit or 16-bit */ -#ifndef SEEPROM_WORD_ADDRESS_16BIT -#define SEEPROM_WORD_ADDRESS_16BIT 1 -#endif - -/* The lower 3 bits of TWSR are reserved on the ATmega163 */ -#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3)) -/* start condition transmitted */ -#define TW_START 0x08 -/* repeated start condition transmitted */ -#define TW_REP_START 0x10 -/* ***Master Transmitter*** */ -/* SLA+W transmitted, ACK received */ -#define TW_MT_SLA_ACK 0x18 -/* SLA+W transmitted, NACK received */ -#define TW_MT_SLA_NACK 0x20 -/* data transmitted, ACK received */ -#define TW_MT_DATA_ACK 0x28 -/* data transmitted, NACK received */ -#define TW_MT_DATA_NACK 0x30 -/* arbitration lost in SLA+W or data */ -#define TW_MT_ARB_LOST 0x38 -/* ***Master Receiver*** */ -/* arbitration lost in SLA+R or NACK */ -#define TW_MR_ARB_LOST 0x38 -/* SLA+R transmitted, ACK received */ -#define TW_MR_SLA_ACK 0x40 -/* SLA+R transmitted, NACK received */ -#define TW_MR_SLA_NACK 0x48 -/* data received, ACK returned */ -#define TW_MR_DATA_ACK 0x50 -/* data received, NACK returned */ -#define TW_MR_DATA_NACK 0x58 - -/* SLA+R address */ -#define TW_READ 1 -/* SLA+W address */ -#define TW_WRITE 0 - -/* - * Maximal number of iterations to wait for a device to respond for a - * selection. Should be large enough to allow for a pending write to - * complete, but low enough to properly abort an infinite loop in case - * a slave is broken or not present at all. With 100 kHz TWI clock, - * transfering the start condition and SLA+R/W packet takes about 10 - * µs. The longest write period is supposed to not exceed ~ 10 ms. - * Thus, normal operation should not require more than 100 iterations - * to get the device to respond to a selection. - */ -#define MAX_ITER 200 - -/************************************************************************* -* DESCRIPTION: Return bytes from SEEPROM memory at address -* RETURN: number of bytes read, or -1 on error -* NOTES: none -**************************************************************************/ -int seeprom_bytes_read( - uint16_t eeaddr, /* SEEPROM starting memory address */ - uint8_t * buf, /* data to store */ - int len) /* number of bytes of data to read */ -{ - uint8_t sla, twcr, n = 0; - int rv = 0; - uint8_t twst; /* status - only valid while TWINT is set. */ - -#if SEEPROM_WORD_ADDRESS_16BIT - /* 16bit address devices need only TWI Device Address */ - sla = SEEPROM_I2C_ADDRESS; -#else - /* patch high bits of EEPROM address into SLA */ - sla = SEEPROM_I2C_ADDRESS | (((eeaddr >> 8) & 0x07) << 1); -#endif - /* Note [8] First cycle: master transmitter mode */ -restart: - if (n++ >= MAX_ITER) { - return -1; - } -begin: - /* send start condition */ - TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_REP_START: - /* OK, but should not happen */ - case TW_START: - break; - case TW_MT_ARB_LOST: - /* Note [9] */ - goto begin; - default: - /* error: not in start condition */ - /* NB: do /not/ send stop condition */ - return -1; - } - - /* Note [10] */ - /* send SLA+W */ - TWDR = sla | TW_WRITE; - /* clear interrupt to start transmission */ - TWCR = _BV(TWINT) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MT_SLA_ACK: - break; - case TW_MT_SLA_NACK: - /* nack during select: device busy writing */ - /* Note [11] */ - goto restart; - case TW_MT_ARB_LOST: - /* re-arbitrate */ - goto begin; - default: - /* must send stop condition */ - goto error; - } -#if SEEPROM_WORD_ADDRESS_16BIT - /* 16 bit word address device, send high 8 bits of addr */ - TWDR = (eeaddr>>8); - /* clear interrupt to start transmission */ - TWCR = _BV(TWINT) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MT_DATA_ACK: - break; - case TW_MT_DATA_NACK: - goto quit; - case TW_MT_ARB_LOST: - goto begin; - default: - /* must send stop condition */ - goto error; - } -#endif - /* low 8 bits of addr */ - TWDR = eeaddr; - /* clear interrupt to start transmission */ - TWCR = _BV(TWINT) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MT_DATA_ACK: - break; - case TW_MT_DATA_NACK: - goto quit; - case TW_MT_ARB_LOST: - goto begin; - default: - /* must send stop condition */ - goto error; - } - - /* Note [12] Next cycle(s): master receiver mode */ - /* send repeated start condition */ - TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_START: - /* OK, but should not happen */ - case TW_REP_START: - break; - case TW_MT_ARB_LOST: - goto begin; - default: - goto error; - } - - /* send SLA+R */ - TWDR = sla | TW_READ; - /* clear interrupt to start transmission */ - TWCR = _BV(TWINT) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MR_SLA_ACK: - break; - case TW_MR_SLA_NACK: - goto quit; - case TW_MR_ARB_LOST: - goto begin; - default: - goto error; - } - /* Note [13] */ - twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA); - for (;len > 0; len--) { - if (len == 1) { - /* send NAK this time */ - twcr = _BV(TWINT) | _BV(TWEN); - } - /* clear int to start transmission */ - TWCR = twcr; - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MR_DATA_NACK: - /* force end of loop */ - len = 0; - /* FALLTHROUGH */ - case TW_MR_DATA_ACK: - *buf= TWDR; - buf++; - rv++; - break; - default: - goto error; - } - } -quit: - /* Note [14] */ - /* send stop condition */ - TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); - return rv; -error: - rv = -1; - goto quit; -} - -/************************************************************************* -* DESCRIPTION: Write some data and wait until it is sent -* RETURN: number of bytes written, or -1 on error -* NOTES: none -**************************************************************************/ -int seeprom_bytes_write( - uint16_t eeaddr, /* SEEPROM starting memory address */ - uint8_t * buf, /* data to send */ - int len) /* number of bytes of data */ -{ - uint8_t sla, n = 0; - int rv = 0; - uint16_t endaddr; - uint8_t twst; /* status - only valid while TWINT is set. */ - - if ((eeaddr + len) < (eeaddr | (SEEPROM_PAGE_SIZE - 1))) { - endaddr = eeaddr + len; - } else { - endaddr = (eeaddr | (SEEPROM_PAGE_SIZE - 1)) + 1; - } - len = endaddr - eeaddr; -#if SEEPROM_WORD_ADDRESS_16BIT - /* 16bit address devices need only TWI Device Address */ - sla = SEEPROM_I2C_ADDRESS; -#else - /* patch high bits of EEPROM address into SLA */ - sla = SEEPROM_I2C_ADDRESS | (((eeaddr >> 8) & 0x07) << 1); -#endif -restart: - if (n++ >= MAX_ITER) { - return -1; - } -begin: - /* Note [15] */ - TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* send start condition */ - while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */ - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_REP_START: - /* OK, but should not happen */ - case TW_START: - break; - case TW_MT_ARB_LOST: - goto begin; - default: - /* error: not in start condition */ - /* NB: do /not/ send stop condition */ - return -1; - } - /* send SLA+W */ - TWDR = sla | TW_WRITE; - /* clear interrupt to start transmission */ - TWCR = _BV(TWINT) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MT_SLA_ACK: - break; - case TW_MT_SLA_NACK: - /* nack during select: device busy writing */ - goto restart; - case TW_MT_ARB_LOST: - /* re-arbitrate */ - goto begin; - default: - /* must send stop condition */ - goto error; - } -#if SEEPROM_WORD_ADDRESS_16BIT - /* 16 bit word address device, send high 8 bits of addr */ - TWDR = (eeaddr>>8); - /* clear interrupt to start transmission */ - TWCR = _BV(TWINT) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MT_DATA_ACK: - break; - case TW_MT_DATA_NACK: - goto quit; - case TW_MT_ARB_LOST: - goto begin; - default: - /* must send stop condition */ - goto error; - } -#endif - /* low 8 bits of addr */ - TWDR = eeaddr; - /* clear interrupt to start transmission */ - TWCR = _BV(TWINT) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) {}; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MT_DATA_ACK: - break; - case TW_MT_DATA_NACK: - goto quit; - case TW_MT_ARB_LOST: - goto begin; - default: - /* must send stop condition */ - goto error; - } - for (; len > 0; len--) { - TWDR = *buf++; - /* start transmission */ - TWCR = _BV(TWINT) | _BV(TWEN); - /* wait for transmission */ - while ((TWCR & _BV(TWINT)) == 0) ; - twst = TWSR & TW_STATUS_MASK; - switch (twst) { - case TW_MT_DATA_NACK: - /* device write protected -- Note [16] */ - goto error; - case TW_MT_DATA_ACK: - rv++; - break; - default: - goto error; - } - } -quit: - /* send stop condition */ - TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); - - return rv; - -error: - rv = -1; - goto quit; -} - -/************************************************************************* -* Description: Initialize the SEEPROM TWI connection -* Returns: none -* Notes: none -**************************************************************************/ -void seeprom_init(void) -{ - /* bit rate prescaler */ - TWSR=0; - TWCR=_BV(TWEN) | _BV(TWEA); - /* bit rate */ - TWBR = (F_CPU / SEEPROM_I2C_CLOCK - 16) / 2; - /* my address */ - TWAR=0; -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" +#include "seeprom.h" + +/* the SEEPROM chip select bits A2, A1, and A0 are grounded */ +/* control byte is 0xAx */ +#ifndef SEEPROM_I2C_ADDRESS +#define SEEPROM_I2C_ADDRESS 0xA0 +#endif + +/* SEEPROM Clock Frequency */ +#ifndef SEEPROM_I2C_CLOCK +#define SEEPROM_I2C_CLOCK 400000UL +#endif + +/* max number of bytes that can be written in a single write */ +#ifndef SEEPROM_PAGE_SIZE +#define SEEPROM_PAGE_SIZE 128 +#endif + +/* word addressing - is it 8-bit or 16-bit */ +#ifndef SEEPROM_WORD_ADDRESS_16BIT +#define SEEPROM_WORD_ADDRESS_16BIT 1 +#endif + +/* The lower 3 bits of TWSR are reserved on the ATmega163 */ +#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3)) +/* start condition transmitted */ +#define TW_START 0x08 +/* repeated start condition transmitted */ +#define TW_REP_START 0x10 +/* ***Master Transmitter*** */ +/* SLA+W transmitted, ACK received */ +#define TW_MT_SLA_ACK 0x18 +/* SLA+W transmitted, NACK received */ +#define TW_MT_SLA_NACK 0x20 +/* data transmitted, ACK received */ +#define TW_MT_DATA_ACK 0x28 +/* data transmitted, NACK received */ +#define TW_MT_DATA_NACK 0x30 +/* arbitration lost in SLA+W or data */ +#define TW_MT_ARB_LOST 0x38 +/* ***Master Receiver*** */ +/* arbitration lost in SLA+R or NACK */ +#define TW_MR_ARB_LOST 0x38 +/* SLA+R transmitted, ACK received */ +#define TW_MR_SLA_ACK 0x40 +/* SLA+R transmitted, NACK received */ +#define TW_MR_SLA_NACK 0x48 +/* data received, ACK returned */ +#define TW_MR_DATA_ACK 0x50 +/* data received, NACK returned */ +#define TW_MR_DATA_NACK 0x58 + +/* SLA+R address */ +#define TW_READ 1 +/* SLA+W address */ +#define TW_WRITE 0 + +/* + * Maximal number of iterations to wait for a device to respond for a + * selection. Should be large enough to allow for a pending write to + * complete, but low enough to properly abort an infinite loop in case + * a slave is broken or not present at all. With 100 kHz TWI clock, + * transfering the start condition and SLA+R/W packet takes about 10 + * µs. The longest write period is supposed to not exceed ~ 10 ms. + * Thus, normal operation should not require more than 100 iterations + * to get the device to respond to a selection. + */ +#define MAX_ITER 200 + +/************************************************************************* +* DESCRIPTION: Return bytes from SEEPROM memory at address +* RETURN: number of bytes read, or -1 on error +* NOTES: none +**************************************************************************/ +int seeprom_bytes_read( + uint16_t eeaddr, /* SEEPROM starting memory address */ + uint8_t * buf, /* data to store */ + int len) +{ /* number of bytes of data to read */ + uint8_t sla, twcr, n = 0; + int rv = 0; + uint8_t twst; /* status - only valid while TWINT is set. */ + +#if SEEPROM_WORD_ADDRESS_16BIT + /* 16bit address devices need only TWI Device Address */ + sla = SEEPROM_I2C_ADDRESS; +#else + /* patch high bits of EEPROM address into SLA */ + sla = SEEPROM_I2C_ADDRESS | (((eeaddr >> 8) & 0x07) << 1); +#endif + /* Note [8] First cycle: master transmitter mode */ + restart: + if (n++ >= MAX_ITER) { + return -1; + } + begin: + /* send start condition */ + TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_REP_START: + /* OK, but should not happen */ + case TW_START: + break; + case TW_MT_ARB_LOST: + /* Note [9] */ + goto begin; + default: + /* error: not in start condition */ + /* NB: do /not/ send stop condition */ + return -1; + } + + /* Note [10] */ + /* send SLA+W */ + TWDR = sla | TW_WRITE; + /* clear interrupt to start transmission */ + TWCR = _BV(TWINT) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MT_SLA_ACK: + break; + case TW_MT_SLA_NACK: + /* nack during select: device busy writing */ + /* Note [11] */ + goto restart; + case TW_MT_ARB_LOST: + /* re-arbitrate */ + goto begin; + default: + /* must send stop condition */ + goto error; + } +#if SEEPROM_WORD_ADDRESS_16BIT + /* 16 bit word address device, send high 8 bits of addr */ + TWDR = (eeaddr >> 8); + /* clear interrupt to start transmission */ + TWCR = _BV(TWINT) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MT_DATA_ACK: + break; + case TW_MT_DATA_NACK: + goto quit; + case TW_MT_ARB_LOST: + goto begin; + default: + /* must send stop condition */ + goto error; + } +#endif + /* low 8 bits of addr */ + TWDR = eeaddr; + /* clear interrupt to start transmission */ + TWCR = _BV(TWINT) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MT_DATA_ACK: + break; + case TW_MT_DATA_NACK: + goto quit; + case TW_MT_ARB_LOST: + goto begin; + default: + /* must send stop condition */ + goto error; + } + + /* Note [12] Next cycle(s): master receiver mode */ + /* send repeated start condition */ + TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_START: + /* OK, but should not happen */ + case TW_REP_START: + break; + case TW_MT_ARB_LOST: + goto begin; + default: + goto error; + } + + /* send SLA+R */ + TWDR = sla | TW_READ; + /* clear interrupt to start transmission */ + TWCR = _BV(TWINT) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MR_SLA_ACK: + break; + case TW_MR_SLA_NACK: + goto quit; + case TW_MR_ARB_LOST: + goto begin; + default: + goto error; + } + /* Note [13] */ + twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA); + for (; len > 0; len--) { + if (len == 1) { + /* send NAK this time */ + twcr = _BV(TWINT) | _BV(TWEN); + } + /* clear int to start transmission */ + TWCR = twcr; + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MR_DATA_NACK: + /* force end of loop */ + len = 0; + /* FALLTHROUGH */ + case TW_MR_DATA_ACK: + *buf = TWDR; + buf++; + rv++; + break; + default: + goto error; + } + } + quit: + /* Note [14] */ + /* send stop condition */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + return rv; + error: + rv = -1; + goto quit; +} + +/************************************************************************* +* DESCRIPTION: Write some data and wait until it is sent +* RETURN: number of bytes written, or -1 on error +* NOTES: none +**************************************************************************/ +int seeprom_bytes_write( + uint16_t eeaddr, /* SEEPROM starting memory address */ + uint8_t * buf, /* data to send */ + int len) +{ /* number of bytes of data */ + uint8_t sla, n = 0; + int rv = 0; + uint16_t endaddr; + uint8_t twst; /* status - only valid while TWINT is set. */ + + if ((eeaddr + len) < (eeaddr | (SEEPROM_PAGE_SIZE - 1))) { + endaddr = eeaddr + len; + } else { + endaddr = (eeaddr | (SEEPROM_PAGE_SIZE - 1)) + 1; + } + len = endaddr - eeaddr; +#if SEEPROM_WORD_ADDRESS_16BIT + /* 16bit address devices need only TWI Device Address */ + sla = SEEPROM_I2C_ADDRESS; +#else + /* patch high bits of EEPROM address into SLA */ + sla = SEEPROM_I2C_ADDRESS | (((eeaddr >> 8) & 0x07) << 1); +#endif + restart: + if (n++ >= MAX_ITER) { + return -1; + } + begin: + /* Note [15] */ + TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* send start condition */ + while ((TWCR & _BV(TWINT)) == 0); /* wait for transmission */ + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_REP_START: + /* OK, but should not happen */ + case TW_START: + break; + case TW_MT_ARB_LOST: + goto begin; + default: + /* error: not in start condition */ + /* NB: do /not/ send stop condition */ + return -1; + } + /* send SLA+W */ + TWDR = sla | TW_WRITE; + /* clear interrupt to start transmission */ + TWCR = _BV(TWINT) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MT_SLA_ACK: + break; + case TW_MT_SLA_NACK: + /* nack during select: device busy writing */ + goto restart; + case TW_MT_ARB_LOST: + /* re-arbitrate */ + goto begin; + default: + /* must send stop condition */ + goto error; + } +#if SEEPROM_WORD_ADDRESS_16BIT + /* 16 bit word address device, send high 8 bits of addr */ + TWDR = (eeaddr >> 8); + /* clear interrupt to start transmission */ + TWCR = _BV(TWINT) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MT_DATA_ACK: + break; + case TW_MT_DATA_NACK: + goto quit; + case TW_MT_ARB_LOST: + goto begin; + default: + /* must send stop condition */ + goto error; + } +#endif + /* low 8 bits of addr */ + TWDR = eeaddr; + /* clear interrupt to start transmission */ + TWCR = _BV(TWINT) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0) { + }; + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MT_DATA_ACK: + break; + case TW_MT_DATA_NACK: + goto quit; + case TW_MT_ARB_LOST: + goto begin; + default: + /* must send stop condition */ + goto error; + } + for (; len > 0; len--) { + TWDR = *buf++; + /* start transmission */ + TWCR = _BV(TWINT) | _BV(TWEN); + /* wait for transmission */ + while ((TWCR & _BV(TWINT)) == 0); + twst = TWSR & TW_STATUS_MASK; + switch (twst) { + case TW_MT_DATA_NACK: + /* device write protected -- Note [16] */ + goto error; + case TW_MT_DATA_ACK: + rv++; + break; + default: + goto error; + } + } + quit: + /* send stop condition */ + TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); + + return rv; + + error: + rv = -1; + goto quit; +} + +/************************************************************************* +* Description: Initialize the SEEPROM TWI connection +* Returns: none +* Notes: none +**************************************************************************/ +void seeprom_init( + void) +{ + /* bit rate prescaler */ + TWSR = 0; + TWCR = _BV(TWEN) | _BV(TWEA); + /* bit rate */ + TWBR = (F_CPU / SEEPROM_I2C_CLOCK - 16) / 2; + /* my address */ + TWAR = 0; +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/seeprom.h b/bacnet-stack/ports/bdk-atxx4-mstp/seeprom.h index 5b9053e5..2c9d9d7f 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/seeprom.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/seeprom.h @@ -1,48 +1,48 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 SEEPROM_H -#define SEEPROM_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -int seeprom_bytes_read( - uint16_t ee_address, /* SEEPROM starting memory address */ - uint8_t * buffer, /* data to store */ - int nbytes); /* number of bytes of data to read */ -int seeprom_bytes_write( - uint16_t ee_address, /* SEEPROM starting memory address */ - uint8_t * buffer, /* data to send */ - int nbytes); /* number of bytes of data */ -void seeprom_init( - void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif +/************************************************************************** +* +* Copyright (C) 2009 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 SEEPROM_H +#define SEEPROM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + int seeprom_bytes_read( + uint16_t ee_address, /* SEEPROM starting memory address */ + uint8_t * buffer, /* data to store */ + int nbytes); /* number of bytes of data to read */ + int seeprom_bytes_write( + uint16_t ee_address, /* SEEPROM starting memory address */ + uint8_t * buffer, /* data to send */ + int nbytes); /* number of bytes of data */ + void seeprom_init( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/serial.c b/bacnet-stack/ports/bdk-atxx4-mstp/serial.c index 82b4abfb..1d30c289 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/serial.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/serial.c @@ -1,173 +1,177 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" -#include "fifo.h" -#include "serial.h" - -/* baud rate */ -static uint32_t Baud_Rate = 9600; - -/* buffer for storing received bytes - size must be power of two */ -static uint8_t Receive_Buffer_Data[128]; -static FIFO_BUFFER Receive_Buffer; - -static void serial_receiver_enable(void) -{ - UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(RXCIE0); -} - -ISR(USART1_RX_vect) -{ - uint8_t data_byte; - - if (BIT_CHECK(UCSR1A, RXC1)) { - /* data is available */ - data_byte = UDR1; - (void)FIFO_Put(&Receive_Buffer, data_byte); - } -} - -bool serial_byte_get( - uint8_t * data_register) -{ - bool data_available = false; /* return value */ - - if (!FIFO_Empty(&Receive_Buffer)) { - *data_register = FIFO_Get(&Receive_Buffer); - data_available = true; - } - - return data_available; -} - -bool serial_byte_peek( - uint8_t * data_register) -{ - bool data_available = false; /* return value */ - - if (!FIFO_Empty(&Receive_Buffer)) { - *data_register = FIFO_Peek(&Receive_Buffer); - data_available = true; - } - - return data_available; -} - -void serial_bytes_send( - uint8_t * buffer, /* data to send */ - uint16_t nbytes) /* number of bytes of data */ -{ - while (!BIT_CHECK(UCSR1A, UDRE1)) { - /* do nothing - wait until Tx buffer is empty */ - } - while (nbytes) { - /* Send the data byte */ - UDR1 = *buffer; - while (!BIT_CHECK(UCSR1A, UDRE1)) { - /* do nothing - wait until Tx buffer is empty */ - } - buffer++; - nbytes--; - } - /* was the frame sent? */ - while (!BIT_CHECK(UCSR1A, TXC1)) { - /* 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(UCSR1A, TXC1); - - return; -} - -void serial_byte_send(uint8_t ch) -{ - uint8_t buffer[1]; - - buffer[0] = ch; - serial_bytes_send(&buffer[0], 1); - - return; -} - -uint32_t serial_baud_rate( - void) -{ - return Baud_Rate; -} - -bool serial_baud_rate_set( - uint32_t baud) -{ - bool valid = true; - - switch (baud) { - case 9600: - case 19200: - case 38400: - case 57600: - case 76800: - case 115200: - Baud_Rate = baud; - /* 2x speed mode */ - BIT_SET(UCSR1A, U2X1); - /* configure baud rate */ - UBRR1 = (F_CPU / (8UL * Baud_Rate)) - 1; - /* FIXME: store the baud rate */ - break; - default: - valid = false; - break; - } - - return valid; -} - -static void serial_usart_init(void) -{ - /* enable Transmit and Receive */ - UCSR1B = _BV(TXEN1) | _BV(RXEN1); - /* 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. */ - UCSR0C = _BV(UCSZ11) | _BV(UCSZ10); - /* Clear Power Reduction */ - BIT_CLEAR(PRR, PRUSART1); -} - -void serial_init(void) -{ - FIFO_Init(&Receive_Buffer, &Receive_Buffer_Data[0], - (unsigned)sizeof(Receive_Buffer_Data)); - serial_usart_init(); - serial_baud_rate_set(Baud_Rate); - serial_receiver_enable(); -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" +#include "fifo.h" +#include "serial.h" + +/* baud rate */ +static uint32_t Baud_Rate = 9600; + +/* buffer for storing received bytes - size must be power of two */ +static uint8_t Receive_Buffer_Data[128]; +static FIFO_BUFFER Receive_Buffer; + +static void serial_receiver_enable( + void) +{ + UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(RXCIE0); +} + +ISR(USART1_RX_vect) +{ + uint8_t data_byte; + + if (BIT_CHECK(UCSR1A, RXC1)) { + /* data is available */ + data_byte = UDR1; + (void) FIFO_Put(&Receive_Buffer, data_byte); + } +} + +bool serial_byte_get( + uint8_t * data_register) +{ + bool data_available = false; /* return value */ + + if (!FIFO_Empty(&Receive_Buffer)) { + *data_register = FIFO_Get(&Receive_Buffer); + data_available = true; + } + + return data_available; +} + +bool serial_byte_peek( + uint8_t * data_register) +{ + bool data_available = false; /* return value */ + + if (!FIFO_Empty(&Receive_Buffer)) { + *data_register = FIFO_Peek(&Receive_Buffer); + data_available = true; + } + + return data_available; +} + +void serial_bytes_send( + uint8_t * buffer, /* data to send */ + uint16_t nbytes) +{ /* number of bytes of data */ + while (!BIT_CHECK(UCSR1A, UDRE1)) { + /* do nothing - wait until Tx buffer is empty */ + } + while (nbytes) { + /* Send the data byte */ + UDR1 = *buffer; + while (!BIT_CHECK(UCSR1A, UDRE1)) { + /* do nothing - wait until Tx buffer is empty */ + } + buffer++; + nbytes--; + } + /* was the frame sent? */ + while (!BIT_CHECK(UCSR1A, TXC1)) { + /* 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(UCSR1A, TXC1); + + return; +} + +void serial_byte_send( + uint8_t ch) +{ + uint8_t buffer[1]; + + buffer[0] = ch; + serial_bytes_send(&buffer[0], 1); + + return; +} + +uint32_t serial_baud_rate( + void) +{ + return Baud_Rate; +} + +bool serial_baud_rate_set( + uint32_t baud) +{ + bool valid = true; + + switch (baud) { + case 9600: + case 19200: + case 38400: + case 57600: + case 76800: + case 115200: + Baud_Rate = baud; + /* 2x speed mode */ + BIT_SET(UCSR1A, U2X1); + /* configure baud rate */ + UBRR1 = (F_CPU / (8UL * Baud_Rate)) - 1; + /* FIXME: store the baud rate */ + break; + default: + valid = false; + break; + } + + return valid; +} + +static void serial_usart_init( + void) +{ + /* enable Transmit and Receive */ + UCSR1B = _BV(TXEN1) | _BV(RXEN1); + /* 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. */ + UCSR0C = _BV(UCSZ11) | _BV(UCSZ10); + /* Clear Power Reduction */ + BIT_CLEAR(PRR, PRUSART1); +} + +void serial_init( + void) +{ + FIFO_Init(&Receive_Buffer, &Receive_Buffer_Data[0], + (unsigned) sizeof(Receive_Buffer_Data)); + serial_usart_init(); + serial_baud_rate_set(Baud_Rate); + serial_receiver_enable(); +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/serial.h b/bacnet-stack/ports/bdk-atxx4-mstp/serial.h index f32ff6f6..a97899d4 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/serial.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/serial.h @@ -1,53 +1,55 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 SERIAL_H -#define SERIAL_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -bool serial_byte_get( - uint8_t * data_register); -bool serial_byte_peek( - uint8_t * data_register); - -void serial_bytes_send( - uint8_t * buffer, /* data to send */ - uint16_t nbytes); /* number of bytes of data */ -void serial_byte_send(uint8_t ch); - -uint32_t serial_baud_rate(void); -bool serial_baud_rate_set( - uint32_t baud); - -void serial_init(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/************************************************************************** +* +* Copyright (C) 2009 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 SERIAL_H +#define SERIAL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + bool serial_byte_get( + uint8_t * data_register); + bool serial_byte_peek( + uint8_t * data_register); + + void serial_bytes_send( + uint8_t * buffer, /* data to send */ + uint16_t nbytes); /* number of bytes of data */ + void serial_byte_send( + uint8_t ch); + + uint32_t serial_baud_rate( + void); + bool serial_baud_rate_set( + uint32_t baud); + + void serial_init( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/stack.c b/bacnet-stack/ports/bdk-atxx4-mstp/stack.c index 1660254d..e5108463 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/stack.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/stack.c @@ -1,77 +1,80 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 "hardware.h" - -/* stack checking */ -extern uint8_t _end; -extern uint8_t __stack; - -#define STACK_CANARY (0xC5) -void stack_init( - void) __attribute__ ((naked)) __attribute__ ((section(".init1"))); - -void stack_init( - void) -{ -#if 0 - uint8_t *p = &_end; - - while (p <= &__stack) { - *p = STACK_CANARY; - p++; - } -#else - __asm volatile ( - " ldi r30,lo8(_end)\n" " ldi r31,hi8(_end)\n" " ldi r24,lo8(0xc5)\n" /* STACK_CANARY = 0xc5 */ - " ldi r25,hi8(__stack)\n" " rjmp .cmp\n" ".loop:\n" - " st Z+,r24\n" ".cmp:\n" " cpi r30,lo8(__stack)\n" - " cpc r31,r25\n" " brlo .loop\n" " breq .loop"::); -#endif -} - -unsigned stack_size(void) -{ - return (&__stack) - (&_end); -} - -uint8_t stack_byte(unsigned offset) -{ - return *(&_end + offset); -} - -unsigned stack_unused(void) -{ - uint8_t *p = &_end; - unsigned count = 0; - - while (p <= &__stack) { - if ((*p) != STACK_CANARY) { - count = p - (&_end); - break; - } - p++; - } - return count; -} +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" + +/* stack checking */ +extern uint8_t _end; +extern uint8_t __stack; + +#define STACK_CANARY (0xC5) +void stack_init( + void) __attribute__ ((naked)) __attribute__ ((section(".init1"))); + +void stack_init( + void) +{ +#if 0 + uint8_t *p = &_end; + + while (p <= &__stack) { + *p = STACK_CANARY; + p++; + } +#else + __asm volatile ( + " ldi r30,lo8(_end)\n" " ldi r31,hi8(_end)\n" " ldi r24,lo8(0xc5)\n" /* STACK_CANARY = 0xc5 */ + " ldi r25,hi8(__stack)\n" " rjmp .cmp\n" ".loop:\n" + " st Z+,r24\n" ".cmp:\n" " cpi r30,lo8(__stack)\n" + " cpc r31,r25\n" " brlo .loop\n" " breq .loop"::); +#endif +} + +unsigned stack_size( + void) +{ + return (&__stack) - (&_end); +} + +uint8_t stack_byte( + unsigned offset) +{ + return *(&_end + offset); +} + +unsigned stack_unused( + void) +{ + uint8_t *p = &_end; + unsigned count = 0; + + while (p <= &__stack) { + if ((*p) != STACK_CANARY) { + count = p - (&_end); + break; + } + p++; + } + return count; +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/stack.h b/bacnet-stack/ports/bdk-atxx4-mstp/stack.h index b8079e6b..a306317d 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/stack.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/stack.h @@ -1,49 +1,51 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 STACK_H -#define STACK_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - /* C stack checking */ - void stack_init(void); - - unsigned stack_size(void); - - uint8_t stack_byte(unsigned offset); - - unsigned stack_unused(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ +/************************************************************************** +* +* Copyright (C) 2009 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 STACK_H +#define STACK_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + /* C stack checking */ + void stack_init( + void); + + unsigned stack_size( + void); + + uint8_t stack_byte( + unsigned offset); + + unsigned stack_unused( + void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ #endif - - diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/timer.h b/bacnet-stack/ports/bdk-atxx4-mstp/timer.h index 61519ac3..dc341b70 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/timer.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/timer.h @@ -1,67 +1,67 @@ -/************************************************************************** -* -* Copyright (C) 2009 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 - -#include -#include - -/* Timer Module */ -/* reserve the millisecond timer indexes as needed for each module */ -#define TIMER_SILENCE 0 -#define TIMER_DEBOUNCE 1 -#define TIMER_LED_1 2 -#define TIMER_LED_2 3 -#define TIMER_LED_3 4 -#define TIMER_LED_4 5 -#define TIMER_DCC 6 -#define MAX_MILLISECOND_TIMERS 7 - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - void timer_init( - void); - unsigned long timer_milliseconds( - unsigned index); - bool timer_elapsed_milliseconds( - unsigned index, - unsigned long value); - bool timer_elapsed_seconds( - unsigned index, - unsigned long value); - bool timer_elapsed_minutes( - unsigned index, - unsigned long seconds); - unsigned long timer_milliseconds_set( - unsigned index, - unsigned long value); - unsigned long timer_reset( - unsigned index); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif +/************************************************************************** +* +* Copyright (C) 2009 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 + +#include +#include + +/* Timer Module */ +/* reserve the millisecond timer indexes as needed for each module */ +#define TIMER_SILENCE 0 +#define TIMER_DEBOUNCE 1 +#define TIMER_LED_1 2 +#define TIMER_LED_2 3 +#define TIMER_LED_3 4 +#define TIMER_LED_4 5 +#define TIMER_DCC 6 +#define MAX_MILLISECOND_TIMERS 7 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void timer_init( + void); + unsigned long timer_milliseconds( + unsigned index); + bool timer_elapsed_milliseconds( + unsigned index, + unsigned long value); + bool timer_elapsed_seconds( + unsigned index, + unsigned long value); + bool timer_elapsed_minutes( + unsigned index, + unsigned long seconds); + unsigned long timer_milliseconds_set( + unsigned index, + unsigned long value); + unsigned long timer_reset( + unsigned index); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/timer2.c b/bacnet-stack/ports/bdk-atxx4-mstp/timer2.c index 8b3acd45..d8165447 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/timer2.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/timer2.c @@ -1,222 +1,223 @@ -/************************************************************************** -* -* Copyright (C) 2009 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" - -/* define various timers in timer.h file */ -#ifndef MAX_MILLISECOND_TIMERS -#define MAX_MILLISECOND_TIMERS 2 -#endif - -/* Timer2 Prescaling: 1, 8, 32, 64, 128, 256, or 1024 */ -#define TIMER2_PRESCALER 128 -/* Count: Timer counts up to 0xFF and then signals overflow */ -#define TIMER2_TICKS (F_CPU/TIMER2_PRESCALER/1000) -#if (TIMER2_TICKS > 0xFF) -#error Timer2 Prescaler value is too small -#endif -#define TIMER2_COUNT (0xFF-TIMER2_TICKS) - -/* counter for the various timers */ -static volatile unsigned long Millisecond_Counter[MAX_MILLISECOND_TIMERS]; - -/************************************************************************* -* Description: Timer Interrupt Handler -* Returns: none -* Notes: Global interupts must be enabled -*************************************************************************/ -static inline void timer_interrupt_handler(void) -{ - unsigned i; /* loop counter */ - - /* increment the tick count */ - for (i = 0; i < MAX_MILLISECOND_TIMERS; i++) { - Millisecond_Counter[i]++; - } -} - -/************************************************************************* -* Description: Timer Interrupt Service Routine - Timer Overflowed! -* Returns: none -* Notes: Global interupts must be enabled -*************************************************************************/ -ISR(TIMER2_OVF_vect) -{ - /* Set the counter for the next interrupt */ - TCNT2 = TIMER2_COUNT; - timer_interrupt_handler(); -} - -/************************************************************************* -* Description: sets the current time count with a value -* Returns: none -* Notes: none -*************************************************************************/ -unsigned long timer_milliseconds_set( - unsigned index, - unsigned long value) -{ - uint8_t sreg = 0; /* holds interrupts pending */ - unsigned long old_value = 0; /* return value */ - - if (index < MAX_MILLISECOND_TIMERS) { - sreg = SREG; - __disable_interrupt(); - old_value = Millisecond_Counter[index]; - Millisecond_Counter[index] = value; - SREG = sreg; - } - - return old_value; -} - -/************************************************************************* -* Description: returns the current millisecond count -* Returns: none -* Notes: none -*************************************************************************/ -unsigned long timer_milliseconds( - unsigned index) -{ - unsigned long timer_value = 0; /* return value */ - uint8_t sreg = 0; /* holds interrupts pending */ - - if (index < MAX_MILLISECOND_TIMERS) { - sreg = SREG; - __disable_interrupt(); - timer_value = Millisecond_Counter[index]; - SREG = sreg; - } - - return timer_value; -} - -/************************************************************************* -* Description: compares the current time count with a value -* Returns: true if the time has elapsed -* Notes: none -*************************************************************************/ -bool timer_elapsed_milliseconds( - unsigned index, - unsigned long value) -{ - return (timer_milliseconds(index) >= value); -} - -/************************************************************************* -* Description: compares the current time count with a value -* Returns: true if the time has elapsed -* Notes: none -*************************************************************************/ -bool timer_elapsed_seconds( - unsigned index, - unsigned long seconds) -{ - return ((timer_milliseconds(index)/1000UL) >= seconds); -} - -/************************************************************************* -* Description: compares the current time count with a value -* Returns: true if the time has elapsed -* Notes: none -*************************************************************************/ -bool timer_elapsed_minutes( - unsigned index, - unsigned long minutes) -{ - return ((timer_milliseconds(index)/(1000UL*60UL)) >= minutes); -} - -/************************************************************************* -* Description: Sets the timer counter to zero. -* Returns: none -* Notes: none -*************************************************************************/ -unsigned long timer_reset( - unsigned index) -{ - return timer_milliseconds_set(index,0); -} - -/************************************************************************* -* Description: Initialization for Timer -* Returns: none -* Notes: none -*************************************************************************/ -static void timer2_init( - void) -{ - /* Normal Operation */ - TCCR2A = 0; - /* Timer2: prescale selections: - CSn2 CSn1 CSn0 Description - ---- ---- ---- ----------- - 0 0 0 No Clock Source - 0 0 1 No prescaling - 0 1 0 CLKt2s/8 - 0 1 1 CLKt2s/32 - 1 0 0 CLKt2s/64 - 1 0 1 CLKt2s/128 - 1 1 0 CLKt2s/256 - 1 1 1 CLKt2s/1024 - */ -#if (TIMER2_PRESCALER==1) - TCCR2B = _BV(CS20); -#elif (TIMER2_PRESCALER==8) - TCCR2B = _BV(CS21); -#elif (TIMER2_PRESCALER==32) - TCCR2B = _BV(CS21) | _BV(CS20); -#elif (TIMER2_PRESCALER==64) - TCCR2B = _BV(CS22); -#elif (TIMER2_PRESCALER==128) - TCCR2B = _BV(CS22) | _BV(CS20); -#elif (TIMER2_PRESCALER==256) - TCCR2B = _BV(CS22) | _BV(CS21); -#elif (TIMER2_PRESCALER==1024) - TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); -#else - #error Timer2 Prescale: Invalid Value -#endif - /* Clear any TOV Flag set when the timer overflowed */ - BIT_CLEAR(TIFR2, TOV2); - /* Initial value */ - TCNT2 = TIMER2_COUNT; - /* Enable the overflow interrupt */ - BIT_SET(TIMSK2, TOIE2); - /* Clear the Power Reduction Timer/Counter0 */ - BIT_CLEAR(PRR, PRTIM2); -} - -/************************************************************************* -* Description: Initialization for Timer -* Returns: none -* Notes: none -*************************************************************************/ -void timer_init( - void) -{ - timer2_init(); -} \ No newline at end of file +/************************************************************************** +* +* Copyright (C) 2009 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" + +/* define various timers in timer.h file */ +#ifndef MAX_MILLISECOND_TIMERS +#define MAX_MILLISECOND_TIMERS 2 +#endif + +/* Timer2 Prescaling: 1, 8, 32, 64, 128, 256, or 1024 */ +#define TIMER2_PRESCALER 128 +/* Count: Timer counts up to 0xFF and then signals overflow */ +#define TIMER2_TICKS (F_CPU/TIMER2_PRESCALER/1000) +#if (TIMER2_TICKS > 0xFF) +#error Timer2 Prescaler value is too small +#endif +#define TIMER2_COUNT (0xFF-TIMER2_TICKS) + +/* counter for the various timers */ +static volatile unsigned long Millisecond_Counter[MAX_MILLISECOND_TIMERS]; + +/************************************************************************* +* Description: Timer Interrupt Handler +* Returns: none +* Notes: Global interupts must be enabled +*************************************************************************/ +static inline void timer_interrupt_handler( + void) +{ + unsigned i; /* loop counter */ + + /* increment the tick count */ + for (i = 0; i < MAX_MILLISECOND_TIMERS; i++) { + Millisecond_Counter[i]++; + } +} + +/************************************************************************* +* Description: Timer Interrupt Service Routine - Timer Overflowed! +* Returns: none +* Notes: Global interupts must be enabled +*************************************************************************/ +ISR(TIMER2_OVF_vect) +{ + /* Set the counter for the next interrupt */ + TCNT2 = TIMER2_COUNT; + timer_interrupt_handler(); +} + +/************************************************************************* +* Description: sets the current time count with a value +* Returns: none +* Notes: none +*************************************************************************/ +unsigned long timer_milliseconds_set( + unsigned index, + unsigned long value) +{ + uint8_t sreg = 0; /* holds interrupts pending */ + unsigned long old_value = 0; /* return value */ + + if (index < MAX_MILLISECOND_TIMERS) { + sreg = SREG; + __disable_interrupt(); + old_value = Millisecond_Counter[index]; + Millisecond_Counter[index] = value; + SREG = sreg; + } + + return old_value; +} + +/************************************************************************* +* Description: returns the current millisecond count +* Returns: none +* Notes: none +*************************************************************************/ +unsigned long timer_milliseconds( + unsigned index) +{ + unsigned long timer_value = 0; /* return value */ + uint8_t sreg = 0; /* holds interrupts pending */ + + if (index < MAX_MILLISECOND_TIMERS) { + sreg = SREG; + __disable_interrupt(); + timer_value = Millisecond_Counter[index]; + SREG = sreg; + } + + return timer_value; +} + +/************************************************************************* +* Description: compares the current time count with a value +* Returns: true if the time has elapsed +* Notes: none +*************************************************************************/ +bool timer_elapsed_milliseconds( + unsigned index, + unsigned long value) +{ + return (timer_milliseconds(index) >= value); +} + +/************************************************************************* +* Description: compares the current time count with a value +* Returns: true if the time has elapsed +* Notes: none +*************************************************************************/ +bool timer_elapsed_seconds( + unsigned index, + unsigned long seconds) +{ + return ((timer_milliseconds(index) / 1000UL) >= seconds); +} + +/************************************************************************* +* Description: compares the current time count with a value +* Returns: true if the time has elapsed +* Notes: none +*************************************************************************/ +bool timer_elapsed_minutes( + unsigned index, + unsigned long minutes) +{ + return ((timer_milliseconds(index) / (1000UL * 60UL)) >= minutes); +} + +/************************************************************************* +* Description: Sets the timer counter to zero. +* Returns: none +* Notes: none +*************************************************************************/ +unsigned long timer_reset( + unsigned index) +{ + return timer_milliseconds_set(index, 0); +} + +/************************************************************************* +* Description: Initialization for Timer +* Returns: none +* Notes: none +*************************************************************************/ +static void timer2_init( + void) +{ + /* Normal Operation */ + TCCR2A = 0; + /* Timer2: prescale selections: + CSn2 CSn1 CSn0 Description + ---- ---- ---- ----------- + 0 0 0 No Clock Source + 0 0 1 No prescaling + 0 1 0 CLKt2s/8 + 0 1 1 CLKt2s/32 + 1 0 0 CLKt2s/64 + 1 0 1 CLKt2s/128 + 1 1 0 CLKt2s/256 + 1 1 1 CLKt2s/1024 + */ +#if (TIMER2_PRESCALER==1) + TCCR2B = _BV(CS20); +#elif (TIMER2_PRESCALER==8) + TCCR2B = _BV(CS21); +#elif (TIMER2_PRESCALER==32) + TCCR2B = _BV(CS21) | _BV(CS20); +#elif (TIMER2_PRESCALER==64) + TCCR2B = _BV(CS22); +#elif (TIMER2_PRESCALER==128) + TCCR2B = _BV(CS22) | _BV(CS20); +#elif (TIMER2_PRESCALER==256) + TCCR2B = _BV(CS22) | _BV(CS21); +#elif (TIMER2_PRESCALER==1024) + TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); +#else +#error Timer2 Prescale: Invalid Value +#endif + /* Clear any TOV Flag set when the timer overflowed */ + BIT_CLEAR(TIFR2, TOV2); + /* Initial value */ + TCNT2 = TIMER2_COUNT; + /* Enable the overflow interrupt */ + BIT_SET(TIMSK2, TOIE2); + /* Clear the Power Reduction Timer/Counter0 */ + BIT_CLEAR(PRR, PRTIM2); +} + +/************************************************************************* +* Description: Initialization for Timer +* Returns: none +* Notes: none +*************************************************************************/ +void timer_init( + void) +{ + timer2_init(); +} diff --git a/bacnet-stack/ports/pic18f6720/device.c b/bacnet-stack/ports/pic18f6720/device.c index 5919e8bf..4cdf7c2c 100644 --- a/bacnet-stack/ports/pic18f6720/device.c +++ b/bacnet-stack/ports/pic18f6720/device.c @@ -450,7 +450,7 @@ int Device_Encode_Property_APDU( case PROP_UTC_OFFSET: /* Note: BACnet Time Zone is offset of local time and UTC, rather than offset of GMT. It is expressed in minutes */ - apdu_len = encode_application_signed(&apdu[0], 5*60 /* EST */ ); + apdu_len = encode_application_signed(&apdu[0], 5 * 60 /* EST */ ); break; case PROP_LOCAL_DATE: /* FIXME: if you support date */ diff --git a/bacnet-stack/ports/win32/rs485.c b/bacnet-stack/ports/win32/rs485.c index 8e06cbe1..9f366e37 100644 --- a/bacnet-stack/ports/win32/rs485.c +++ b/bacnet-stack/ports/win32/rs485.c @@ -98,8 +98,8 @@ void RS485_Set_Interface( if (ifname) { if (strncmp("COM", ifname, 3) == 0) { if (strlen(ifname) > 3) { - sprintf(RS485_Port_Name, "\\\\.\\COM%i", atoi(ifname+3)); - fprintf(stderr, "Adjusted interface name to %s\r\n", + sprintf(RS485_Port_Name, "\\\\.\\COM%i", atoi(ifname + 3)); + fprintf(stderr, "Adjusted interface name to %s\r\n", RS485_Port_Name); } } @@ -119,15 +119,9 @@ static void RS485_Print_Error( DWORD dwExtSize; DWORD dwErr; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL ); - MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION ); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + (LPTSTR) & lpMsgBuf, 0, NULL); + MessageBox(NULL, lpMsgBuf, "GetLastError", MB_OK | MB_ICONINFORMATION); LocalFree(lpMsgBuf); return; diff --git a/bacnet-stack/src/bacapp.c b/bacnet-stack/src/bacapp.c index e69477e1..9b6ce5ad 100644 --- a/bacnet-stack/src/bacapp.c +++ b/bacnet-stack/src/bacapp.c @@ -809,34 +809,29 @@ bool bacapp_print_value( if (value->type.Date.day == 255) { fprintf(stream, "(unspecified), "); } else { - fprintf(stream, "%u, ", - (unsigned) value->type.Date.day); + fprintf(stream, "%u, ", (unsigned) value->type.Date.day); } if (value->type.Date.year == 255) { fprintf(stream, "(unspecified), "); } else { - fprintf(stream, "%u", - (unsigned) value->type.Date.year); + fprintf(stream, "%u", (unsigned) value->type.Date.year); } break; case BACNET_APPLICATION_TAG_TIME: if (value->type.Time.hour == 255) { fprintf(stream, "**:"); } else { - fprintf(stream, "%02u:", - (unsigned) value->type.Time.hour); + fprintf(stream, "%02u:", (unsigned) value->type.Time.hour); } if (value->type.Time.min == 255) { fprintf(stream, "**:"); } else { - fprintf(stream, "%02u:", - (unsigned) value->type.Time.min); + fprintf(stream, "%02u:", (unsigned) value->type.Time.min); } if (value->type.Time.sec == 255) { fprintf(stream, "**."); } else { - fprintf(stream, "%02u.", - (unsigned) value->type.Time.sec); + fprintf(stream, "%02u.", (unsigned) value->type.Time.sec); } if (value->type.Time.hundredths == 255) { fprintf(stream, "**");