Fixed line endings and SVN props with fixup.sh script
This commit is contained in:
@@ -1,108 +1,108 @@
|
||||
#
|
||||
# There exist several targets which are by default empty and which can be
|
||||
# used for execution of your targets. These targets are usually executed
|
||||
# before and after some main targets. They are:
|
||||
#
|
||||
# .build-pre: called before 'build' target
|
||||
# .build-post: called after 'build' target
|
||||
# .clean-pre: called before 'clean' target
|
||||
# .clean-post: called after 'clean' target
|
||||
# .clobber-pre: called before 'clobber' target
|
||||
# .clobber-post: called after 'clobber' target
|
||||
# .all-pre: called before 'all' target
|
||||
# .all-post: called after 'all' target
|
||||
# .help-pre: called before 'help' target
|
||||
# .help-post: called after 'help' target
|
||||
#
|
||||
# Targets beginning with '.' are not intended to be called on their own.
|
||||
#
|
||||
# Main targets can be executed directly, and they are:
|
||||
#
|
||||
# build build a specific configuration
|
||||
# clean remove built files from a configuration
|
||||
# clobber remove all built files
|
||||
# all build all configurations
|
||||
# help print help mesage
|
||||
#
|
||||
# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
|
||||
# .help-impl are implemented in nbproject/makefile-impl.mk.
|
||||
#
|
||||
# Available make variables:
|
||||
#
|
||||
# CND_BASEDIR base directory for relative paths
|
||||
# CND_DISTDIR default top distribution directory (build artifacts)
|
||||
# CND_BUILDDIR default top build directory (object files, ...)
|
||||
# CONF name of current configuration
|
||||
# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
|
||||
# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
|
||||
# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
|
||||
# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
|
||||
# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
|
||||
# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
|
||||
#
|
||||
# NOCDDL
|
||||
|
||||
|
||||
# Environment
|
||||
MKDIR=mkdir
|
||||
CP=cp
|
||||
CCADMIN=CCadmin
|
||||
RANLIB=ranlib
|
||||
|
||||
|
||||
# build
|
||||
build: .build-post
|
||||
|
||||
.build-pre:
|
||||
# Add your pre 'build' code here...
|
||||
|
||||
.build-post: .build-impl
|
||||
# Add your post 'build' code here...
|
||||
|
||||
|
||||
# clean
|
||||
clean: .clean-post
|
||||
|
||||
.clean-pre:
|
||||
# Add your pre 'clean' code here...
|
||||
|
||||
.clean-post: .clean-impl
|
||||
# Add your post 'clean' code here...
|
||||
|
||||
|
||||
# clobber
|
||||
clobber: .clobber-post
|
||||
|
||||
.clobber-pre:
|
||||
# Add your pre 'clobber' code here...
|
||||
|
||||
.clobber-post: .clobber-impl
|
||||
# Add your post 'clobber' code here...
|
||||
|
||||
|
||||
# all
|
||||
all: .all-post
|
||||
|
||||
.all-pre:
|
||||
# Add your pre 'all' code here...
|
||||
|
||||
.all-post: .all-impl
|
||||
# Add your post 'all' code here...
|
||||
|
||||
|
||||
# help
|
||||
help: .help-post
|
||||
|
||||
.help-pre:
|
||||
# Add your pre 'help' code here...
|
||||
|
||||
.help-post: .help-impl
|
||||
# Add your post 'help' code here...
|
||||
|
||||
|
||||
|
||||
# include project implementation makefile
|
||||
include nbproject/Makefile-impl.mk
|
||||
|
||||
# include project make variables
|
||||
include nbproject/Makefile-variables.mk
|
||||
#
|
||||
# There exist several targets which are by default empty and which can be
|
||||
# used for execution of your targets. These targets are usually executed
|
||||
# before and after some main targets. They are:
|
||||
#
|
||||
# .build-pre: called before 'build' target
|
||||
# .build-post: called after 'build' target
|
||||
# .clean-pre: called before 'clean' target
|
||||
# .clean-post: called after 'clean' target
|
||||
# .clobber-pre: called before 'clobber' target
|
||||
# .clobber-post: called after 'clobber' target
|
||||
# .all-pre: called before 'all' target
|
||||
# .all-post: called after 'all' target
|
||||
# .help-pre: called before 'help' target
|
||||
# .help-post: called after 'help' target
|
||||
#
|
||||
# Targets beginning with '.' are not intended to be called on their own.
|
||||
#
|
||||
# Main targets can be executed directly, and they are:
|
||||
#
|
||||
# build build a specific configuration
|
||||
# clean remove built files from a configuration
|
||||
# clobber remove all built files
|
||||
# all build all configurations
|
||||
# help print help mesage
|
||||
#
|
||||
# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
|
||||
# .help-impl are implemented in nbproject/makefile-impl.mk.
|
||||
#
|
||||
# Available make variables:
|
||||
#
|
||||
# CND_BASEDIR base directory for relative paths
|
||||
# CND_DISTDIR default top distribution directory (build artifacts)
|
||||
# CND_BUILDDIR default top build directory (object files, ...)
|
||||
# CONF name of current configuration
|
||||
# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
|
||||
# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
|
||||
# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
|
||||
# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
|
||||
# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
|
||||
# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
|
||||
#
|
||||
# NOCDDL
|
||||
|
||||
|
||||
# Environment
|
||||
MKDIR=mkdir
|
||||
CP=cp
|
||||
CCADMIN=CCadmin
|
||||
RANLIB=ranlib
|
||||
|
||||
|
||||
# build
|
||||
build: .build-post
|
||||
|
||||
.build-pre:
|
||||
# Add your pre 'build' code here...
|
||||
|
||||
.build-post: .build-impl
|
||||
# Add your post 'build' code here...
|
||||
|
||||
|
||||
# clean
|
||||
clean: .clean-post
|
||||
|
||||
.clean-pre:
|
||||
# Add your pre 'clean' code here...
|
||||
|
||||
.clean-post: .clean-impl
|
||||
# Add your post 'clean' code here...
|
||||
|
||||
|
||||
# clobber
|
||||
clobber: .clobber-post
|
||||
|
||||
.clobber-pre:
|
||||
# Add your pre 'clobber' code here...
|
||||
|
||||
.clobber-post: .clobber-impl
|
||||
# Add your post 'clobber' code here...
|
||||
|
||||
|
||||
# all
|
||||
all: .all-post
|
||||
|
||||
.all-pre:
|
||||
# Add your pre 'all' code here...
|
||||
|
||||
.all-post: .all-impl
|
||||
# Add your post 'all' code here...
|
||||
|
||||
|
||||
# help
|
||||
help: .help-post
|
||||
|
||||
.help-pre:
|
||||
# Add your pre 'help' code here...
|
||||
|
||||
.help-post: .help-impl
|
||||
# Add your post 'help' code here...
|
||||
|
||||
|
||||
|
||||
# include project implementation makefile
|
||||
include nbproject/Makefile-impl.mk
|
||||
|
||||
# include project make variables
|
||||
include nbproject/Makefile-variables.mk
|
||||
|
||||
@@ -1,164 +1,164 @@
|
||||
###############################################################################
|
||||
# Makefile for BACnet
|
||||
###############################################################################
|
||||
|
||||
## General Flags
|
||||
MCU = pic18
|
||||
PORT = 18f6720
|
||||
TARGET = bacnet
|
||||
## Tools
|
||||
CC = sdcc
|
||||
PACK = packihx
|
||||
|
||||
# Source locations
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_DEMO = ../../demo
|
||||
|
||||
CSRC = main.c \
|
||||
isr.c \
|
||||
rs485.c \
|
||||
dlmstp.c \
|
||||
mstp.c \
|
||||
$(BACNET_CORE)/crc.c
|
||||
|
||||
DEMOSRC = h_rp.c \
|
||||
device.c \
|
||||
ai.c \
|
||||
av.c \
|
||||
bi.c \
|
||||
bv.c \
|
||||
$(BACNET_DEMO)/handler/txbuf.c \
|
||||
$(BACNET_DEMO)/handler/noserv.c \
|
||||
$(BACNET_DEMO)/handler/h_npdu.c \
|
||||
$(BACNET_DEMO)/handler/h_whois.c \
|
||||
h_wp.c
|
||||
|
||||
CORESRC = \
|
||||
$(BACNET_CORE)/apdu.c \
|
||||
$(BACNET_CORE)/npdu.c \
|
||||
$(BACNET_CORE)/bacdcode.c \
|
||||
$(BACNET_CORE)/bacint.c \
|
||||
$(BACNET_CORE)/bacreal.c \
|
||||
$(BACNET_CORE)/bacstr.c \
|
||||
$(BACNET_CORE)/iam.c \
|
||||
$(BACNET_CORE)/rp.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)/dcc.c \
|
||||
# $(BACNET_CORE)/iam/iam_client.c \
|
||||
# $(BACNET_CORE)/ihave.c \
|
||||
# $(BACNET_CORE)/rd.c \
|
||||
# $(BACNET_CORE)/rpm.c \
|
||||
# $(BACNET_CORE)/timesync.c \
|
||||
# $(BACNET_CORE)/whohas.c \
|
||||
# $(BACNET_CORE)/filename.c \
|
||||
# $(BACNET_CORE)/tsm.c \
|
||||
# $(BACNET_CORE)/address.c \
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE)
|
||||
|
||||
# Source to Object conversion
|
||||
COBJ = $(CSRC:.c=.o)
|
||||
DEMOOBJ = $(DEMOSRC:.c=.o)
|
||||
COREOBJ = $(CORESRC:.c=.o)
|
||||
|
||||
LIBRARY = lib$(TARGET).a
|
||||
|
||||
## Options common to compile, link and assembly rules
|
||||
COMMON = -m$(MCU) -p$(PORT)
|
||||
OPTIMIZATION = --opt-code-size
|
||||
|
||||
## 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_REAL
|
||||
CFLAGS = $(COMMON)
|
||||
# dead code removal
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
CFLAGS += -Wall $(BFLAGS) $(OPTIMIZATION)
|
||||
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,--gc-sections,-static
|
||||
LDFLAGS += -Wl,-Map=$(TARGET).map,-L.,-l$(TARGET)
|
||||
#LDFLAGS += -Wl,-Map=$(TARGET).map
|
||||
|
||||
## Intel Hex file production flags
|
||||
HEX_FLASH_FLAGS = -R .eeprom
|
||||
HEX_EEPROM_FLAGS = -j .eeprom
|
||||
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
|
||||
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings
|
||||
|
||||
## Objects that must be built in order to link
|
||||
OBJECTS = $(COBJ) $(DEMOOBJ)
|
||||
#OBJECTS = $(COBJ)
|
||||
|
||||
## Build
|
||||
TARGET_ELF=$(TARGET).elf
|
||||
|
||||
all: $(LIBRARY) $(TARGET_ELF) $(TARGET).hex $(TARGET).eep $(TARGET).lst \
|
||||
size Makefile
|
||||
|
||||
##Link
|
||||
$(TARGET_ELF): $(OBJECTS) $(LIBRARY)
|
||||
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||
|
||||
%.hex: $(TARGET_ELF)
|
||||
$(OBJCOPY) -O ihex $(HEX_FLASH_FLAGS) $< $@
|
||||
|
||||
%.eep: $(TARGET_ELF)
|
||||
-$(OBJCOPY) $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0
|
||||
|
||||
%.lst: $(TARGET_ELF)
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
lib: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(COREOBJ) Makefile
|
||||
$(AR) rcs $@ $(COREOBJ)
|
||||
$(OBJDUMP) --syms $@ > $(LIBRARY:.a=.lst)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@
|
||||
|
||||
size: ${TARGET_ELF}
|
||||
@echo
|
||||
@${SIZE} -C --mcu=${MCU} ${TARGET_ELF}
|
||||
|
||||
## Clean target
|
||||
.PHONY: clean
|
||||
clean:
|
||||
touch Makefile
|
||||
-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/*)
|
||||
###############################################################################
|
||||
# Makefile for BACnet
|
||||
###############################################################################
|
||||
|
||||
## General Flags
|
||||
MCU = pic18
|
||||
PORT = 18f6720
|
||||
TARGET = bacnet
|
||||
## Tools
|
||||
CC = sdcc
|
||||
PACK = packihx
|
||||
|
||||
# Source locations
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_DEMO = ../../demo
|
||||
|
||||
CSRC = main.c \
|
||||
isr.c \
|
||||
rs485.c \
|
||||
dlmstp.c \
|
||||
mstp.c \
|
||||
$(BACNET_CORE)/crc.c
|
||||
|
||||
DEMOSRC = h_rp.c \
|
||||
device.c \
|
||||
ai.c \
|
||||
av.c \
|
||||
bi.c \
|
||||
bv.c \
|
||||
$(BACNET_DEMO)/handler/txbuf.c \
|
||||
$(BACNET_DEMO)/handler/noserv.c \
|
||||
$(BACNET_DEMO)/handler/h_npdu.c \
|
||||
$(BACNET_DEMO)/handler/h_whois.c \
|
||||
h_wp.c
|
||||
|
||||
CORESRC = \
|
||||
$(BACNET_CORE)/apdu.c \
|
||||
$(BACNET_CORE)/npdu.c \
|
||||
$(BACNET_CORE)/bacdcode.c \
|
||||
$(BACNET_CORE)/bacint.c \
|
||||
$(BACNET_CORE)/bacreal.c \
|
||||
$(BACNET_CORE)/bacstr.c \
|
||||
$(BACNET_CORE)/iam.c \
|
||||
$(BACNET_CORE)/rp.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)/dcc.c \
|
||||
# $(BACNET_CORE)/iam/iam_client.c \
|
||||
# $(BACNET_CORE)/ihave.c \
|
||||
# $(BACNET_CORE)/rd.c \
|
||||
# $(BACNET_CORE)/rpm.c \
|
||||
# $(BACNET_CORE)/timesync.c \
|
||||
# $(BACNET_CORE)/whohas.c \
|
||||
# $(BACNET_CORE)/filename.c \
|
||||
# $(BACNET_CORE)/tsm.c \
|
||||
# $(BACNET_CORE)/address.c \
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE)
|
||||
|
||||
# Source to Object conversion
|
||||
COBJ = $(CSRC:.c=.o)
|
||||
DEMOOBJ = $(DEMOSRC:.c=.o)
|
||||
COREOBJ = $(CORESRC:.c=.o)
|
||||
|
||||
LIBRARY = lib$(TARGET).a
|
||||
|
||||
## Options common to compile, link and assembly rules
|
||||
COMMON = -m$(MCU) -p$(PORT)
|
||||
OPTIMIZATION = --opt-code-size
|
||||
|
||||
## 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_REAL
|
||||
CFLAGS = $(COMMON)
|
||||
# dead code removal
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
CFLAGS += -Wall $(BFLAGS) $(OPTIMIZATION)
|
||||
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,--gc-sections,-static
|
||||
LDFLAGS += -Wl,-Map=$(TARGET).map,-L.,-l$(TARGET)
|
||||
#LDFLAGS += -Wl,-Map=$(TARGET).map
|
||||
|
||||
## Intel Hex file production flags
|
||||
HEX_FLASH_FLAGS = -R .eeprom
|
||||
HEX_EEPROM_FLAGS = -j .eeprom
|
||||
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
|
||||
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings
|
||||
|
||||
## Objects that must be built in order to link
|
||||
OBJECTS = $(COBJ) $(DEMOOBJ)
|
||||
#OBJECTS = $(COBJ)
|
||||
|
||||
## Build
|
||||
TARGET_ELF=$(TARGET).elf
|
||||
|
||||
all: $(LIBRARY) $(TARGET_ELF) $(TARGET).hex $(TARGET).eep $(TARGET).lst \
|
||||
size Makefile
|
||||
|
||||
##Link
|
||||
$(TARGET_ELF): $(OBJECTS) $(LIBRARY)
|
||||
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||
|
||||
%.hex: $(TARGET_ELF)
|
||||
$(OBJCOPY) -O ihex $(HEX_FLASH_FLAGS) $< $@
|
||||
|
||||
%.eep: $(TARGET_ELF)
|
||||
-$(OBJCOPY) $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0
|
||||
|
||||
%.lst: $(TARGET_ELF)
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
lib: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(COREOBJ) Makefile
|
||||
$(AR) rcs $@ $(COREOBJ)
|
||||
$(OBJDUMP) --syms $@ > $(LIBRARY:.a=.lst)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@
|
||||
|
||||
size: ${TARGET_ELF}
|
||||
@echo
|
||||
@${SIZE} -C --mcu=${MCU} ${TARGET_ELF}
|
||||
|
||||
## Clean target
|
||||
.PHONY: clean
|
||||
clean:
|
||||
touch Makefile
|
||||
-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/*)
|
||||
|
||||
+174
-174
@@ -1,174 +1,174 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Input Objects customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "ai.h"
|
||||
|
||||
/* Analog Input = Photocell */
|
||||
#define MAX_ANALOG_INPUTS 2
|
||||
|
||||
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] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
sprintf(text_string, "AI-%lu", (unsigned long) object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void Analog_Input_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
Present_Value[object_instance] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
rpdata->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(rpdata->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(rpdata->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:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Input Objects customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "ai.h"
|
||||
|
||||
/* Analog Input = Photocell */
|
||||
#define MAX_ANALOG_INPUTS 2
|
||||
|
||||
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] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
sprintf(text_string, "AI-%lu", (unsigned long) object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void Analog_Input_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
Present_Value[object_instance] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
rpdata->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(rpdata->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(rpdata->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:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
@@ -1,232 +1,232 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "dcc.h"
|
||||
#include "handlers.h"
|
||||
/* me */
|
||||
#include "apdu.h"
|
||||
|
||||
uint16_t apdu_timeout(
|
||||
void)
|
||||
{
|
||||
return 3000;
|
||||
}
|
||||
|
||||
uint8_t apdu_retries(
|
||||
void)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool apdu_service_supported(
|
||||
BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
switch (service_supported) {
|
||||
case SERVICE_SUPPORTED_READ_PROPERTY:
|
||||
case SERVICE_SUPPORTED_WHO_IS:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
case SERVICE_SUPPORTED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.
|
||||
When the initiation of communications is disabled,
|
||||
all APDUs shall be processed and responses returned as
|
||||
required... */
|
||||
static bool apdu_confirmed_dcc_disabled(
|
||||
uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dcc_communication_disabled()) {
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
break;
|
||||
default:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
/* If the request is valid and the 'Enable/Disable' parameter is
|
||||
DISABLE_INITIATION, the responding BACnet-user shall
|
||||
discontinue the initiation of messages except for I-Am
|
||||
requests issued in accordance with the Who-Is service procedure.*/
|
||||
static bool apdu_unconfirmed_dcc_disabled(
|
||||
uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dcc_communication_disabled()) {
|
||||
/* there are no Unconfirmed messages that
|
||||
can be processed in this state */
|
||||
status = true;
|
||||
} else if (dcc_communication_initiation_disabled()) {
|
||||
/* WhoIs will be processed and I-Am initiated as response. */
|
||||
switch (service_choice) {
|
||||
case SERVICE_UNCONFIRMED_WHO_IS:
|
||||
break;
|
||||
default:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (apdu_confirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
break;
|
||||
}
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request, service_request_len,
|
||||
src, &service_data);
|
||||
} else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else if (service_choice ==
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE) {
|
||||
handler_reinitialize_device(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else if (service_choice ==
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) {
|
||||
handler_device_communication_control(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (apdu_unconfirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.
|
||||
If communications have been initiation disabled, then
|
||||
WhoIs may be processed. */
|
||||
break;
|
||||
}
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "dcc.h"
|
||||
#include "handlers.h"
|
||||
/* me */
|
||||
#include "apdu.h"
|
||||
|
||||
uint16_t apdu_timeout(
|
||||
void)
|
||||
{
|
||||
return 3000;
|
||||
}
|
||||
|
||||
uint8_t apdu_retries(
|
||||
void)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool apdu_service_supported(
|
||||
BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
switch (service_supported) {
|
||||
case SERVICE_SUPPORTED_READ_PROPERTY:
|
||||
case SERVICE_SUPPORTED_WHO_IS:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
case SERVICE_SUPPORTED_WRITE_PROPERTY:
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.
|
||||
When the initiation of communications is disabled,
|
||||
all APDUs shall be processed and responses returned as
|
||||
required... */
|
||||
static bool apdu_confirmed_dcc_disabled(
|
||||
uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dcc_communication_disabled()) {
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL:
|
||||
case SERVICE_CONFIRMED_REINITIALIZE_DEVICE:
|
||||
break;
|
||||
default:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
/* If the request is valid and the 'Enable/Disable' parameter is
|
||||
DISABLE_INITIATION, the responding BACnet-user shall
|
||||
discontinue the initiation of messages except for I-Am
|
||||
requests issued in accordance with the Who-Is service procedure.*/
|
||||
static bool apdu_unconfirmed_dcc_disabled(
|
||||
uint8_t service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dcc_communication_disabled()) {
|
||||
/* there are no Unconfirmed messages that
|
||||
can be processed in this state */
|
||||
status = true;
|
||||
} else if (dcc_communication_initiation_disabled()) {
|
||||
/* WhoIs will be processed and I-Am initiated as response. */
|
||||
switch (service_choice) {
|
||||
case SERVICE_UNCONFIRMED_WHO_IS:
|
||||
break;
|
||||
default:
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (apdu_confirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are completely disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated. */
|
||||
break;
|
||||
}
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request, service_request_len,
|
||||
src, &service_data);
|
||||
} else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else if (service_choice ==
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE) {
|
||||
handler_reinitialize_device(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else if (service_choice ==
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) {
|
||||
handler_device_communication_control(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
} else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (apdu_unconfirmed_dcc_disabled(service_choice)) {
|
||||
/* When network communications are disabled,
|
||||
only DeviceCommunicationControl and ReinitializeDevice APDUs
|
||||
shall be processed and no messages shall be initiated.
|
||||
If communications have been initiation disabled, then
|
||||
WhoIs may be processed. */
|
||||
break;
|
||||
}
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
+413
-413
@@ -1,413 +1,413 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "av.h"
|
||||
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
|
||||
/* we choose to have a NULL level in our system represented by */
|
||||
/* a particular value. When the priorities are not in use, they */
|
||||
/* will be relinquished (i.e. set to the NULL level). */
|
||||
#define ANALOG_LEVEL_NULL 255
|
||||
/* When all the priorities are level null, the present value returns */
|
||||
/* the Relinquish Default value */
|
||||
#define ANALOG_RELINQUISH_DEFAULT 0
|
||||
/* Here is our Present_Value. They are supposed to be Real, but */
|
||||
/* we don't have that kind of memory, so we will use a single byte */
|
||||
/* and load a Real for returning the value when asked. */
|
||||
static uint8_t Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* we need to have our arrays initialized before answering any calls */
|
||||
static bool Analog_Value_Initialized = false;
|
||||
|
||||
void Analog_Value_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Analog_Value_Initialized) {
|
||||
Analog_Value_Initialized = true;
|
||||
|
||||
/* initialize all the analog output priority arrays to NULL */
|
||||
for (i = 0; i < MAX_ANALOG_VALUES; i++) {
|
||||
Present_Value[i] = ANALOG_LEVEL_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(
|
||||
void)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return MAX_ANALOG_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ANALOG_VALUES;
|
||||
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
float Analog_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = ANALOG_RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
Analog_Value_Init();
|
||||
index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ANALOG_VALUES) {
|
||||
value = Present_Value[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_VALUES) {
|
||||
sprintf(text_string, "AV-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float real_value = (float) 1.414;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Analog_Value_Init();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(rpdata->object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
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:
|
||||
#if 0
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
state = Analog_Value_Out_Of_Service[object_index];
|
||||
#endif
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
#if 0
|
||||
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 = Analog_Value_Instance_To_Index(object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Present_Value[object_index][array_index - 1] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value =
|
||||
Present_Value[object_index][array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], real_value);
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = ANALOG_RELINQUISH_DEFAULT;
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) &&
|
||||
#if 0
|
||||
(property != PROP_PRIORITY_ARRAY) &&
|
||||
#endif
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
uint8_t level = ANALOG_LEVEL_NULL;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
Analog_Value_Init();
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->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? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
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.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
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. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_DESCRIPTION:
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Analog Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "av.h"
|
||||
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
|
||||
/* we choose to have a NULL level in our system represented by */
|
||||
/* a particular value. When the priorities are not in use, they */
|
||||
/* will be relinquished (i.e. set to the NULL level). */
|
||||
#define ANALOG_LEVEL_NULL 255
|
||||
/* When all the priorities are level null, the present value returns */
|
||||
/* the Relinquish Default value */
|
||||
#define ANALOG_RELINQUISH_DEFAULT 0
|
||||
/* Here is our Present_Value. They are supposed to be Real, but */
|
||||
/* we don't have that kind of memory, so we will use a single byte */
|
||||
/* and load a Real for returning the value when asked. */
|
||||
static uint8_t Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* we need to have our arrays initialized before answering any calls */
|
||||
static bool Analog_Value_Initialized = false;
|
||||
|
||||
void Analog_Value_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (!Analog_Value_Initialized) {
|
||||
Analog_Value_Initialized = true;
|
||||
|
||||
/* initialize all the analog output priority arrays to NULL */
|
||||
for (i = 0; i < MAX_ANALOG_VALUES; i++) {
|
||||
Present_Value[i] = ANALOG_LEVEL_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then count how many you have */
|
||||
unsigned Analog_Value_Count(
|
||||
void)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return MAX_ANALOG_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the instance */
|
||||
/* that correlates to the correct index */
|
||||
uint32_t Analog_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
Analog_Value_Init();
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need to return the index */
|
||||
/* that correlates to the correct instance number */
|
||||
unsigned Analog_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_ANALOG_VALUES;
|
||||
|
||||
Analog_Value_Init();
|
||||
if (object_instance < MAX_ANALOG_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
float Analog_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
float value = ANALOG_RELINQUISH_DEFAULT;
|
||||
unsigned index = 0;
|
||||
unsigned i = 0;
|
||||
|
||||
Analog_Value_Init();
|
||||
index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (index < MAX_ANALOG_VALUES) {
|
||||
value = Present_Value[index];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[32] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_VALUES) {
|
||||
sprintf(text_string, "AV-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float real_value = (float) 1.414;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Analog_Value_Init();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(rpdata->object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
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:
|
||||
#if 0
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
state = Analog_Value_Out_Of_Service[object_index];
|
||||
#endif
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
#if 0
|
||||
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 = Analog_Value_Instance_To_Index(object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (array_index <= BACNET_MAX_PRIORITY) {
|
||||
if (Present_Value[object_index][array_index - 1] ==
|
||||
ANALOG_LEVEL_NULL)
|
||||
apdu_len = encode_application_null(&apdu[0]);
|
||||
else {
|
||||
real_value =
|
||||
Present_Value[object_index][array_index - 1];
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], real_value);
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
real_value = ANALOG_RELINQUISH_DEFAULT;
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) &&
|
||||
#if 0
|
||||
(property != PROP_PRIORITY_ARRAY) &&
|
||||
#endif
|
||||
(rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
uint8_t level = ANALOG_LEVEL_NULL;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
Analog_Value_Init();
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->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? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
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.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
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. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_DESCRIPTION:
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
+197
-197
@@ -1,197 +1,197 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Input Objects customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bi.h"
|
||||
|
||||
#define MAX_BINARY_INPUTS 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS) {
|
||||
sprintf(text_string, "BI-%lu", 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_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
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;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Binary_Input_Initialize();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
|
||||
rpdata->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(rpdata->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(rpdata->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:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Input Objects customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h"
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bi.h"
|
||||
|
||||
#define MAX_BINARY_INPUTS 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS) {
|
||||
sprintf(text_string, "BI-%lu", 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_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
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;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Binary_Input_Initialize();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
|
||||
rpdata->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(rpdata->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(rpdata->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:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
+328
-328
@@ -1,328 +1,328 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bv.h"
|
||||
|
||||
#define MAX_BINARY_VALUES 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
static void Binary_Value_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
Binary_Value_Initialize();
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
value = Present_Value[object_instance];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
sprintf(text_string, "BV-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
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;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Binary_Value_Initialize();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
rpdata->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_Value_Name(rpdata->object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
Binary_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->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? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
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 >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. */
|
||||
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. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
#if 0
|
||||
/* NOTE: this Binary Value has no priority array */
|
||||
level = BINARY_NULL;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Binary_Value_Level[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#else
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_POLARITY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "rp.h"
|
||||
#include "bv.h"
|
||||
|
||||
#define MAX_BINARY_VALUES 8
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
static void Binary_Value_Initialize(
|
||||
void)
|
||||
{
|
||||
static bool initialized = false;
|
||||
unsigned i;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
Binary_Value_Initialize();
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
value = Present_Value[object_instance];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[16] = ""; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
sprintf(text_string, "BV-%lu", object_instance);
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
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;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
Binary_Value_Initialize();
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
rpdata->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_Value_Name(rpdata->object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
Binary_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (rpdata->array_index != BACNET_ARRAY_ALL)) {
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->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? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
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 >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. */
|
||||
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. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
#if 0
|
||||
/* NOTE: this Binary Value has no priority array */
|
||||
level = BINARY_NULL;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Binary_Value_Level[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#else
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_POLARITY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,319 +1,319 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#if PRINT_ENABLED
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "bacdef.h"
|
||||
#include "mstp.h"
|
||||
#include "dlmstp.h"
|
||||
#include "rs485.h"
|
||||
#include "npdu.h"
|
||||
#include "handlers.h"
|
||||
|
||||
/* Number of MS/TP Packets Rx/Tx */
|
||||
uint16_t MSTP_Packets = 0;
|
||||
|
||||
/* receive buffer */
|
||||
#pragma udata MSTP_RxData
|
||||
static DLMSTP_PACKET Receive_Buffer;
|
||||
/* temp buffer for NPDU insertion */
|
||||
/* local MS/TP port data - shared with RS-485 */
|
||||
#pragma udata MSTP_PortData
|
||||
volatile struct mstp_port_struct_t MSTP_Port;
|
||||
#pragma udata
|
||||
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
|
||||
void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer);
|
||||
}
|
||||
|
||||
void dlmstp_reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Reinit();
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES);
|
||||
dlmstp_set_max_master(DEFAULT_MAX_MASTER);
|
||||
}
|
||||
|
||||
void dlmstp_init(
|
||||
void)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
/* initialize buffer */
|
||||
Receive_Buffer.ready = false;
|
||||
Receive_Buffer.pdu_len = 0;
|
||||
/* initialize hardware */
|
||||
RS485_Initialize();
|
||||
MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0];
|
||||
MSTP_Init(&MSTP_Port);
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
/* nothing to do for static buffers */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
unsigned npdu_len = 0;
|
||||
uint8_t frame_type = 0;
|
||||
BACNET_ADDRESS src;
|
||||
unsigned i = 0; /* loop counter */
|
||||
|
||||
if (MSTP_Port.TxReady == false) {
|
||||
if (npdu_data->data_expecting_reply)
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
else
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
|
||||
/* load destination MAC address */
|
||||
if (dest && dest->mac_len) {
|
||||
MSTP_Port.TxDestination = dest->mac[0];
|
||||
} else {
|
||||
/* mac_len = 0 is a broadcast address */
|
||||
MSTP_Port.TxDestination = MSTP_BROADCAST_ADDRESS;
|
||||
}
|
||||
dlmstp_get_my_address(&src);
|
||||
if ((MAX_HEADER + pdu_len) > MAX_MPDU) {
|
||||
return -4;
|
||||
}
|
||||
bytes_sent =
|
||||
MSTP_Create_Frame((uint8_t *) & MSTP_Port.TxBuffer[0],
|
||||
sizeof(MSTP_Port.TxBuffer), MSTP_Port.TxFrameType,
|
||||
MSTP_Port.TxDestination, MSTP_Port.This_Station, pdu, pdu_len);
|
||||
MSTP_Port.TxLength = bytes_sent;
|
||||
MSTP_Port.TxReady = true;
|
||||
MSTP_Packets++;
|
||||
}
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
void dlmstp_task(
|
||||
void)
|
||||
{
|
||||
bool bytes_remaining;
|
||||
bool received_frame;
|
||||
|
||||
/* only do receive state machine while we don't have a frame */
|
||||
if ((MSTP_Port.ReceivedValidFrame == false) &&
|
||||
(MSTP_Port.ReceivedInvalidFrame == false)) {
|
||||
do {
|
||||
bytes_remaining = RS485_Check_UART_Data(&MSTP_Port);
|
||||
MSTP_Receive_Frame_FSM(&MSTP_Port);
|
||||
received_frame = MSTP_Port.ReceivedValidFrame ||
|
||||
MSTP_Port.ReceivedInvalidFrame;
|
||||
if (received_frame)
|
||||
break;
|
||||
} while (bytes_remaining);
|
||||
}
|
||||
/* only do master state machine while rx is idle */
|
||||
if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
||||
if (MSTP_Port.This_Station <= DEFAULT_MAX_MASTER) {
|
||||
while (MSTP_Master_Node_FSM(&MSTP_Port)) {
|
||||
/* do nothing while some states fast transition */
|
||||
};
|
||||
}
|
||||
}
|
||||
/* see if there is a packet available, and a place
|
||||
to put the reply (if necessary) and process it */
|
||||
if (Receive_Buffer.ready && !MSTP_Port.TxReady) {
|
||||
if (Receive_Buffer.pdu_len) {
|
||||
MSTP_Packets++;
|
||||
npdu_handler(&Receive_Buffer.address, &Receive_Buffer.pdu[0],
|
||||
Receive_Buffer.pdu_len);
|
||||
}
|
||||
Receive_Buffer.ready = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len)
|
||||
{ /* amount of PDU data */
|
||||
/* PDU is already in the Receive_Buffer */
|
||||
dlmstp_fill_bacnet_address(&Receive_Buffer.address, src);
|
||||
Receive_Buffer.pdu_len = pdu_len;
|
||||
Receive_Buffer.ready = true;
|
||||
}
|
||||
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t mac_address)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127) {
|
||||
MSTP_Port.This_Station = mac_address;
|
||||
/* FIXME: implement your data storage */
|
||||
/* I2C_Write_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
mac_address,
|
||||
EEPROM_MSTP_MAC_ADDR); */
|
||||
if (mac_address > MSTP_Port.Nmax_master)
|
||||
dlmstp_set_max_master(mac_address);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_my_address(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.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) {
|
||||
MSTP_Port.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;
|
||||
}
|
||||
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.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 (MSTP_Port.This_Station <= max_master) {
|
||||
MSTP_Port.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 MSTP_Port.Nmax_master;
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
|
||||
my_address->mac_len = 1;
|
||||
my_address->mac[0] = MSTP_Port.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;
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#if PRINT_ENABLED
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "bacdef.h"
|
||||
#include "mstp.h"
|
||||
#include "dlmstp.h"
|
||||
#include "rs485.h"
|
||||
#include "npdu.h"
|
||||
#include "handlers.h"
|
||||
|
||||
/* Number of MS/TP Packets Rx/Tx */
|
||||
uint16_t MSTP_Packets = 0;
|
||||
|
||||
/* receive buffer */
|
||||
#pragma udata MSTP_RxData
|
||||
static DLMSTP_PACKET Receive_Buffer;
|
||||
/* temp buffer for NPDU insertion */
|
||||
/* local MS/TP port data - shared with RS-485 */
|
||||
#pragma udata MSTP_PortData
|
||||
volatile struct mstp_port_struct_t MSTP_Port;
|
||||
#pragma udata
|
||||
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
|
||||
void dlmstp_millisecond_timer(
|
||||
void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer);
|
||||
}
|
||||
|
||||
void dlmstp_reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Reinit();
|
||||
dlmstp_set_my_address(DEFAULT_MAC_ADDRESS);
|
||||
dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES);
|
||||
dlmstp_set_max_master(DEFAULT_MAX_MASTER);
|
||||
}
|
||||
|
||||
void dlmstp_init(
|
||||
void)
|
||||
{
|
||||
uint8_t data;
|
||||
|
||||
/* initialize buffer */
|
||||
Receive_Buffer.ready = false;
|
||||
Receive_Buffer.pdu_len = 0;
|
||||
/* initialize hardware */
|
||||
RS485_Initialize();
|
||||
MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0];
|
||||
MSTP_Init(&MSTP_Port);
|
||||
}
|
||||
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
/* nothing to do for static buffers */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
unsigned npdu_len = 0;
|
||||
uint8_t frame_type = 0;
|
||||
BACNET_ADDRESS src;
|
||||
unsigned i = 0; /* loop counter */
|
||||
|
||||
if (MSTP_Port.TxReady == false) {
|
||||
if (npdu_data->data_expecting_reply)
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
else
|
||||
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
|
||||
/* load destination MAC address */
|
||||
if (dest && dest->mac_len) {
|
||||
MSTP_Port.TxDestination = dest->mac[0];
|
||||
} else {
|
||||
/* mac_len = 0 is a broadcast address */
|
||||
MSTP_Port.TxDestination = MSTP_BROADCAST_ADDRESS;
|
||||
}
|
||||
dlmstp_get_my_address(&src);
|
||||
if ((MAX_HEADER + pdu_len) > MAX_MPDU) {
|
||||
return -4;
|
||||
}
|
||||
bytes_sent =
|
||||
MSTP_Create_Frame((uint8_t *) & MSTP_Port.TxBuffer[0],
|
||||
sizeof(MSTP_Port.TxBuffer), MSTP_Port.TxFrameType,
|
||||
MSTP_Port.TxDestination, MSTP_Port.This_Station, pdu, pdu_len);
|
||||
MSTP_Port.TxLength = bytes_sent;
|
||||
MSTP_Port.TxReady = true;
|
||||
MSTP_Packets++;
|
||||
}
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
void dlmstp_task(
|
||||
void)
|
||||
{
|
||||
bool bytes_remaining;
|
||||
bool received_frame;
|
||||
|
||||
/* only do receive state machine while we don't have a frame */
|
||||
if ((MSTP_Port.ReceivedValidFrame == false) &&
|
||||
(MSTP_Port.ReceivedInvalidFrame == false)) {
|
||||
do {
|
||||
bytes_remaining = RS485_Check_UART_Data(&MSTP_Port);
|
||||
MSTP_Receive_Frame_FSM(&MSTP_Port);
|
||||
received_frame = MSTP_Port.ReceivedValidFrame ||
|
||||
MSTP_Port.ReceivedInvalidFrame;
|
||||
if (received_frame)
|
||||
break;
|
||||
} while (bytes_remaining);
|
||||
}
|
||||
/* only do master state machine while rx is idle */
|
||||
if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) {
|
||||
if (MSTP_Port.This_Station <= DEFAULT_MAX_MASTER) {
|
||||
while (MSTP_Master_Node_FSM(&MSTP_Port)) {
|
||||
/* do nothing while some states fast transition */
|
||||
};
|
||||
}
|
||||
}
|
||||
/* see if there is a packet available, and a place
|
||||
to put the reply (if necessary) and process it */
|
||||
if (Receive_Buffer.ready && !MSTP_Port.TxReady) {
|
||||
if (Receive_Buffer.pdu_len) {
|
||||
MSTP_Packets++;
|
||||
npdu_handler(&Receive_Buffer.address, &Receive_Buffer.pdu[0],
|
||||
Receive_Buffer.pdu_len);
|
||||
}
|
||||
Receive_Buffer.ready = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len)
|
||||
{ /* amount of PDU data */
|
||||
/* PDU is already in the Receive_Buffer */
|
||||
dlmstp_fill_bacnet_address(&Receive_Buffer.address, src);
|
||||
Receive_Buffer.pdu_len = pdu_len;
|
||||
Receive_Buffer.ready = true;
|
||||
}
|
||||
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t mac_address)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
if (mac_address <= 127) {
|
||||
MSTP_Port.This_Station = mac_address;
|
||||
/* FIXME: implement your data storage */
|
||||
/* I2C_Write_Byte(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
mac_address,
|
||||
EEPROM_MSTP_MAC_ADDR); */
|
||||
if (mac_address > MSTP_Port.Nmax_master)
|
||||
dlmstp_set_max_master(mac_address);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dlmstp_my_address(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.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) {
|
||||
MSTP_Port.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;
|
||||
}
|
||||
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void)
|
||||
{
|
||||
return MSTP_Port.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 (MSTP_Port.This_Station <= max_master) {
|
||||
MSTP_Port.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 MSTP_Port.Nmax_master;
|
||||
}
|
||||
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0; /* counter */
|
||||
|
||||
my_address->mac_len = 1;
|
||||
my_address->mac[0] = MSTP_Port.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;
|
||||
}
|
||||
|
||||
@@ -1,125 +1,125 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 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 DLMSTP_H
|
||||
#define DLMSTP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
/* defines specific to MS/TP */
|
||||
#define MAX_HEADER (2+1+1+1+2+1)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
typedef struct dlmstp_packet {
|
||||
bool ready; /* true if ready to be sent or received */
|
||||
BACNET_ADDRESS address; /* source address */
|
||||
uint8_t frame_type; /* type of message */
|
||||
unsigned pdu_len; /* packet length */
|
||||
uint8_t pdu[MAX_MPDU]; /* packet */
|
||||
} DLMSTP_PACKET;
|
||||
|
||||
/* number of MS/TP tx/rx packets */
|
||||
extern uint16_t MSTP_Packets;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void dlmstp_reinit(
|
||||
void);
|
||||
void dlmstp_init(
|
||||
void);
|
||||
void dlmstp_cleanup(
|
||||
void);
|
||||
void dlmstp_millisecond_timer(
|
||||
void);
|
||||
void dlmstp_task(
|
||||
void);
|
||||
|
||||
/* returns number of bytes sent on success, negative 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 */
|
||||
|
||||
/* 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);
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void);
|
||||
|
||||
/* 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);
|
||||
uint8_t dlmstp_max_master(
|
||||
void);
|
||||
|
||||
/* MAC address for MS/TP */
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t my_address);
|
||||
uint8_t dlmstp_my_address(
|
||||
void);
|
||||
|
||||
/* BACnet address used in datalink */
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest); /* destination address */
|
||||
|
||||
/* MS/TP state machine functions */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 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 DLMSTP_H
|
||||
#define DLMSTP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
/* defines specific to MS/TP */
|
||||
#define MAX_HEADER (2+1+1+1+2+1)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
typedef struct dlmstp_packet {
|
||||
bool ready; /* true if ready to be sent or received */
|
||||
BACNET_ADDRESS address; /* source address */
|
||||
uint8_t frame_type; /* type of message */
|
||||
unsigned pdu_len; /* packet length */
|
||||
uint8_t pdu[MAX_MPDU]; /* packet */
|
||||
} DLMSTP_PACKET;
|
||||
|
||||
/* number of MS/TP tx/rx packets */
|
||||
extern uint16_t MSTP_Packets;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void dlmstp_reinit(
|
||||
void);
|
||||
void dlmstp_init(
|
||||
void);
|
||||
void dlmstp_cleanup(
|
||||
void);
|
||||
void dlmstp_millisecond_timer(
|
||||
void);
|
||||
void dlmstp_task(
|
||||
void);
|
||||
|
||||
/* returns number of bytes sent on success, negative 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 */
|
||||
|
||||
/* 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);
|
||||
unsigned dlmstp_max_info_frames(
|
||||
void);
|
||||
|
||||
/* 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);
|
||||
uint8_t dlmstp_max_master(
|
||||
void);
|
||||
|
||||
/* MAC address for MS/TP */
|
||||
void dlmstp_set_my_address(
|
||||
uint8_t my_address);
|
||||
uint8_t dlmstp_my_address(
|
||||
void);
|
||||
|
||||
/* BACnet address used in datalink */
|
||||
void dlmstp_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
void dlmstp_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest); /* destination address */
|
||||
|
||||
/* MS/TP state machine functions */
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,128 +1,128 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef HARDWARE_H
|
||||
#define HARDWARE_H
|
||||
|
||||
#include <p18f87j60.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* PORTA.0 Photocell Input PORTA.1 LED Row6 PORTA.2 LED Row5 PORTA.3 LED
|
||||
* Row4 PORTA.4 Square Wave input from RTC PORTA.5 LCD RW PORTB.0 Zero
|
||||
* Cross PORTB.1 USB RXF# PORTB.2 USB TXE# PORTB.3 Keypad Row Enable
|
||||
* (74HC373 Output Control) PORTB.4 Keypad Row Gate (74HC373 Gate)
|
||||
* PORTB.5 Switch Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6
|
||||
* ICD connection PORTB.7 ICD connection PORTC.0 Pilot Latch PORTC.1
|
||||
* Pilot Output Enable (low) PORTC.2 Piezo PORTC.3 I2C clock PORTC.4 I2C
|
||||
* data PORTC.5 RS232 enable (low) PORTC.6 RS232 Tx PORTC.7 RS232 Rx
|
||||
* PORTD.0 Data bus PORTD.1 Data bus PORTD.2 Data bus PORTD.3 Data bus
|
||||
* PORTD.4 Data bus PORTD.5 Data bus PORTD.6 Data bus PORTD.7 Data bus
|
||||
* PORTE.0 USB RD PORTE.1 USB WR PORTE.2 LCD RS PORTE.3 485 transmit
|
||||
* enable PORTE.4 Relay data latch PORTE.5 Switch Input Clock PORTE.6
|
||||
* Switch Input High/Low PORTE.7 Switch Input Data PORTF.0 LED Row2
|
||||
* PORTF.1 LED Row1 PORTF.2 LED Col5 PORTF.3 LED Col4 PORTF.4 LED Col3
|
||||
* PORTF.5 LED Col2 PORTF.6 LED Col1 PORTF.7 LED Col0 PORTG.0 485 receive
|
||||
* enable PORTG.1 485 Tx PORTG.2 485 Rx PORTG.3 LCD E PORTG.4 LED Row0 */
|
||||
#define RS485_TX_ENABLE PORTEbits.RE3
|
||||
#define RS485_RX_DISABLE PORTGbits.RG0
|
||||
|
||||
#define LEDPORT PORTG
|
||||
#define LEDTRIS TRISG
|
||||
#define LED_ROW1 PORTGbits.RG1
|
||||
#define LED_ROW2 PORTGbits.RG2
|
||||
#define LED_ROW3 PORTGbits.RG3
|
||||
#define LED_ROW4 PORTGbits.RG4
|
||||
|
||||
#define TURN_OFF_COMPARATORS() CMCON = 0x07
|
||||
|
||||
enum INT_STATE { INT_DISABLED, INT_ENABLED, INT_RESTORE };
|
||||
|
||||
#define RESTART_WDT() { _asm CLRWDT _endasm }
|
||||
|
||||
/* *************************************************************************
|
||||
define ENABLE_GLOBAL_INT() INTCONbits.GIE = 1 £
|
||||
#define DISABLE_GLOBAL_INT() INTCONbits.GIE = 0 £
|
||||
#define ENABLE_PERIPHERAL_INT() INTCONbits.PEIE = 1 £
|
||||
#define DISABLE_PERIPHERAL_INT() INTCONbits.PEIE = 0
|
||||
*************************************************************************** */
|
||||
#define ENABLE_HIGH_INT() INTCONbits.GIE = 1
|
||||
#define DISABLE_HIGH_INT() INTCONbits.GIE = 0
|
||||
|
||||
#define ENABLE_LOW_INT() INTCONbits.PEIE = 1
|
||||
#define DISABLE_LOW_INT() INTCONbits.PEIE = 0
|
||||
|
||||
#define ENABLE_TIMER0_INT() INTCONbits.TMR0IE = 1
|
||||
#define DISABLE_TIMER0_INT() INTCONbits.TMR0IE = 0
|
||||
|
||||
#define ENABLE_TIMER2_INT() PIE1bits.TMR2IE = 1
|
||||
#define DISABLE_TIMER2_INT() PIE1bits.TMR2IE = 0
|
||||
|
||||
#define ENABLE_TIMER4_INT() PIE3bits.TMR4IE = 1
|
||||
#define DISABLE_TIMER4_INT() PIE3bits.TMR4IE = 0
|
||||
|
||||
#define ENABLE_CCP2_INT() PIE2bits.CCP2IE = 1
|
||||
#define DISABLE_CCP2_INT() PIE2bits.CCP2IE = 0
|
||||
|
||||
#define ENABLE_CCP1_INT() PIE1bits.CCP1IE = 1
|
||||
#define DISABLE_CCP1_INT() PIE1bits.CCP1IE = 0
|
||||
|
||||
#define ENABLE_ABUS_INT() PIE1bits.SSPIE = 1
|
||||
#define DISABLE_ABUS_INT() PIE1bits.SSPIE = 0
|
||||
#define CLEAR_ABUS_FLAG() PIR1bits.SSPIF = 0
|
||||
|
||||
#define SETUP_CCP1(x) CCP1CON = x
|
||||
#define SETUP_CCP2(x) CCP2CON = x
|
||||
|
||||
#define DISABLE_RX_INT() PIE1bits.RCIE = 0
|
||||
#define ENABLE_RX_INT() PIE1bits.RCIE = 1
|
||||
|
||||
#define DISABLE_TX_INT() PIE1bits.TXIE = 0
|
||||
#define ENABLE_TX_INT() PIE1bits.TXIE = 1
|
||||
|
||||
#if CLOCKSPEED == 20
|
||||
#define DELAY_US(x) { _asm \
|
||||
MOVLW x \
|
||||
LOOP: \
|
||||
NOP \
|
||||
NOP \
|
||||
DECFSZ WREG, 1, 0 \
|
||||
BRA LOOP \
|
||||
_endasm }
|
||||
#endif
|
||||
|
||||
#define setup_timer4(mode, period, postscale) \
|
||||
T4CON = (mode | (postscale - 1) << 3); \
|
||||
PR4 = period
|
||||
|
||||
#define setup_timer2(mode, period, postscale) \
|
||||
T2CON = (mode | (postscale - 1) << 3); \
|
||||
PR2 = period
|
||||
|
||||
|
||||
/* Global Vars */
|
||||
extern uint8_t Piezo_Timer;
|
||||
extern volatile bool DataPortLocked;
|
||||
|
||||
#endif /* HARDWARE_H */
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef HARDWARE_H
|
||||
#define HARDWARE_H
|
||||
|
||||
#include <p18f87j60.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* PORTA.0 Photocell Input PORTA.1 LED Row6 PORTA.2 LED Row5 PORTA.3 LED
|
||||
* Row4 PORTA.4 Square Wave input from RTC PORTA.5 LCD RW PORTB.0 Zero
|
||||
* Cross PORTB.1 USB RXF# PORTB.2 USB TXE# PORTB.3 Keypad Row Enable
|
||||
* (74HC373 Output Control) PORTB.4 Keypad Row Gate (74HC373 Gate)
|
||||
* PORTB.5 Switch Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6
|
||||
* ICD connection PORTB.7 ICD connection PORTC.0 Pilot Latch PORTC.1
|
||||
* Pilot Output Enable (low) PORTC.2 Piezo PORTC.3 I2C clock PORTC.4 I2C
|
||||
* data PORTC.5 RS232 enable (low) PORTC.6 RS232 Tx PORTC.7 RS232 Rx
|
||||
* PORTD.0 Data bus PORTD.1 Data bus PORTD.2 Data bus PORTD.3 Data bus
|
||||
* PORTD.4 Data bus PORTD.5 Data bus PORTD.6 Data bus PORTD.7 Data bus
|
||||
* PORTE.0 USB RD PORTE.1 USB WR PORTE.2 LCD RS PORTE.3 485 transmit
|
||||
* enable PORTE.4 Relay data latch PORTE.5 Switch Input Clock PORTE.6
|
||||
* Switch Input High/Low PORTE.7 Switch Input Data PORTF.0 LED Row2
|
||||
* PORTF.1 LED Row1 PORTF.2 LED Col5 PORTF.3 LED Col4 PORTF.4 LED Col3
|
||||
* PORTF.5 LED Col2 PORTF.6 LED Col1 PORTF.7 LED Col0 PORTG.0 485 receive
|
||||
* enable PORTG.1 485 Tx PORTG.2 485 Rx PORTG.3 LCD E PORTG.4 LED Row0 */
|
||||
#define RS485_TX_ENABLE PORTEbits.RE3
|
||||
#define RS485_RX_DISABLE PORTGbits.RG0
|
||||
|
||||
#define LEDPORT PORTG
|
||||
#define LEDTRIS TRISG
|
||||
#define LED_ROW1 PORTGbits.RG1
|
||||
#define LED_ROW2 PORTGbits.RG2
|
||||
#define LED_ROW3 PORTGbits.RG3
|
||||
#define LED_ROW4 PORTGbits.RG4
|
||||
|
||||
#define TURN_OFF_COMPARATORS() CMCON = 0x07
|
||||
|
||||
enum INT_STATE { INT_DISABLED, INT_ENABLED, INT_RESTORE };
|
||||
|
||||
#define RESTART_WDT() { _asm CLRWDT _endasm }
|
||||
|
||||
/* *************************************************************************
|
||||
define ENABLE_GLOBAL_INT() INTCONbits.GIE = 1 £
|
||||
#define DISABLE_GLOBAL_INT() INTCONbits.GIE = 0 £
|
||||
#define ENABLE_PERIPHERAL_INT() INTCONbits.PEIE = 1 £
|
||||
#define DISABLE_PERIPHERAL_INT() INTCONbits.PEIE = 0
|
||||
*************************************************************************** */
|
||||
#define ENABLE_HIGH_INT() INTCONbits.GIE = 1
|
||||
#define DISABLE_HIGH_INT() INTCONbits.GIE = 0
|
||||
|
||||
#define ENABLE_LOW_INT() INTCONbits.PEIE = 1
|
||||
#define DISABLE_LOW_INT() INTCONbits.PEIE = 0
|
||||
|
||||
#define ENABLE_TIMER0_INT() INTCONbits.TMR0IE = 1
|
||||
#define DISABLE_TIMER0_INT() INTCONbits.TMR0IE = 0
|
||||
|
||||
#define ENABLE_TIMER2_INT() PIE1bits.TMR2IE = 1
|
||||
#define DISABLE_TIMER2_INT() PIE1bits.TMR2IE = 0
|
||||
|
||||
#define ENABLE_TIMER4_INT() PIE3bits.TMR4IE = 1
|
||||
#define DISABLE_TIMER4_INT() PIE3bits.TMR4IE = 0
|
||||
|
||||
#define ENABLE_CCP2_INT() PIE2bits.CCP2IE = 1
|
||||
#define DISABLE_CCP2_INT() PIE2bits.CCP2IE = 0
|
||||
|
||||
#define ENABLE_CCP1_INT() PIE1bits.CCP1IE = 1
|
||||
#define DISABLE_CCP1_INT() PIE1bits.CCP1IE = 0
|
||||
|
||||
#define ENABLE_ABUS_INT() PIE1bits.SSPIE = 1
|
||||
#define DISABLE_ABUS_INT() PIE1bits.SSPIE = 0
|
||||
#define CLEAR_ABUS_FLAG() PIR1bits.SSPIF = 0
|
||||
|
||||
#define SETUP_CCP1(x) CCP1CON = x
|
||||
#define SETUP_CCP2(x) CCP2CON = x
|
||||
|
||||
#define DISABLE_RX_INT() PIE1bits.RCIE = 0
|
||||
#define ENABLE_RX_INT() PIE1bits.RCIE = 1
|
||||
|
||||
#define DISABLE_TX_INT() PIE1bits.TXIE = 0
|
||||
#define ENABLE_TX_INT() PIE1bits.TXIE = 1
|
||||
|
||||
#if CLOCKSPEED == 20
|
||||
#define DELAY_US(x) { _asm \
|
||||
MOVLW x \
|
||||
LOOP: \
|
||||
NOP \
|
||||
NOP \
|
||||
DECFSZ WREG, 1, 0 \
|
||||
BRA LOOP \
|
||||
_endasm }
|
||||
#endif
|
||||
|
||||
#define setup_timer4(mode, period, postscale) \
|
||||
T4CON = (mode | (postscale - 1) << 3); \
|
||||
PR4 = period
|
||||
|
||||
#define setup_timer2(mode, period, postscale) \
|
||||
T2CON = (mode | (postscale - 1) << 3); \
|
||||
PR2 = period
|
||||
|
||||
|
||||
/* Global Vars */
|
||||
extern uint8_t Piezo_Timer;
|
||||
extern volatile bool DataPortLocked;
|
||||
|
||||
#endif /* HARDWARE_H */
|
||||
|
||||
@@ -1,206 +1,206 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include "stdint.h"
|
||||
#include "hardware.h"
|
||||
#include "rs485.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
/* from main.c */
|
||||
extern volatile uint8_t Milliseconds;
|
||||
|
||||
void InterruptHandlerHigh(
|
||||
void);
|
||||
void InterruptHandlerLow(
|
||||
void);
|
||||
void Interrupt_Timer2(
|
||||
void);
|
||||
void Interrupt_Timer3(
|
||||
void);
|
||||
void Interrupt_Timer4(
|
||||
void);
|
||||
void Interrupt_USART_Rx(
|
||||
void);
|
||||
void Interrupt_USART_Tx(
|
||||
void);
|
||||
void Interrupt_CCP2(
|
||||
void);
|
||||
void INT0_Interrupt(
|
||||
void);
|
||||
|
||||
#pragma code InterruptVectorHigh = 0x08
|
||||
void InterruptVectorHigh(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerHigh _endasm}
|
||||
#pragma code
|
||||
#pragma code InterruptVectorLow = 0x18
|
||||
void InterruptVectorLow(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerLow _endasm}
|
||||
#pragma code
|
||||
#pragma interrupt InterruptHandlerHigh
|
||||
void InterruptHandlerHigh(
|
||||
void)
|
||||
{
|
||||
#if 0
|
||||
/* check for USART Rx int */
|
||||
if ((PIR1bits.RCIF) && (PIE1bits.RCIE)) {
|
||||
if ((RCSTA1bits.FERR) || (RCSTA1bits.OERR)) {
|
||||
Comstat.Rx_Bufferoverrun = TRUE;
|
||||
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
|
||||
} else if (Comstat.Rx_Bytes++ < RX_BUFFER_SIZE - 1) {
|
||||
Rx_Buffer[Comstat.RxHead++] = RCREG1;
|
||||
|
||||
/* Stick a Null on the end to let us use str functions on our
|
||||
* buffer */
|
||||
Rx_Buffer[Comstat.RxHead] = 0;
|
||||
} else {
|
||||
Comstat.Rx_Bufferoverrun = TRUE;
|
||||
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check for timer0 int */
|
||||
if ((INTCONbits.TMR0IF) && (INTCONbits.TMR0IE)) {
|
||||
INTCONbits.TMR0IF = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma interruptlow InterruptHandlerLow save = PROD, section(".tmpdata"), TABLAT, TBLPTR, section \
|
||||
("MATH_DATA")
|
||||
|
||||
void InterruptHandlerLow(
|
||||
void)
|
||||
{
|
||||
/* check for timer2 int */
|
||||
if ((PIR1bits.TMR2IF) && (PIE1bits.TMR2IE)) {
|
||||
PIR1bits.TMR2IF = 0;
|
||||
Interrupt_Timer2();
|
||||
}
|
||||
|
||||
/* check for timer3 int */
|
||||
if ((PIR2bits.TMR3IF) && (PIE2bits.TMR3IE)) {
|
||||
PIR2bits.TMR3IF = 0;
|
||||
Interrupt_Timer3();
|
||||
}
|
||||
|
||||
/* check for timer4 int */
|
||||
if ((PIR3bits.TMR4IF) && (PIE3bits.TMR4IE)) {
|
||||
PIR3bits.TMR4IF = 0;
|
||||
dlmstp_millisecond_timer();
|
||||
Interrupt_Timer4();
|
||||
}
|
||||
|
||||
/* check for compare int */
|
||||
if ((PIR2bits.CCP2IF) && (PIE2bits.CCP2IE)) {
|
||||
PIR2bits.CCP2IF = 0;
|
||||
Interrupt_CCP2();
|
||||
}
|
||||
|
||||
/* check for USART Tx int */
|
||||
if ((PIR3bits.TX2IF) && (PIE3bits.TX2IE)) {
|
||||
RS485_Interrupt_Tx();
|
||||
}
|
||||
|
||||
/* check for USART Rx int */
|
||||
if ((PIR3bits.RC2IF) && (PIE3bits.RC2IE)) {
|
||||
RS485_Interrupt_Rx();
|
||||
}
|
||||
|
||||
/* Unused Interrupts
|
||||
//check for timer1 int
|
||||
if ((PIR1bits.TMR1IF) && (PIE1bits.TMR1IE))
|
||||
{
|
||||
PIR1bits.TMR1IF = 0;
|
||||
Interrupt_Timer1();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR1bits.CCP1IF) && (PIE1bits.CCP1IE))
|
||||
{
|
||||
PIR1bits.CCP1IF = 0;
|
||||
Interrupt_CCP1();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR3bits.CCP3IF) && (PIE3bits.CCP3IE))
|
||||
{
|
||||
PIR3bits.CCP3IF = 0;
|
||||
Interrupt_CCP3();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR3bits.CCP4IF) && (PIE3bits.CCP4IE))
|
||||
{
|
||||
PIR3bits.CCP4IF = 0;
|
||||
|
||||
Interrupt_CCP4();
|
||||
}
|
||||
|
||||
//check for AD int
|
||||
if ((PIR1bits.ADIF) && (PIE1bits.ADIE))
|
||||
{
|
||||
PIR1bits.ADIF = 0;
|
||||
Interrupt_ADC();
|
||||
}
|
||||
|
||||
//check for MSSP int
|
||||
if ((PIR1bits.SSPIF) && (PIE1bits.SSPIE))
|
||||
{
|
||||
PIR1bits.SSPIF = 0;
|
||||
Interrupt_SSP();
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
void Interrupt_Timer2(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
void Interrupt_Timer3(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Timer4 is set to go off every 1ms. This is our system tick */
|
||||
void Interrupt_Timer4(
|
||||
void)
|
||||
{
|
||||
/* Milisecond is our system tick */
|
||||
if (Milliseconds < 0xFF)
|
||||
++Milliseconds;
|
||||
}
|
||||
|
||||
void Interrupt_CCP2(
|
||||
void)
|
||||
{
|
||||
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include "stdint.h"
|
||||
#include "hardware.h"
|
||||
#include "rs485.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
/* from main.c */
|
||||
extern volatile uint8_t Milliseconds;
|
||||
|
||||
void InterruptHandlerHigh(
|
||||
void);
|
||||
void InterruptHandlerLow(
|
||||
void);
|
||||
void Interrupt_Timer2(
|
||||
void);
|
||||
void Interrupt_Timer3(
|
||||
void);
|
||||
void Interrupt_Timer4(
|
||||
void);
|
||||
void Interrupt_USART_Rx(
|
||||
void);
|
||||
void Interrupt_USART_Tx(
|
||||
void);
|
||||
void Interrupt_CCP2(
|
||||
void);
|
||||
void INT0_Interrupt(
|
||||
void);
|
||||
|
||||
#pragma code InterruptVectorHigh = 0x08
|
||||
void InterruptVectorHigh(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerHigh _endasm}
|
||||
#pragma code
|
||||
#pragma code InterruptVectorLow = 0x18
|
||||
void InterruptVectorLow(
|
||||
void)
|
||||
{
|
||||
/* jump to interrupt routine */
|
||||
_asm goto InterruptHandlerLow _endasm}
|
||||
#pragma code
|
||||
#pragma interrupt InterruptHandlerHigh
|
||||
void InterruptHandlerHigh(
|
||||
void)
|
||||
{
|
||||
#if 0
|
||||
/* check for USART Rx int */
|
||||
if ((PIR1bits.RCIF) && (PIE1bits.RCIE)) {
|
||||
if ((RCSTA1bits.FERR) || (RCSTA1bits.OERR)) {
|
||||
Comstat.Rx_Bufferoverrun = TRUE;
|
||||
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
|
||||
} else if (Comstat.Rx_Bytes++ < RX_BUFFER_SIZE - 1) {
|
||||
Rx_Buffer[Comstat.RxHead++] = RCREG1;
|
||||
|
||||
/* Stick a Null on the end to let us use str functions on our
|
||||
* buffer */
|
||||
Rx_Buffer[Comstat.RxHead] = 0;
|
||||
} else {
|
||||
Comstat.Rx_Bufferoverrun = TRUE;
|
||||
PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check for timer0 int */
|
||||
if ((INTCONbits.TMR0IF) && (INTCONbits.TMR0IE)) {
|
||||
INTCONbits.TMR0IF = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma interruptlow InterruptHandlerLow save = PROD, section(".tmpdata"), TABLAT, TBLPTR, section \
|
||||
("MATH_DATA")
|
||||
|
||||
void InterruptHandlerLow(
|
||||
void)
|
||||
{
|
||||
/* check for timer2 int */
|
||||
if ((PIR1bits.TMR2IF) && (PIE1bits.TMR2IE)) {
|
||||
PIR1bits.TMR2IF = 0;
|
||||
Interrupt_Timer2();
|
||||
}
|
||||
|
||||
/* check for timer3 int */
|
||||
if ((PIR2bits.TMR3IF) && (PIE2bits.TMR3IE)) {
|
||||
PIR2bits.TMR3IF = 0;
|
||||
Interrupt_Timer3();
|
||||
}
|
||||
|
||||
/* check for timer4 int */
|
||||
if ((PIR3bits.TMR4IF) && (PIE3bits.TMR4IE)) {
|
||||
PIR3bits.TMR4IF = 0;
|
||||
dlmstp_millisecond_timer();
|
||||
Interrupt_Timer4();
|
||||
}
|
||||
|
||||
/* check for compare int */
|
||||
if ((PIR2bits.CCP2IF) && (PIE2bits.CCP2IE)) {
|
||||
PIR2bits.CCP2IF = 0;
|
||||
Interrupt_CCP2();
|
||||
}
|
||||
|
||||
/* check for USART Tx int */
|
||||
if ((PIR3bits.TX2IF) && (PIE3bits.TX2IE)) {
|
||||
RS485_Interrupt_Tx();
|
||||
}
|
||||
|
||||
/* check for USART Rx int */
|
||||
if ((PIR3bits.RC2IF) && (PIE3bits.RC2IE)) {
|
||||
RS485_Interrupt_Rx();
|
||||
}
|
||||
|
||||
/* Unused Interrupts
|
||||
//check for timer1 int
|
||||
if ((PIR1bits.TMR1IF) && (PIE1bits.TMR1IE))
|
||||
{
|
||||
PIR1bits.TMR1IF = 0;
|
||||
Interrupt_Timer1();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR1bits.CCP1IF) && (PIE1bits.CCP1IE))
|
||||
{
|
||||
PIR1bits.CCP1IF = 0;
|
||||
Interrupt_CCP1();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR3bits.CCP3IF) && (PIE3bits.CCP3IE))
|
||||
{
|
||||
PIR3bits.CCP3IF = 0;
|
||||
Interrupt_CCP3();
|
||||
}
|
||||
|
||||
//check for compare int
|
||||
if ((PIR3bits.CCP4IF) && (PIE3bits.CCP4IE))
|
||||
{
|
||||
PIR3bits.CCP4IF = 0;
|
||||
|
||||
Interrupt_CCP4();
|
||||
}
|
||||
|
||||
//check for AD int
|
||||
if ((PIR1bits.ADIF) && (PIE1bits.ADIE))
|
||||
{
|
||||
PIR1bits.ADIF = 0;
|
||||
Interrupt_ADC();
|
||||
}
|
||||
|
||||
//check for MSSP int
|
||||
if ((PIR1bits.SSPIF) && (PIE1bits.SSPIE))
|
||||
{
|
||||
PIR1bits.SSPIF = 0;
|
||||
Interrupt_SSP();
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
void Interrupt_Timer2(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
void Interrupt_Timer3(
|
||||
void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Timer4 is set to go off every 1ms. This is our system tick */
|
||||
void Interrupt_Timer4(
|
||||
void)
|
||||
{
|
||||
/* Milisecond is our system tick */
|
||||
if (Milliseconds < 0xFF)
|
||||
++Milliseconds;
|
||||
}
|
||||
|
||||
void Interrupt_CCP2(
|
||||
void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,223 +1,223 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memmove */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "stdint.h"
|
||||
#include "hardware.h"
|
||||
/* BACnet */
|
||||
#include "apdu.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
#include "rs485.h"
|
||||
|
||||
/* chip configuration data */
|
||||
/* define this to enable ICD */
|
||||
/* #define USE_ICD */
|
||||
|
||||
/* Configuration Bits */
|
||||
#pragma config FOSC = HSPLL
|
||||
#pragma config FOSC2 = ON
|
||||
#pragma config FCMEN = OFF
|
||||
#pragma config XINST = OFF
|
||||
#pragma config IESO = OFF
|
||||
#pragma config CCP2MX = ON
|
||||
#pragma config ECCPMX = ON
|
||||
#pragma config STVR = OFF
|
||||
#pragma config CP0 = OFF
|
||||
#pragma config ETHLED = ON
|
||||
|
||||
volatile uint8_t Milliseconds = 0;
|
||||
volatile uint8_t Zero_Cross_Timeout = 0;
|
||||
|
||||
void Reinitialize(
|
||||
void)
|
||||
{
|
||||
uint8_t i;
|
||||
char name = 0;
|
||||
|
||||
_asm reset _endasm return;
|
||||
}
|
||||
|
||||
void Global_Int(
|
||||
enum INT_STATE state)
|
||||
{
|
||||
static uint8_t intstate = 0;
|
||||
|
||||
switch (state) {
|
||||
case INT_DISABLED:
|
||||
intstate >>= 2;
|
||||
intstate |= (INTCON & 0xC0);
|
||||
break;
|
||||
case INT_ENABLED:
|
||||
INTCONbits.GIE = 1;
|
||||
INTCONbits.PEIE = 1;
|
||||
intstate <<= 2;
|
||||
break;
|
||||
case INT_RESTORE:
|
||||
INTCON |= (intstate & 0xC0);
|
||||
intstate <<= 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hardware_Initialize(
|
||||
void)
|
||||
{
|
||||
/* PORTA.0 Input - Photocell PORTA.1 Output - LED Row6 PORTA.2 Output
|
||||
* - LED Row5 PORTA.3 Output - LED Row4 PORTA.4 Input - Square Wave
|
||||
* input from RTC PORTA.5 Output - LCD RW */
|
||||
TRISA = 0xD1;
|
||||
|
||||
/* PORTB.0 Input - Zero Cross PORTB.1 Input - USB RXF# PORTB.2 Input
|
||||
* USB TXE# PORTB.3 Output - Keypad Row Enable (74HC373 Output Control)
|
||||
* PORTB.4 Output Keypad Row Gate (74HC373 Gate) PORTB.5 Output Switch
|
||||
* Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6 Input - ICD
|
||||
* connection PORTB.7 Input - ICD connection */
|
||||
TRISB = 0xC7;
|
||||
|
||||
/* PORTC.0 Output - Pilot Latch PORTC.1 Output - Pilot Output Enable
|
||||
* (low) PORTC.2 I/O - Piezo PORTC.3 Input - I2C clock PORTC.4 Input
|
||||
* I2C data PORTC.5 Output RS232 enable (low) PORTC.6 Output - RS232 Tx
|
||||
* PORTC.7 Input - RS232 Rx */
|
||||
TRISC = 0x9C;
|
||||
|
||||
/* PORTD.0 I/O - Data bus PORTD.1 I/O - Data bus PORTD.2 I/O - Data
|
||||
* bus PORTD.3 I/O - Data bus PORTD.4 I/O - Data bus PORTD.5 I/O - Data
|
||||
* bus PORTD.6 I/O - Data bus PORTD.7 I/O - Data bus */
|
||||
TRISD = 0xFF;
|
||||
|
||||
/* PORTE.0 Input - USB RD PORTE.1 Input - USB WR PORTE.2 Output - LCD
|
||||
* RS PORTE.3 Output - 485 transmit enable PORTE.4 Output - Relay data
|
||||
* latch PORTE.5 Output Switch Input Clock PORTE.6 Output - Switch
|
||||
* Input High/Low PORTE.7 Input Switch Input Data */
|
||||
TRISE = 0x83;
|
||||
|
||||
/* PORTF.0 Output - LED Row2 PORTF.1 Output - LED Row1 PORTF.2 Output
|
||||
* - LED Col5 PORTF.3 Output - LED Col4 PORTF.4 Output - LED Col3
|
||||
* PORTF.5 Output - LED Col2 PORTF.6 Output - LED Col1 PORTF.7 Output
|
||||
* LED Col0 */
|
||||
TRISF = 0x00;
|
||||
|
||||
/* PORTG.0 Output - 485 receive enable PORTG.1 Output - 485 Tx PORTG.2
|
||||
* Input 485 Rx PORTG.3 Output - LCD E PORTG.4 Output - LED Row0 */
|
||||
TRISG = 0xE6;
|
||||
|
||||
/* Turn all leds off. These are the hardware pins */
|
||||
LED_ROW1 = 1;
|
||||
LED_ROW2 = 1;
|
||||
LED_ROW3 = 1;
|
||||
LED_ROW4 = 1;
|
||||
LEDPORT = 0x03;
|
||||
|
||||
/* The following gives us a PWM frequency of 1.990KHz with a 50% duty
|
||||
* cycle It also serves to multiplex the LEDs. */
|
||||
CCPR1L = 0x4E;
|
||||
CCP1CON = 0x2F;
|
||||
setup_timer2(6, 156, 2);
|
||||
PIE1bits.TMR2IE = 1;
|
||||
|
||||
/* We will use Timer4 as our system tick timer. Our system tick is set
|
||||
* to 1ms. Hold off on enabling the int. */
|
||||
setup_timer4(5, 250, 5);
|
||||
|
||||
/* Setup our interrupt priorities */
|
||||
RCONbits.IPEN = 1;
|
||||
IPR1 = 0;
|
||||
IPR2 = 0;
|
||||
IPR3 = 0;
|
||||
|
||||
/* Setup TMR0 to be high priority */
|
||||
INTCON2 = 0xFC;
|
||||
INTCON3 = 0;
|
||||
|
||||
/* USART 1 high priority */
|
||||
IPR1bits.RC1IP = 1;
|
||||
IPR1bits.TX1IP = 1;
|
||||
|
||||
/* Finally enable our ints */
|
||||
Global_Int(INT_ENABLED);
|
||||
}
|
||||
|
||||
void Initialize_Variables(
|
||||
void)
|
||||
{
|
||||
/* Check to see if we need to initialize our eeproms */
|
||||
ENABLE_TIMER4_INT();
|
||||
/* interrupts must be enabled before we read our inputs */
|
||||
Global_Int(INT_ENABLED);
|
||||
/* Start our time from now */
|
||||
Milliseconds = 0;
|
||||
}
|
||||
|
||||
void MainTasks(
|
||||
void)
|
||||
{
|
||||
static uint16_t millisecond_counter = 0;
|
||||
/* Handle our millisecond counters */
|
||||
while (Milliseconds) {
|
||||
millisecond_counter++;
|
||||
--Milliseconds;
|
||||
}
|
||||
/* Handle our seconds counters */
|
||||
if (millisecond_counter > 1000) {
|
||||
millisecond_counter -= 1000;
|
||||
dcc_timer_seconds(1);
|
||||
}
|
||||
}
|
||||
|
||||
void main(
|
||||
void)
|
||||
{
|
||||
RCONbits.NOT_POR = 1;
|
||||
RCONbits.NOT_RI = 1;
|
||||
Hardware_Initialize();
|
||||
Initialize_Variables();
|
||||
/* initialize BACnet Data Link Layer */
|
||||
dlmstp_set_my_address(42);
|
||||
dlmstp_set_max_info_frames(1);
|
||||
dlmstp_set_max_master(127);
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
dlmstp_init();
|
||||
/* Handle anything that needs to be done on powerup */
|
||||
/* Greet the BACnet world! */
|
||||
Send_I_Am(&Handler_Transmit_Buffer[0]);
|
||||
/* Main loop */
|
||||
while (TRUE) {
|
||||
RESTART_WDT();
|
||||
dlmstp_task();
|
||||
MainTasks();
|
||||
Global_Int(INT_ENABLED);
|
||||
ENABLE_TIMER4_INT();
|
||||
}
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h> /* for memmove */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "stdint.h"
|
||||
#include "hardware.h"
|
||||
/* BACnet */
|
||||
#include "apdu.h"
|
||||
#include "datalink.h"
|
||||
#include "dcc.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
#include "rs485.h"
|
||||
|
||||
/* chip configuration data */
|
||||
/* define this to enable ICD */
|
||||
/* #define USE_ICD */
|
||||
|
||||
/* Configuration Bits */
|
||||
#pragma config FOSC = HSPLL
|
||||
#pragma config FOSC2 = ON
|
||||
#pragma config FCMEN = OFF
|
||||
#pragma config XINST = OFF
|
||||
#pragma config IESO = OFF
|
||||
#pragma config CCP2MX = ON
|
||||
#pragma config ECCPMX = ON
|
||||
#pragma config STVR = OFF
|
||||
#pragma config CP0 = OFF
|
||||
#pragma config ETHLED = ON
|
||||
|
||||
volatile uint8_t Milliseconds = 0;
|
||||
volatile uint8_t Zero_Cross_Timeout = 0;
|
||||
|
||||
void Reinitialize(
|
||||
void)
|
||||
{
|
||||
uint8_t i;
|
||||
char name = 0;
|
||||
|
||||
_asm reset _endasm return;
|
||||
}
|
||||
|
||||
void Global_Int(
|
||||
enum INT_STATE state)
|
||||
{
|
||||
static uint8_t intstate = 0;
|
||||
|
||||
switch (state) {
|
||||
case INT_DISABLED:
|
||||
intstate >>= 2;
|
||||
intstate |= (INTCON & 0xC0);
|
||||
break;
|
||||
case INT_ENABLED:
|
||||
INTCONbits.GIE = 1;
|
||||
INTCONbits.PEIE = 1;
|
||||
intstate <<= 2;
|
||||
break;
|
||||
case INT_RESTORE:
|
||||
INTCON |= (intstate & 0xC0);
|
||||
intstate <<= 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hardware_Initialize(
|
||||
void)
|
||||
{
|
||||
/* PORTA.0 Input - Photocell PORTA.1 Output - LED Row6 PORTA.2 Output
|
||||
* - LED Row5 PORTA.3 Output - LED Row4 PORTA.4 Input - Square Wave
|
||||
* input from RTC PORTA.5 Output - LCD RW */
|
||||
TRISA = 0xD1;
|
||||
|
||||
/* PORTB.0 Input - Zero Cross PORTB.1 Input - USB RXF# PORTB.2 Input
|
||||
* USB TXE# PORTB.3 Output - Keypad Row Enable (74HC373 Output Control)
|
||||
* PORTB.4 Output Keypad Row Gate (74HC373 Gate) PORTB.5 Output Switch
|
||||
* Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6 Input - ICD
|
||||
* connection PORTB.7 Input - ICD connection */
|
||||
TRISB = 0xC7;
|
||||
|
||||
/* PORTC.0 Output - Pilot Latch PORTC.1 Output - Pilot Output Enable
|
||||
* (low) PORTC.2 I/O - Piezo PORTC.3 Input - I2C clock PORTC.4 Input
|
||||
* I2C data PORTC.5 Output RS232 enable (low) PORTC.6 Output - RS232 Tx
|
||||
* PORTC.7 Input - RS232 Rx */
|
||||
TRISC = 0x9C;
|
||||
|
||||
/* PORTD.0 I/O - Data bus PORTD.1 I/O - Data bus PORTD.2 I/O - Data
|
||||
* bus PORTD.3 I/O - Data bus PORTD.4 I/O - Data bus PORTD.5 I/O - Data
|
||||
* bus PORTD.6 I/O - Data bus PORTD.7 I/O - Data bus */
|
||||
TRISD = 0xFF;
|
||||
|
||||
/* PORTE.0 Input - USB RD PORTE.1 Input - USB WR PORTE.2 Output - LCD
|
||||
* RS PORTE.3 Output - 485 transmit enable PORTE.4 Output - Relay data
|
||||
* latch PORTE.5 Output Switch Input Clock PORTE.6 Output - Switch
|
||||
* Input High/Low PORTE.7 Input Switch Input Data */
|
||||
TRISE = 0x83;
|
||||
|
||||
/* PORTF.0 Output - LED Row2 PORTF.1 Output - LED Row1 PORTF.2 Output
|
||||
* - LED Col5 PORTF.3 Output - LED Col4 PORTF.4 Output - LED Col3
|
||||
* PORTF.5 Output - LED Col2 PORTF.6 Output - LED Col1 PORTF.7 Output
|
||||
* LED Col0 */
|
||||
TRISF = 0x00;
|
||||
|
||||
/* PORTG.0 Output - 485 receive enable PORTG.1 Output - 485 Tx PORTG.2
|
||||
* Input 485 Rx PORTG.3 Output - LCD E PORTG.4 Output - LED Row0 */
|
||||
TRISG = 0xE6;
|
||||
|
||||
/* Turn all leds off. These are the hardware pins */
|
||||
LED_ROW1 = 1;
|
||||
LED_ROW2 = 1;
|
||||
LED_ROW3 = 1;
|
||||
LED_ROW4 = 1;
|
||||
LEDPORT = 0x03;
|
||||
|
||||
/* The following gives us a PWM frequency of 1.990KHz with a 50% duty
|
||||
* cycle It also serves to multiplex the LEDs. */
|
||||
CCPR1L = 0x4E;
|
||||
CCP1CON = 0x2F;
|
||||
setup_timer2(6, 156, 2);
|
||||
PIE1bits.TMR2IE = 1;
|
||||
|
||||
/* We will use Timer4 as our system tick timer. Our system tick is set
|
||||
* to 1ms. Hold off on enabling the int. */
|
||||
setup_timer4(5, 250, 5);
|
||||
|
||||
/* Setup our interrupt priorities */
|
||||
RCONbits.IPEN = 1;
|
||||
IPR1 = 0;
|
||||
IPR2 = 0;
|
||||
IPR3 = 0;
|
||||
|
||||
/* Setup TMR0 to be high priority */
|
||||
INTCON2 = 0xFC;
|
||||
INTCON3 = 0;
|
||||
|
||||
/* USART 1 high priority */
|
||||
IPR1bits.RC1IP = 1;
|
||||
IPR1bits.TX1IP = 1;
|
||||
|
||||
/* Finally enable our ints */
|
||||
Global_Int(INT_ENABLED);
|
||||
}
|
||||
|
||||
void Initialize_Variables(
|
||||
void)
|
||||
{
|
||||
/* Check to see if we need to initialize our eeproms */
|
||||
ENABLE_TIMER4_INT();
|
||||
/* interrupts must be enabled before we read our inputs */
|
||||
Global_Int(INT_ENABLED);
|
||||
/* Start our time from now */
|
||||
Milliseconds = 0;
|
||||
}
|
||||
|
||||
void MainTasks(
|
||||
void)
|
||||
{
|
||||
static uint16_t millisecond_counter = 0;
|
||||
/* Handle our millisecond counters */
|
||||
while (Milliseconds) {
|
||||
millisecond_counter++;
|
||||
--Milliseconds;
|
||||
}
|
||||
/* Handle our seconds counters */
|
||||
if (millisecond_counter > 1000) {
|
||||
millisecond_counter -= 1000;
|
||||
dcc_timer_seconds(1);
|
||||
}
|
||||
}
|
||||
|
||||
void main(
|
||||
void)
|
||||
{
|
||||
RCONbits.NOT_POR = 1;
|
||||
RCONbits.NOT_RI = 1;
|
||||
Hardware_Initialize();
|
||||
Initialize_Variables();
|
||||
/* initialize BACnet Data Link Layer */
|
||||
dlmstp_set_my_address(42);
|
||||
dlmstp_set_max_info_frames(1);
|
||||
dlmstp_set_max_master(127);
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
dlmstp_init();
|
||||
/* Handle anything that needs to be done on powerup */
|
||||
/* Greet the BACnet world! */
|
||||
Send_I_Am(&Handler_Transmit_Buffer[0]);
|
||||
/* Main loop */
|
||||
while (TRUE) {
|
||||
RESTART_WDT();
|
||||
dlmstp_task();
|
||||
MainTasks();
|
||||
Global_Int(INT_ENABLED);
|
||||
ENABLE_TIMER4_INT();
|
||||
}
|
||||
}
|
||||
|
||||
+1250
-1250
File diff suppressed because it is too large
Load Diff
@@ -1,188 +1,188 @@
|
||||
/*####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 MSTP_H
|
||||
#define MSTP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacdef.h"
|
||||
#include "mstpdef.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
struct mstp_port_struct_t {
|
||||
MSTP_RECEIVE_STATE receive_state;
|
||||
/* When a master node is powered up or reset, */
|
||||
/* it shall unconditionally enter the INITIALIZE state. */
|
||||
MSTP_MASTER_STATE master_state;
|
||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||
/* if an error is detected during the reception of a frame. */
|
||||
/* Set to FALSE by the main state machine. */
|
||||
unsigned ReceiveError:1;
|
||||
/* There is data in the buffer */
|
||||
unsigned DataAvailable:1;
|
||||
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;
|
||||
/* stores the latest received data */
|
||||
uint8_t DataRegister;
|
||||
/* Used to accumulate the CRC on the data field of a frame. */
|
||||
uint16_t DataCRC;
|
||||
/* Used to store the data length of a received frame. */
|
||||
unsigned DataLength;
|
||||
/* Used to store the destination address of a received frame. */
|
||||
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 */
|
||||
uint8_t EventCount;
|
||||
/* Used to store the frame type of a received frame. */
|
||||
uint8_t FrameType;
|
||||
/* 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. */
|
||||
unsigned FrameCount;
|
||||
/* Used to accumulate the CRC on the header of a frame. */
|
||||
uint8_t HeaderCRC;
|
||||
/* Used as an index by the Receive State Machine, up to a maximum value of */
|
||||
/* InputBufferSize. */
|
||||
unsigned Index;
|
||||
/* An array of octets, used to store octets as they are received. */
|
||||
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
|
||||
/* The maximum size of a frame is 501 octets. */
|
||||
uint8_t *InputBuffer;
|
||||
/* "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. */
|
||||
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. */
|
||||
uint8_t Poll_Station;
|
||||
/* A counter of transmission retries used for Token and Poll For Master */
|
||||
/* transmission. */
|
||||
unsigned RetryCount;
|
||||
/* A timer with nominal 5 millisecond resolution used to measure and */
|
||||
/* generate silence on the medium between octets. It is incremented by a */
|
||||
/* timer process and is cleared by the Receive State Machine when activity */
|
||||
/* is detected and by the SendFrame procedure as each octet is transmitted. */
|
||||
/* Since the timer resolution is limited and the timer is not necessarily */
|
||||
/* synchronized to other machine events, a timer value of N will actually */
|
||||
/* denote intervals between N-1 and N */
|
||||
uint16_t SilenceTimer;
|
||||
|
||||
/* A timer used to measure and generate Reply Postponed frames. It is */
|
||||
/* incremented by a timer process and is cleared by the Master Node State */
|
||||
/* Machine when a Data Expecting Reply Answer activity is completed. */
|
||||
/* note: we always send a reply postponed since a message other than
|
||||
the reply may be in the transmit queue */
|
||||
/* uint16_t ReplyPostponedTimer; */
|
||||
|
||||
/* Used to store the Source Address of a received frame. */
|
||||
uint8_t SourceAddress;
|
||||
|
||||
/* 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. */
|
||||
unsigned TokenCount;
|
||||
|
||||
/* "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. */
|
||||
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. */
|
||||
unsigned 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. */
|
||||
unsigned Nmax_master;
|
||||
|
||||
/* An array of octets, used to store PDU octets prior to being transmitted. */
|
||||
/* This array is only used for APDU messages */
|
||||
uint8_t TxBuffer[MAX_MPDU];
|
||||
unsigned TxLength;
|
||||
uint8_t TxDestination;
|
||||
bool TxReady; /* true if ready to be sent or received */
|
||||
uint8_t TxFrameType; /* type of message - needed by MS/TP */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void MSTP_Init(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
bool MSTP_Master_Node_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
|
||||
/* returns true if line is active */
|
||||
bool MSTP_Line_Active(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
unsigned MSTP_Create_Frame(
|
||||
uint8_t * buffer, /* where frame is loaded */
|
||||
unsigned buffer_len, /* amount of space available */
|
||||
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 */
|
||||
unsigned data_len); /* number of bytes of data (up to 501) */
|
||||
|
||||
|
||||
#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 MSTP_H
|
||||
#define MSTP_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "bacdef.h"
|
||||
#include "mstpdef.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
struct mstp_port_struct_t {
|
||||
MSTP_RECEIVE_STATE receive_state;
|
||||
/* When a master node is powered up or reset, */
|
||||
/* it shall unconditionally enter the INITIALIZE state. */
|
||||
MSTP_MASTER_STATE master_state;
|
||||
/* A Boolean flag set to TRUE by the Receive State Machine */
|
||||
/* if an error is detected during the reception of a frame. */
|
||||
/* Set to FALSE by the main state machine. */
|
||||
unsigned ReceiveError:1;
|
||||
/* There is data in the buffer */
|
||||
unsigned DataAvailable:1;
|
||||
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;
|
||||
/* stores the latest received data */
|
||||
uint8_t DataRegister;
|
||||
/* Used to accumulate the CRC on the data field of a frame. */
|
||||
uint16_t DataCRC;
|
||||
/* Used to store the data length of a received frame. */
|
||||
unsigned DataLength;
|
||||
/* Used to store the destination address of a received frame. */
|
||||
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 */
|
||||
uint8_t EventCount;
|
||||
/* Used to store the frame type of a received frame. */
|
||||
uint8_t FrameType;
|
||||
/* 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. */
|
||||
unsigned FrameCount;
|
||||
/* Used to accumulate the CRC on the header of a frame. */
|
||||
uint8_t HeaderCRC;
|
||||
/* Used as an index by the Receive State Machine, up to a maximum value of */
|
||||
/* InputBufferSize. */
|
||||
unsigned Index;
|
||||
/* An array of octets, used to store octets as they are received. */
|
||||
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
|
||||
/* The maximum size of a frame is 501 octets. */
|
||||
uint8_t *InputBuffer;
|
||||
/* "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. */
|
||||
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. */
|
||||
uint8_t Poll_Station;
|
||||
/* A counter of transmission retries used for Token and Poll For Master */
|
||||
/* transmission. */
|
||||
unsigned RetryCount;
|
||||
/* A timer with nominal 5 millisecond resolution used to measure and */
|
||||
/* generate silence on the medium between octets. It is incremented by a */
|
||||
/* timer process and is cleared by the Receive State Machine when activity */
|
||||
/* is detected and by the SendFrame procedure as each octet is transmitted. */
|
||||
/* Since the timer resolution is limited and the timer is not necessarily */
|
||||
/* synchronized to other machine events, a timer value of N will actually */
|
||||
/* denote intervals between N-1 and N */
|
||||
uint16_t SilenceTimer;
|
||||
|
||||
/* A timer used to measure and generate Reply Postponed frames. It is */
|
||||
/* incremented by a timer process and is cleared by the Master Node State */
|
||||
/* Machine when a Data Expecting Reply Answer activity is completed. */
|
||||
/* note: we always send a reply postponed since a message other than
|
||||
the reply may be in the transmit queue */
|
||||
/* uint16_t ReplyPostponedTimer; */
|
||||
|
||||
/* Used to store the Source Address of a received frame. */
|
||||
uint8_t SourceAddress;
|
||||
|
||||
/* 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. */
|
||||
unsigned TokenCount;
|
||||
|
||||
/* "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. */
|
||||
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. */
|
||||
unsigned 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. */
|
||||
unsigned Nmax_master;
|
||||
|
||||
/* An array of octets, used to store PDU octets prior to being transmitted. */
|
||||
/* This array is only used for APDU messages */
|
||||
uint8_t TxBuffer[MAX_MPDU];
|
||||
unsigned TxLength;
|
||||
uint8_t TxDestination;
|
||||
bool TxReady; /* true if ready to be sent or received */
|
||||
uint8_t TxFrameType; /* type of message - needed by MS/TP */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void MSTP_Init(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
void MSTP_Receive_Frame_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
bool MSTP_Master_Node_FSM(
|
||||
volatile struct mstp_port_struct_t
|
||||
*mstp_port);
|
||||
|
||||
/* returns true if line is active */
|
||||
bool MSTP_Line_Active(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
|
||||
unsigned MSTP_Create_Frame(
|
||||
uint8_t * buffer, /* where frame is loaded */
|
||||
unsigned buffer_len, /* amount of space available */
|
||||
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 */
|
||||
unsigned data_len); /* number of bytes of data (up to 501) */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
BACnet Stack - SourceForge.net
|
||||
Build for MPLAB IDE
|
||||
|
||||
These are some settings that are important when building
|
||||
the BACnet Stack using MPLAB IDE and MCC18 Compiler,
|
||||
|
||||
1. Add the files to the project that you need:
|
||||
abort.c, apdu.c, bacapp.c, bacdcode.c, bacerror.c,
|
||||
bacstr.c, crc.c, datetime.c, dcc.c, iam.c,
|
||||
npdu.c, rd.c, reject.c, rp.c, whois.c, wp.c
|
||||
|
||||
From ports/picxx: isr.c, main.c, rs485.c, mstp.c, dlmstp.c
|
||||
|
||||
From demo/object/: device.c or dev_tiny.c
|
||||
objects as needed: ai.c, ao.c, etc.
|
||||
|
||||
From demo/handler/: txbuf.c, h_dcc.c, h_rd.c, h_rp.c or h_rp_tiny.c
|
||||
Additional handlers as needed: h_wp.c
|
||||
|
||||
2. Project->Options->Project
|
||||
|
||||
General Tab: Include Path:
|
||||
C:\code\bacnet-stack\;C:\code\bacnet-stack\demo\handler\;C:\code\bacnet-stack\demo\object\;C:\code\bacnet-stack\ports\pic18f6720\
|
||||
|
||||
MPLAB C18 Tab: Memory Model:
|
||||
Code: Large Code Model
|
||||
Data: Large Data Model
|
||||
Stack: Multi-bank Model
|
||||
|
||||
MPLAB C18 Tab: General: Macro Definitions:
|
||||
PRINT_ENABLED=0
|
||||
BACDL_MSTP=1
|
||||
TSM_ENABLED=0
|
||||
BIG_ENDIAN=0
|
||||
|
||||
3. The linker script must reserve some extra stack space.
|
||||
|
||||
//DATABANK NAME=gpr12 START=0xC00 END=0xCFF
|
||||
//DATABANK NAME=gpr13 START=0xD00 END=0xDFF
|
||||
DATABANK NAME=stackreg START=0xC00 END=0xDFF PROTECTED
|
||||
|
||||
//STACK SIZE=0x100 RAM=gpr13
|
||||
STACK SIZE=0x200 RAM=stackreg
|
||||
|
||||
BACnet Stack - SourceForge.net
|
||||
Build for MPLAB IDE
|
||||
|
||||
These are some settings that are important when building
|
||||
the BACnet Stack using MPLAB IDE and MCC18 Compiler,
|
||||
|
||||
1. Add the files to the project that you need:
|
||||
abort.c, apdu.c, bacapp.c, bacdcode.c, bacerror.c,
|
||||
bacstr.c, crc.c, datetime.c, dcc.c, iam.c,
|
||||
npdu.c, rd.c, reject.c, rp.c, whois.c, wp.c
|
||||
|
||||
From ports/picxx: isr.c, main.c, rs485.c, mstp.c, dlmstp.c
|
||||
|
||||
From demo/object/: device.c or dev_tiny.c
|
||||
objects as needed: ai.c, ao.c, etc.
|
||||
|
||||
From demo/handler/: txbuf.c, h_dcc.c, h_rd.c, h_rp.c or h_rp_tiny.c
|
||||
Additional handlers as needed: h_wp.c
|
||||
|
||||
2. Project->Options->Project
|
||||
|
||||
General Tab: Include Path:
|
||||
C:\code\bacnet-stack\;C:\code\bacnet-stack\demo\handler\;C:\code\bacnet-stack\demo\object\;C:\code\bacnet-stack\ports\pic18f6720\
|
||||
|
||||
MPLAB C18 Tab: Memory Model:
|
||||
Code: Large Code Model
|
||||
Data: Large Data Model
|
||||
Stack: Multi-bank Model
|
||||
|
||||
MPLAB C18 Tab: General: Macro Definitions:
|
||||
PRINT_ENABLED=0
|
||||
BACDL_MSTP=1
|
||||
TSM_ENABLED=0
|
||||
BIG_ENDIAN=0
|
||||
|
||||
3. The linker script must reserve some extra stack space.
|
||||
|
||||
//DATABANK NAME=gpr12 START=0xC00 END=0xCFF
|
||||
//DATABANK NAME=gpr13 START=0xD00 END=0xDFF
|
||||
DATABANK NAME=stackreg START=0xC00 END=0xDFF PROTECTED
|
||||
|
||||
//STACK SIZE=0x100 RAM=gpr13
|
||||
STACK SIZE=0x200 RAM=stackreg
|
||||
|
||||
|
||||
@@ -1,353 +1,353 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* The module handles sending data out the RS-485 port */
|
||||
/* and handles receiving data from the RS-485 port. */
|
||||
/* Customize this file for your specific hardware */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "hardware.h"
|
||||
#include "mstp.h"
|
||||
#include "rs485.h"
|
||||
#include "fifo.h"
|
||||
|
||||
/* public port info */
|
||||
extern volatile struct mstp_port_struct_t MSTP_Port;
|
||||
|
||||
/* the baud rate is adjustable */
|
||||
uint32_t RS485_Baud_Rate = 38400;
|
||||
|
||||
/* the FIFO structures for sending and receiving */
|
||||
FIFO_BUFFER FIFO_Rx;
|
||||
FIFO_BUFFER FIFO_Tx;
|
||||
#pragma udata MSTPPortData
|
||||
/* the buffer for receiving data (size must be a power of 2) */
|
||||
volatile uint8_t RS485_Rx_Buffer[128];
|
||||
/* the buffer for sending data (size must be a power of 2) */
|
||||
volatile uint8_t RS485_Tx_Buffer[128];
|
||||
#pragma udata
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Transmits a frame using the UART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
uint16_t i = 0; /* loop counter */
|
||||
uint8_t turnaround_time;
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
while (!FIFO_Empty(&FIFO_Tx)) {
|
||||
/* buffer is not empty. Wait for ISR to transmit. */
|
||||
};
|
||||
|
||||
/* wait 40 bit times since reception */
|
||||
if (RS485_Baud_Rate == 9600)
|
||||
turnaround_time = 4;
|
||||
else if (RS485_Baud_Rate == 19200)
|
||||
turnaround_time = 2;
|
||||
else
|
||||
turnaround_time = 2;
|
||||
|
||||
while (mstp_port->SilenceTimer < turnaround_time) {
|
||||
/* The line has not been silent long enough, so wait. */
|
||||
};
|
||||
|
||||
if (FIFO_Add(&FIFO_Tx, buffer, nbytes)) {
|
||||
/* disable the receiver */
|
||||
PIE3bits.RC2IE = 0;
|
||||
RCSTA2bits.CREN = 0;
|
||||
/* enable the transceiver */
|
||||
RS485_TX_ENABLE = 1;
|
||||
RS485_RX_DISABLE = 1;
|
||||
/* enable the transmitter */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
PIE3bits.TX2IE = 1;
|
||||
/* reset the silence timer per MSTP spec, sort of */
|
||||
mstp_port->SilenceTimer = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Checks for data on the receive UART, and handles errors
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t * mstp_port)
|
||||
{
|
||||
/* check for data */
|
||||
if (!FIFO_Empty(&FIFO_Rx)) {
|
||||
mstp_port->DataRegister = FIFO_Get(&FIFO_Rx);
|
||||
mstp_port->DataAvailable = TRUE;
|
||||
}
|
||||
|
||||
return (!FIFO_Empty(&FIFO_Rx));
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Receives RS485 data stream
|
||||
|
||||
RETURN: none
|
||||
|
||||
ALGORITHM: none
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Rx(
|
||||
void)
|
||||
{
|
||||
uint8_t data_byte;
|
||||
|
||||
if ((RCSTA2bits.FERR) || (RCSTA2bits.OERR)) {
|
||||
/* Clear the error */
|
||||
RCSTA2bits.CREN = 0;
|
||||
RCSTA2bits.CREN = 1;
|
||||
/* FIXME: flag the MS/TP state machine on buffer overrun */
|
||||
data_byte = RCREG2;
|
||||
} else {
|
||||
data_byte = RCREG2;
|
||||
FIFO_Put(&FIFO_Rx, data_byte);
|
||||
}
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Transmits a byte using the UART out the RS485 port
|
||||
|
||||
RETURN: none
|
||||
|
||||
ALGORITHM: none
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Tx(
|
||||
void)
|
||||
{
|
||||
if (!FIFO_Empty(&FIFO_Tx)) {
|
||||
TXREG2 = FIFO_Get(&FIFO_Tx);
|
||||
} else {
|
||||
/* wait for the USART to be empty */
|
||||
while (!TXSTA2bits.TRMT);
|
||||
/* disable this interrupt */
|
||||
PIE3bits.TX2IE = 0;
|
||||
/* enable the receiver */
|
||||
RS485_TX_ENABLE = 0;
|
||||
RS485_RX_DISABLE = 0;
|
||||
/* enable the this interrupt */
|
||||
PIE3bits.RC2IE = 1;
|
||||
RCSTA2bits.CREN = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Returns the baud rate that we are currently running at
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Baud_Rate;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Sets the baud rate for the chip USART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 76800:
|
||||
case 115200:
|
||||
RS485_Baud_Rate = baud;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
/* FIXME: store the baud rate */
|
||||
/* I2C_Write_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&RS485_Baud_Rate,
|
||||
sizeof(RS485_Baud_Rate),
|
||||
EEPROM_MSTP_BAUD_RATE_ADDR); */
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in
|
||||
* receive mode.
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize_Port(
|
||||
void)
|
||||
{
|
||||
|
||||
/* Reset USART registers to POR state */
|
||||
TXSTA2 = 0;
|
||||
RCSTA2 = 0;
|
||||
/* configure USART for receiving */
|
||||
/* since the TX will handle setting up for transmit */
|
||||
RCSTA2bits.CREN = 1;
|
||||
/* Interrupt on receipt */
|
||||
PIE3bits.RC2IE = 1;
|
||||
/* enable the transmitter, disable its interrupt */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
PIE3bits.TX2IE = 0;
|
||||
/* setup USART Baud Rate Generator */
|
||||
/* see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book */
|
||||
/* Fosc=20MHz
|
||||
BRGH=1 BRGH=0
|
||||
Rate SPBRG Rate SPBRG
|
||||
------- ----- ------- -----
|
||||
9615 129 9469 32
|
||||
19230 64 19530 15
|
||||
37878 32 78130 3
|
||||
56818 21 104200 2
|
||||
113630 10 312500 0
|
||||
250000 4
|
||||
625000 1
|
||||
1250000 0
|
||||
*/
|
||||
switch (RS485_Baud_Rate) {
|
||||
case 19200:
|
||||
SPBRG2 = 64;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 38400:
|
||||
SPBRG2 = 32;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 57600:
|
||||
SPBRG2 = 21;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 76800:
|
||||
SPBRG2 = 3;
|
||||
TXSTA2bits.BRGH = 0;
|
||||
break;
|
||||
case 115200:
|
||||
SPBRG2 = 10;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 9600:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
default:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
RS485_Set_Baud_Rate(9600);
|
||||
break;
|
||||
}
|
||||
/* select async mode */
|
||||
TXSTA2bits.SYNC = 0;
|
||||
/* enable transmitter */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
/* serial port enable */
|
||||
RCSTA2bits.SPEN = 1;
|
||||
/* since we are using RS485,
|
||||
we need to explicitly say
|
||||
transmit enable or not */
|
||||
RS485_RX_DISABLE = 0;
|
||||
RS485_TX_ENABLE = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Disables the RS485 hardware
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Disable_Port(
|
||||
void)
|
||||
{
|
||||
RCSTA2 &= 0x4F; /* Disable the receiver */
|
||||
TXSTA2bits.TXEN = 0; /* and transmitter */
|
||||
PIE3 &= 0xCF; /* Disable both interrupts */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Reinitializes the port
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the data and the port
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
/* Init the Rs485 buffers */
|
||||
FIFO_Init(&FIFO_Rx, RS485_Rx_Buffer, sizeof(RS485_Rx_Buffer));
|
||||
FIFO_Init(&FIFO_Tx, RS485_Tx_Buffer, sizeof(RS485_Tx_Buffer));
|
||||
|
||||
/* FIXME: read the stored baud rate */
|
||||
/* I2C_Read_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&RS485_Baud_Rate,
|
||||
sizeof(RS485_Baud_Rate),
|
||||
EEPROM_MSTP_BAUD_RATE_ADDR); */
|
||||
|
||||
RS485_Initialize_Port();
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* The module handles sending data out the RS-485 port */
|
||||
/* and handles receiving data from the RS-485 port. */
|
||||
/* Customize this file for your specific hardware */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "hardware.h"
|
||||
#include "mstp.h"
|
||||
#include "rs485.h"
|
||||
#include "fifo.h"
|
||||
|
||||
/* public port info */
|
||||
extern volatile struct mstp_port_struct_t MSTP_Port;
|
||||
|
||||
/* the baud rate is adjustable */
|
||||
uint32_t RS485_Baud_Rate = 38400;
|
||||
|
||||
/* the FIFO structures for sending and receiving */
|
||||
FIFO_BUFFER FIFO_Rx;
|
||||
FIFO_BUFFER FIFO_Tx;
|
||||
#pragma udata MSTPPortData
|
||||
/* the buffer for receiving data (size must be a power of 2) */
|
||||
volatile uint8_t RS485_Rx_Buffer[128];
|
||||
/* the buffer for sending data (size must be a power of 2) */
|
||||
volatile uint8_t RS485_Tx_Buffer[128];
|
||||
#pragma udata
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Transmits a frame using the UART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data (up to 501) */
|
||||
uint16_t i = 0; /* loop counter */
|
||||
uint8_t turnaround_time;
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
while (!FIFO_Empty(&FIFO_Tx)) {
|
||||
/* buffer is not empty. Wait for ISR to transmit. */
|
||||
};
|
||||
|
||||
/* wait 40 bit times since reception */
|
||||
if (RS485_Baud_Rate == 9600)
|
||||
turnaround_time = 4;
|
||||
else if (RS485_Baud_Rate == 19200)
|
||||
turnaround_time = 2;
|
||||
else
|
||||
turnaround_time = 2;
|
||||
|
||||
while (mstp_port->SilenceTimer < turnaround_time) {
|
||||
/* The line has not been silent long enough, so wait. */
|
||||
};
|
||||
|
||||
if (FIFO_Add(&FIFO_Tx, buffer, nbytes)) {
|
||||
/* disable the receiver */
|
||||
PIE3bits.RC2IE = 0;
|
||||
RCSTA2bits.CREN = 0;
|
||||
/* enable the transceiver */
|
||||
RS485_TX_ENABLE = 1;
|
||||
RS485_RX_DISABLE = 1;
|
||||
/* enable the transmitter */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
PIE3bits.TX2IE = 1;
|
||||
/* reset the silence timer per MSTP spec, sort of */
|
||||
mstp_port->SilenceTimer = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Checks for data on the receive UART, and handles errors
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t * mstp_port)
|
||||
{
|
||||
/* check for data */
|
||||
if (!FIFO_Empty(&FIFO_Rx)) {
|
||||
mstp_port->DataRegister = FIFO_Get(&FIFO_Rx);
|
||||
mstp_port->DataAvailable = TRUE;
|
||||
}
|
||||
|
||||
return (!FIFO_Empty(&FIFO_Rx));
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Receives RS485 data stream
|
||||
|
||||
RETURN: none
|
||||
|
||||
ALGORITHM: none
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Rx(
|
||||
void)
|
||||
{
|
||||
uint8_t data_byte;
|
||||
|
||||
if ((RCSTA2bits.FERR) || (RCSTA2bits.OERR)) {
|
||||
/* Clear the error */
|
||||
RCSTA2bits.CREN = 0;
|
||||
RCSTA2bits.CREN = 1;
|
||||
/* FIXME: flag the MS/TP state machine on buffer overrun */
|
||||
data_byte = RCREG2;
|
||||
} else {
|
||||
data_byte = RCREG2;
|
||||
FIFO_Put(&FIFO_Rx, data_byte);
|
||||
}
|
||||
}
|
||||
|
||||
/* *************************************************************************
|
||||
DESCRIPTION: Transmits a byte using the UART out the RS485 port
|
||||
|
||||
RETURN: none
|
||||
|
||||
ALGORITHM: none
|
||||
|
||||
NOTES: none
|
||||
*************************************************************************** */
|
||||
void RS485_Interrupt_Tx(
|
||||
void)
|
||||
{
|
||||
if (!FIFO_Empty(&FIFO_Tx)) {
|
||||
TXREG2 = FIFO_Get(&FIFO_Tx);
|
||||
} else {
|
||||
/* wait for the USART to be empty */
|
||||
while (!TXSTA2bits.TRMT);
|
||||
/* disable this interrupt */
|
||||
PIE3bits.TX2IE = 0;
|
||||
/* enable the receiver */
|
||||
RS485_TX_ENABLE = 0;
|
||||
RS485_RX_DISABLE = 0;
|
||||
/* enable the this interrupt */
|
||||
PIE3bits.RC2IE = 1;
|
||||
RCSTA2bits.CREN = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Returns the baud rate that we are currently running at
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Baud_Rate;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Sets the baud rate for the chip USART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 76800:
|
||||
case 115200:
|
||||
RS485_Baud_Rate = baud;
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
/* FIXME: store the baud rate */
|
||||
/* I2C_Write_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&RS485_Baud_Rate,
|
||||
sizeof(RS485_Baud_Rate),
|
||||
EEPROM_MSTP_BAUD_RATE_ADDR); */
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in
|
||||
* receive mode.
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize_Port(
|
||||
void)
|
||||
{
|
||||
|
||||
/* Reset USART registers to POR state */
|
||||
TXSTA2 = 0;
|
||||
RCSTA2 = 0;
|
||||
/* configure USART for receiving */
|
||||
/* since the TX will handle setting up for transmit */
|
||||
RCSTA2bits.CREN = 1;
|
||||
/* Interrupt on receipt */
|
||||
PIE3bits.RC2IE = 1;
|
||||
/* enable the transmitter, disable its interrupt */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
PIE3bits.TX2IE = 0;
|
||||
/* setup USART Baud Rate Generator */
|
||||
/* see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book */
|
||||
/* Fosc=20MHz
|
||||
BRGH=1 BRGH=0
|
||||
Rate SPBRG Rate SPBRG
|
||||
------- ----- ------- -----
|
||||
9615 129 9469 32
|
||||
19230 64 19530 15
|
||||
37878 32 78130 3
|
||||
56818 21 104200 2
|
||||
113630 10 312500 0
|
||||
250000 4
|
||||
625000 1
|
||||
1250000 0
|
||||
*/
|
||||
switch (RS485_Baud_Rate) {
|
||||
case 19200:
|
||||
SPBRG2 = 64;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 38400:
|
||||
SPBRG2 = 32;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 57600:
|
||||
SPBRG2 = 21;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 76800:
|
||||
SPBRG2 = 3;
|
||||
TXSTA2bits.BRGH = 0;
|
||||
break;
|
||||
case 115200:
|
||||
SPBRG2 = 10;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
case 9600:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
break;
|
||||
default:
|
||||
SPBRG2 = 129;
|
||||
TXSTA2bits.BRGH = 1;
|
||||
RS485_Set_Baud_Rate(9600);
|
||||
break;
|
||||
}
|
||||
/* select async mode */
|
||||
TXSTA2bits.SYNC = 0;
|
||||
/* enable transmitter */
|
||||
TXSTA2bits.TXEN = 1;
|
||||
/* serial port enable */
|
||||
RCSTA2bits.SPEN = 1;
|
||||
/* since we are using RS485,
|
||||
we need to explicitly say
|
||||
transmit enable or not */
|
||||
RS485_RX_DISABLE = 0;
|
||||
RS485_TX_ENABLE = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Disables the RS485 hardware
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Disable_Port(
|
||||
void)
|
||||
{
|
||||
RCSTA2 &= 0x4F; /* Disable the receiver */
|
||||
TXSTA2bits.TXEN = 0; /* and transmitter */
|
||||
PIE3 &= 0xCF; /* Disable both interrupts */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Reinitializes the port
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Reinit(
|
||||
void)
|
||||
{
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the data and the port
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
/* Init the Rs485 buffers */
|
||||
FIFO_Init(&FIFO_Rx, RS485_Rx_Buffer, sizeof(RS485_Rx_Buffer));
|
||||
FIFO_Init(&FIFO_Tx, RS485_Tx_Buffer, sizeof(RS485_Tx_Buffer));
|
||||
|
||||
/* FIXME: read the stored baud rate */
|
||||
/* I2C_Read_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&RS485_Baud_Rate,
|
||||
sizeof(RS485_Baud_Rate),
|
||||
EEPROM_MSTP_BAUD_RATE_ADDR); */
|
||||
|
||||
RS485_Initialize_Port();
|
||||
}
|
||||
|
||||
@@ -1,80 +1,80 @@
|
||||
/*####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 <stdint.h>
|
||||
#include "mstp.h"
|
||||
|
||||
extern uint32_t RS485_Baud_Rate;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Reinit(
|
||||
void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Disable(
|
||||
void);
|
||||
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
/* returns true if there is more data waiting */
|
||||
bool RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
|
||||
void RS485_Interrupt_Rx(
|
||||
void);
|
||||
|
||||
void RS485_Interrupt_Tx(
|
||||
void);
|
||||
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
#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 <stdint.h>
|
||||
#include "mstp.h"
|
||||
|
||||
extern uint32_t RS485_Baud_Rate;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Reinit(
|
||||
void);
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Disable(
|
||||
void);
|
||||
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
/* returns true if there is more data waiting */
|
||||
bool RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
|
||||
void RS485_Interrupt_Rx(
|
||||
void);
|
||||
|
||||
void RS485_Interrupt_Tx(
|
||||
void);
|
||||
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef char _Bool;
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef char _Bool;
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
/* Defines the standard integer types that are used in code */
|
||||
|
||||
#ifndef STDINT_H
|
||||
#define STDINT_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t; /* 1 byte 0 to 255 */
|
||||
typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */
|
||||
typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
/* Defines the standard integer types that are used in code */
|
||||
|
||||
#ifndef STDINT_H
|
||||
#define STDINT_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t; /* 1 byte 0 to 255 */
|
||||
typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */
|
||||
typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
|
||||
Reference in New Issue
Block a user