adjust root folder

This commit is contained in:
Steve Karg
2019-10-08 23:47:53 -05:00
parent b6fc50ddea
commit a42e8f507c
1258 changed files with 26 additions and 214 deletions
+404
View File
@@ -0,0 +1,404 @@
###############################################################################
# Makefile for Project - AVR
###############################################################################
## General Flags
ifeq (${MCU},atmega1284p)
MCU = atmega1284p
AVRDUDE_MCU = m1284p
LINT_MCU = __AVR_ATmega1284p__
else
MCU = atmega644p
AVRDUDE_MCU = m644p
# ATmega644 bootload is at word address 7000h, 7800h, 7C00h, or 7E00h
# Double that value to get the byte address
BOOTLOAD = 0xF800
LINT_MCU = __AVR_ATmega644p__
endif
TARGET = bacnet
## Tools
CC = avr-gcc
AR = avr-ar
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AVRDUDE = avrdude
LINT = splint
SIZE_OPTIONS = -t
#SIZE_OPTIONS = -C --mcu=${MCU}
# programmer id--check the avrdude for complete list
# of available opts. These should include stk500,
# avr910, avrisp, bsd, pony and more. Set this to
# one of the valid "-c PROGRAMMER-ID" values
# described in the avrdude info page.
# jtag2fast = Atmel JTAG ICE mkII, running at 115200 Bd
# jtag2slow = Atmel JTAG ICE mkII, running at 19200 Bd
# avrispmkII = AVR ISP MKII
# avr109 = bootloader
ifeq (${JTAG},ftisp)
AVRDUDE_PROGRAMMERID = ftisp
endif
ifeq (${JTAG},avr109)
AVRDUDE_PROGRAMMERID = avr109
endif
ifeq (${JTAG},avrispmkII)
AVRDUDE_PROGRAMMERID = avrispmkII
endif
ifeq (${JTAG},dragon_isp)
AVRDUDE_PROGRAMMERID = dragon_isp
endif
ifeq (${JTAG},dragon_jtag)
AVRDUDE_PROGRAMMERID = dragon_jtag
endif
ifeq (${JTAG},jtag2fast)
AVRDUDE_PROGRAMMERID = jtag2fast
endif
ifndef JTAG
AVRDUDE_PROGRAMMERID = dragon_jtag
endif
#
# port--serial or parallel port to which your
# hardware programmer is attached
# usb can just be usb
AVRDUDE_PORT := usb
ifeq (${JTAG},ftisp)
AVRDUDE_PORT := /dev/ttyUSB0
endif
# Source locations
BACNET_CORE = ../../src
BACNET_INCLUDE = ../../include
BACNET_HANDLER = ../../demo/handler
BACNET_OBJECT = ../../demo/object
BACNET_DEMO = ../../demo
# local files for this project
CSRC = main.c \
fuses.c \
init.c \
stack.c \
adc.c \
input.c \
serial.c \
rs485.c \
timer2.c \
timer.c \
led.c \
eeprom.c \
seeprom.c \
watchdog.c \
dlmstp.c \
test.c \
bacnet.c \
bname.c \
device.c \
ai.c \
av.c \
bi.c \
bo.c
# common demo files needed
DEMOSRC = $(BACNET_DEMO)/handler/h_dcc.c \
$(BACNET_DEMO)/handler/h_npdu.c \
$(BACNET_DEMO)/handler/h_rd.c \
$(BACNET_DEMO)/handler/h_rp.c \
$(BACNET_DEMO)/handler/h_rpm.c \
$(BACNET_DEMO)/handler/h_whohas.c \
$(BACNET_DEMO)/handler/h_whois.c \
$(BACNET_DEMO)/handler/h_wp.c \
$(BACNET_DEMO)/handler/noserv.c \
$(BACNET_DEMO)/handler/s_iam.c \
$(BACNET_DEMO)/handler/s_ihave.c \
$(BACNET_DEMO)/handler/txbuf.c
# core BACnet stack files
CORESRC = \
$(BACNET_CORE)/abort.c \
$(BACNET_CORE)/apdu.c \
$(BACNET_CORE)/bacaddr.c \
$(BACNET_CORE)/bacapp.c \
$(BACNET_CORE)/bacdcode.c \
$(BACNET_CORE)/bacerror.c \
$(BACNET_CORE)/bacint.c \
$(BACNET_CORE)/bacreal.c \
$(BACNET_CORE)/bacstr.c \
$(BACNET_CORE)/crc.c \
$(BACNET_CORE)/dcc.c \
$(BACNET_CORE)/fifo.c \
$(BACNET_CORE)/iam.c \
$(BACNET_CORE)/ihave.c \
$(BACNET_CORE)/memcopy.c \
$(BACNET_CORE)/npdu.c \
$(BACNET_CORE)/rd.c \
$(BACNET_CORE)/reject.c \
$(BACNET_CORE)/ringbuf.c \
$(BACNET_CORE)/rp.c \
$(BACNET_CORE)/rpm.c \
$(BACNET_CORE)/whohas.c \
$(BACNET_CORE)/whois.c \
$(BACNET_CORE)/wp.c
# $(BACNET_CORE)/version.c
# $(BACNET_CORE)/bacprop.c \
# $(BACNET_CORE)/bactext.c \
# $(BACNET_CORE)/datetime.c \
# $(BACNET_CORE)/indtext.c \
# $(BACNET_CORE)/bigend.c \
# $(BACNET_CORE)/arf.c \
# $(BACNET_CORE)/awf.c \
# $(BACNET_CORE)/cov.c \
# $(BACNET_CORE)/iam/iam_client.c \
# $(BACNET_CORE)/ihave.c \
# $(BACNET_CORE)/timesync.c \
# $(BACNET_CORE)/whohas.c \
# $(BACNET_CORE)/filename.c \
# $(BACNET_CORE)/tsm.c \
# $(BACNET_CORE)/address.c \
## Include Directories
INCLUDES = -I. -I$(BACNET_INCLUDE) -I$(BACNET_HANDLER) -I$(BACNET_OBJECT)
# Source to Object conversion
COBJ = $(CSRC:%.c=%.o)
DEMOOBJ = $(DEMOSRC:.c=.o)
COREOBJ = $(CORESRC:.c=.o)
LIBRARY = lib$(TARGET).a
## Options common to compile, link and assembly rules
COMMON = -mmcu=$(MCU)
# define something from the Makefile or batch file
DEFINES =
# various SEEPROM sizes
ifeq (${SEEPROM},128)
DEFINES += -DSEEPROM_PAGE_SIZE=64
DEFINES += -DSEEPROM_WORD_ADDRESS_16BIT=1
endif
ifeq (${BDK_VERSION},3)
DEFINES += -DBDK_VERSION=3
endif
#ifdef
OPTIMIZE_FLAGS = -mcall-prologues
OPTIMIZE_FLAGS += -finline-functions-called-once
# default is for building from AVR Studio
OPTIMIZATION = -Os $(OPTIMIZE_FLAGS)
DEBUGGING = -g
ifeq (${BUILD},debug)
OPTIMIZATION = -O0
DEBUGGING = -g
endif
ifeq (${BUILD},release)
OPTIMIZATION = -Os $(OPTIMIZE_FLAGS)
DEBUGGING = -DNDEBUG
endif
ifeq (${BUILD},monitor)
OPTIMIZATION = -Os $(OPTIMIZE_FLAGS)
DEBUGGING = -DNDEBUG -DMSTP_MONITOR
endif
## BACnet options
BFLAGS = -DBACDL_MSTP
BFLAGS += -DMAX_APDU=128
BFLAGS += -DBIG_ENDIAN=0
BFLAGS += -DMAX_TSM_TRANSACTIONS=0
BFLAGS += -DMSTP_PDU_PACKET_COUNT=2
BFLAGS += -DMAX_CHARACTER_STRING_BYTES=64
BFLAGS += -DMAX_OCTET_STRING_BYTES=64
#BFLAGS += -DMAX_ANALOG_INPUTS=48
#BFLAGS += -DCRC_USE_TABLE
BFLAGS += -DBACAPP_BOOLEAN
BFLAGS += -DBACAPP_REAL
BFLAGS += -DBACAPP_OBJECT_ID
BFLAGS += -DBACAPP_UNSIGNED
BFLAGS += -DBACAPP_ENUMERATED
BFLAGS += -DBACAPP_CHARACTER_STRING
BFLAGS += -DWRITE_PROPERTY
## Compile options for C files
CFLAGS = $(COMMON)
CFLAGS += $(DEFINES)
CFLAGS += $(DEBUGGING)
# dead code removal
CFLAGS += -ffunction-sections -fdata-sections
# General flags
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
# warnings
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wmissing-prototypes
# put it all together
CFLAGS += -gdwarf-2 $(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,-nostartfiles,-nostdlib
LDFLAGS += -Wl,--gc-sections,-static
ifneq (${MCU},atmega1284p)
LDFLAGS += -Wl,--section-start=.bootloader=$(BOOTLOAD)
endif
LDFLAGS += -Wl,-Map=$(TARGET).map
LDFLAGS += -Wl,-L.,-l$(TARGET)
## Intel Hex file production flags
HEX_FLASH_FLAGS = -R .eeprom -R .fuse -R .lock -R .signature
HEX_EEPROM_FLAGS = -j .eeprom
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings
HEX_FUSE_FLAGS = -j .fuse
HEX_FUSE_FLAGS += --change-section-lma .fuse=0 --no-change-warnings
AVRDUDE_FLAGS = -c $(AVRDUDE_PROGRAMMERID)
AVRDUDE_FLAGS += -p $(AVRDUDE_MCU)
AVRDUDE_FLAGS += -P $(AVRDUDE_PORT)
AVRDUDE_FLAGS += -B 8
# Fuse high byte (0=enable,1=disable):
# 0x93 = 1 0 0 1 0 0 1 1
# 0x17 = 0 0 0 1 0 0 1 1 - v1,v2 board
# 0x17 = 0 0 0 1 0 1 1 1 - default
# ^ ^ ^ ^ ^ \+/ ^
# | | | | | | |---- BOOTRST (Enable Bootloader Reset Vector)
# | | | | | +------- BOOTSZ 1..0 (Select Boot Size)
# | | | | | +------- [00=4k, 01=2k, 10=1k, 11=512]
# | | | | +---------- EESAVE (Enable preserve EEPROM on Chip Erase)
# | | | +-------------- WDTON (watchdog timer always on)
# | | +---------------- SPIEN (Enable Serial Program / Data Downloading)
# | +------------------ JTAGEN (Enable JTAG)
# +-------------------- OCDEN (Enable OCD)
#
# Fuse low byte (0=enable,1=disable):
# 0xD7 = 1 1 0 1 0 1 1 1 - v3 board
# 0xE6 = 1 1 1 0 0 1 1 0 - v1,v2 board
# 0x62 = 0 1 1 0 0 0 1 0 - default
# ^ ^ \+/ \--+--/
# | | | +------- CKSEL 3..0 (Select Clock Source)
# | | | +------- [1111-1000=Low Power Crystal Oscillator]
# | | | +------- [0111-0110=Full Swing Crystal Oscillator]
# | | | +------- [0101-0100=Low Frequency Crystal Oscillator]
# | | | +------- [0011=Internal 128kHz RC Oscillator]
# | | | +------- [0010=Calibrated Internal RC Oscillator]
# | | | +------- [0000=External Clock]
# | | +--------------- SUT 1..0 (Start up Time selection)
# | | +--------------- [CKSEL0=0:14CK+ 00=4.1ms,01=65ms,10=BOD,11=4.1ms]
# | | +--------------- [CKSEL0=1:14CK+ 00=65ms,01=BOD,10=4.1ms,11=65ms]
# | +------------------ CKOUT (clock output on CKOUT pin)
# +-------------------- CKDIV8 (divide clock by 8)
#
# Fuse extended byte (0=enable,1=disable):
# 0xFC = 1 1 1 1 1 1 0 0
# 0xFC = 1 1 1 1 1 1 1 1 - default
# ^ ^ ^ ^ ^ \-+-/
# | | | | | +------ BODLEVEL 2..0 (brownout trigger level)
# | | | | | +------ [100=4.3V, 101=2.7V, 110=1.8V, 111=disabled]
# | | | | +----------
# | | | +--------------
# | | +----------------
# | +------------------
# +--------------------
AVRDUDE_DEFAULT_FUSES = -U hfuse:w:0x17:m -U lfuse:w:0x62:m -U efuse:w:0xFF:m
AVRDUDE_WRITE_FUSES = -U hfuse:w:0x93:m -U lfuse:w:0xD7:m -U efuse:w:0xFC:m
AVRDUDE_WRITE_FUSES_V2 = -U hfuse:w:0x13:m -U lfuse:w:0xE6:m -U efuse:w:0xFC:m
AVRDUDE_BOOTL_FUSES = -U hfuse:w:0x92:m -U lfuse:w:0xD7:m -U efuse:w:0xFC:m
AVRDUDE_READ_FUSES = -U hfuse:r:-:h -U lfuse:r:-:h -U efuse:r:-:h
AVRDUDE_WRITE_FLASH = -e -U flash:w:$(TARGET).hex
AVRDUDE_INSTALL = $(AVRDUDE_WRITE_FLASH)
#AVRDUDE_INSTALL += $(AVRDUDE_WRITE_FUSES)
## Objects not in library that must be built in order to link
OBJECTS = $(COBJ) $(DEMOOBJ)
## Build
TARGET_ELF=$(TARGET).elf
all: $(LIBRARY) \
$(TARGET_ELF) \
$(TARGET).bin \
$(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) $< $@
%.bin: $(TARGET_ELF)
$(OBJCOPY) --output-target=binary $(HEX_FLASH_FLAGS) $< $@
%.eep: $(TARGET_ELF)
-$(OBJCOPY) $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0
%.lst: $(TARGET_ELF)
$(OBJDUMP) -h -S $< > $@
lib: $(LIBRARY)
$(LIBRARY): $(COREOBJ) Makefile
$(AR) rcs $@ $(COREOBJ)
$(OBJDUMP) --syms $@ > $(LIBRARY:.a=.lst)
%.o: %.c
$(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@
size: ${TARGET_ELF}
@echo
@${SIZE} ${SIZE_OPTIONS} ${TARGET_ELF}
lint:
$(LINT) -exportlocal -D$(LINT_MCU) $(BFLAGS) $(CSRC)
install: $(TARGET_ELF)
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_INSTALL)
writefuses:
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FUSES)
writefusesv2:
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FUSES_V2)
bootloadfuses:
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_BOOTL_FUSES)
defaultfuses:
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_DEFAULT_FUSES)
showfuses:
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_READ_FUSES)
bootloader:
make -C bootloader all
## Clean target
.PHONY: clean
clean:
-rm -rf $(OBJECTS) $(TARGET_ELF) dep/*
-rm -rf $(LIBRARY) $(COREOBJ) $(LIBRARY:.a=.lst)
-rm -rf $(TARGET).hex $(TARGET).eep $(TARGET).lst $(TARGET).map
## Other dependencies
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)
Binary file not shown.
+131
View File
@@ -0,0 +1,131 @@
/**************************************************************************
*
* Copyright (C) 2009 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 "hardware.h"
/* me */
#include "adc.h"
/* prescale select bits */
#if (F_CPU >> 1) < 1000000
#define ADPS_8BIT (1)
#define ADPS_10BIT (3)
#elif (F_CPU >> 2) < 1000000
#define ADPS_8BIT (2)
#define ADPS_10BIT (4)
#elif (F_CPU >> 3) < 1000000
#define ADPS_8BIT (3)
#define ADPS_10BIT (5)
#elif (F_CPU >> 4) < 1000000
#define ADPS_8BIT (4)
#define ADPS_10BIT (6)
#elif (F_CPU >> 5) < 1000000
#define ADPS_8BIT (5)
#define ADPS_10BIT (7)
#else
#error "ADC: F_CPU too large for accuracy."
#endif
/* ADMUX: channel bits 0..4
ADLAR = Left Adjust Result
REFSx = hardware setup: cap on AREF
*/
/* ADCSRA:
ADEN = Enable
ADSC = Start conversion
ADIF = Interrupt Flag
ADIE = Interrupt Enable
ADATE = Auto Trigger Enable
*/
void adc_enable(
uint8_t index)
{
index = index;
/* do nothing */
}
/**************************************************
* Description: Run a Analog to Digital conversion
* Returns: none
* Notes: none
**************************************************/
uint8_t adc_result_8bit(
uint8_t channel)
{ /* 0..7 = ADC0..ADC7, respectively */
uint8_t value = 0; /* return value */
while (ADCSRA & (1 << ADSC));
ADMUX = channel | (1 << ADLAR) | (0 << REFS1) | (1 << REFS0);
/* Delay needed for the stabilization of the ADC input voltage */
_delay_us(10);
/* Start the analog to digital conversion */
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIF) | ADPS_8BIT;
/* Wait for the analog to digital conversion to complete */
while ((ADCSRA & (1 << ADIF)) == 0);
value = ADCH;
return value;
}
/**************************************************
* Description: Run a Analog to Digital conversion
* Returns: none
* Notes: none
**************************************************/
uint16_t adc_result_10bit(
uint8_t channel)
{ /* 0..7 = ADC0..ADC7, respectively */
uint16_t value = 0; /* return value */
while (ADCSRA & (1 << ADSC));
ADMUX = channel | (0 << ADLAR) | (0 << REFS1) | (1 << REFS0);
/* Delay needed for the stabilization of the ADC input voltage */
_delay_us(10);
/* Start the analog to digital conversion */
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIF) | ADPS_10BIT;
/* Wait for the analog to digital conversion to complete */
while ((ADCSRA & (1 << ADIF)) == 0);
value = ADCL;
value |= (ADCH << 8);
return value;
}
/**************************************************
* Description: Initializes the Analog to Digital Converter
* Returns: none
* Notes: none
**************************************************/
void adc_init(
void)
{
/* configure ADC for Free Running Mode - ADTS = 000 */
/* AIN1 is applied to the negative input of the Analog Comparator - ACME */
BITMASK_CLEAR(ADCSRB, _BV(ACME) | _BV(ADTS2) | _BV(ADTS1) | _BV(ADTS0));
/* Digital input not needed on ADC0, so disable it to save power */
BIT_SET(DIDR0, ADC0D);
/* Clear the Power Reduction bit to enable ADC */
BIT_CLEAR(PRR, PRADC);
}
+171
View File
@@ -0,0 +1,171 @@
/**************************************************************************
*
* Copyright (C) 2009 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 "hardware.h"
/* me */
#include "adc.h"
/* prescale select bits */
#if (F_CPU >> 1) < 1000000
#define ADPS_8BIT (1)
#define ADPS_10BIT (3)
#elif (F_CPU >> 2) < 1000000
#define ADPS_8BIT (2)
#define ADPS_10BIT (4)
#elif (F_CPU >> 3) < 1000000
#define ADPS_8BIT (3)
#define ADPS_10BIT (5)
#elif (F_CPU >> 4) < 1000000
#define ADPS_8BIT (4)
#define ADPS_10BIT (6)
#elif (F_CPU >> 5) < 1000000
#define ADPS_8BIT (5)
#define ADPS_10BIT (7)
#else
#error "ADC: F_CPU too large for accuracy."
#endif
/* Array of ADC results */
#define ADC_CHANNELS_MAX 8
static volatile uint16_t Sample_Result[ADC_CHANNELS_MAX];
static volatile uint8_t Enabled_Channels;
ISR(ADC_vect)
{
uint8_t index;
uint8_t mask;
uint8_t channels;
uint16_t value = 0;
/* determine which conversion finished */
index = BITMASK_CHECK(ADMUX, ((1 << MUX2) | (1 << MUX1) | (1 << MUX0)));
/* read the results */
value = ADCL;
value |= (ADCH << 8);
Sample_Result[index] = value;
channels = Enabled_Channels;
__enable_interrupt();
/* clear the mux */
BITMASK_CLEAR(ADMUX, ((1 << MUX2) | (1 << MUX1) | (1 << MUX0)));
/* find the next enabled channel */
while (channels) {
index++;
if (index >= ADC_CHANNELS_MAX) {
index = 0;
}
mask = 1 << index;
if (channels & mask) {
break;
}
}
/* configure the next channel */
BITMASK_SET(ADMUX, ((index) << MUX0));
/* Start the next conversion */
BIT_SET(ADCSRA, ADSC);
}
void adc_enable(
uint8_t index)
{ /* 0..7 = ADC0..ADC7, respectively */
if (Enabled_Channels) {
/* ADC interupt is already started */
BIT_SET(Enabled_Channels, index);
} else {
if (index < ADC_CHANNELS_MAX) {
/* not running yet */
BIT_SET(Enabled_Channels, index);
/* clear the mux */
BITMASK_CLEAR(ADMUX, ((1 << MUX2) | (1 << MUX1) | (1 << MUX0)));
/* configure the channel */
BITMASK_SET(ADMUX, ((index) << MUX0));
/* Start the next conversion */
BIT_SET(ADCSRA, ADSC);
}
}
}
uint8_t adc_result_8bit(
uint8_t index)
{ /* 0..7 = ADC0..ADC7, respectively */
uint8_t result = 0;
uint8_t sreg;
if (index < ADC_CHANNELS_MAX) {
adc_enable(index);
sreg = SREG;
__disable_interrupt();
result = (uint8_t) (Sample_Result[index] >> 2);
SREG = sreg;
}
return result;
}
uint16_t adc_result_10bit(
uint8_t index)
{ /* 0..7 = ADC0..ADC7, respectively */
uint16_t result = 0;
uint8_t sreg;
if (index < ADC_CHANNELS_MAX) {
adc_enable(index);
sreg = SREG;
__disable_interrupt();
result = Sample_Result[index];
SREG = sreg;
}
return result;
}
void adc_init(
void)
{
/* Initial channel selection */
/* ADLAR = Left Adjust Result
REFSx = hardware setup: cap on AREF
*/
ADMUX = (0 << ADLAR) | (0 << REFS1) | (1 << REFS0);
/* ADEN = Enable
ADSC = Start conversion
ADIF = Interrupt Flag - write 1 to clear!
ADIE = Interrupt Enable
ADATE = Auto Trigger Enable
*/
ADCSRA =
(1 << ADEN) | (1 << ADIE) | (1 << ADIF) | (0 << ADATE) | ADPS_10BIT;
/* trigger selection bits
0 0 0 Free Running mode
0 0 1 Analog Comparator
0 1 0 External Interrupt Request 0
0 1 1 Timer/Counter0 Compare Match
1 0 0 Timer/Counter0 Overflow
1 0 1 Timer/Counter1 Compare Match B
1 1 0 Timer/Counter1 Overflow
1 1 1 Timer/Counter1 Capture Event
*/
ADCSRB = (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0);
power_adc_enable();
}
+45
View File
@@ -0,0 +1,45 @@
/**************************************************************************
*
* Copyright (C) 2009 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 ADC_H
#define ADC_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void adc_enable(
uint8_t index); /* 0..7 = ADC0..ADC7, respectively */
uint8_t adc_result_8bit(
uint8_t index); /* 0..7 = ADC0..ADC7, respectively */
uint16_t adc_result_10bit(
uint8_t index); /* 0..7 = ADC0..ADC7, respectively */
void adc_init(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+215
View File
@@ -0,0 +1,215 @@
/**************************************************************************
*
* 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 "ai.h"
#include "handlers.h"
#ifndef MAX_ANALOG_INPUTS
#define MAX_ANALOG_INPUTS 2
#endif
static float Present_Value[MAX_ANALOG_INPUTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Analog_Input_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_UNITS,
-1
};
static const int Analog_Input_Properties_Optional[] = {
-1
};
static const int Analog_Input_Properties_Proprietary[] = {
-1
};
void Analog_Input_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Analog_Input_Properties_Required;
if (pOptional)
*pOptional = Analog_Input_Properties_Optional;
if (pProprietary)
*pProprietary = Analog_Input_Properties_Proprietary;
return;
}
void Analog_Input_Init(
void)
{
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_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;
}
bool Analog_Input_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32]; /* okay for single thread */
bool status = false;
if (object_instance < MAX_ANALOG_INPUTS) {
sprintf(text_string, "AI-%lu", object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
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 already exists */
int Analog_Input_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0; /* return value */
BACNET_CHARACTER_STRING char_string = { 0 };
BACNET_BIT_STRING bit_string = { 0 };
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], rpdata->object_type,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Analog_Input_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], rpdata->object_type);
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 = BACNET_STATUS_ERROR;
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 = BACNET_STATUS_ERROR;
}
return apdu_len;
}
+431
View File
@@ -0,0 +1,431 @@
/**************************************************************************
*
* 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 "av.h"
#include "handlers.h"
#include "hardware.h"
#ifndef MAX_ANALOG_VALUES
#define MAX_ANALOG_VALUES 2
#endif
static float Present_Value[MAX_ANALOG_VALUES];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Analog_Value_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_UNITS,
-1
};
static const int Analog_Value_Properties_Optional[] = {
#if 0
PROP_PRIORITY_ARRAY,
PROP_RELINQUISH_DEFAULT,
#endif
-1
};
static const int Analog_Value_Properties_Proprietary[] = {
-1
};
void Analog_Value_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Analog_Value_Properties_Required;
if (pOptional)
*pOptional = Analog_Value_Properties_Optional;
if (pProprietary)
*pProprietary = Analog_Value_Properties_Proprietary;
return;
}
void Analog_Value_Init(
void)
{
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)
{
if (object_instance < MAX_ANALOG_VALUES)
return true;
return false;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then count how many you have */
unsigned Analog_Value_Count(
void)
{
return MAX_ANALOG_VALUES;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the instance */
/* that correlates to the correct index */
uint32_t Analog_Value_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. Yours might be */
/* more complex, and then you need to return the index */
/* that correlates to the correct instance number */
unsigned Analog_Value_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_ANALOG_VALUES;
if (object_instance < MAX_ANALOG_VALUES)
index = object_instance;
return index;
}
float Analog_Value_Present_Value(
uint32_t object_instance)
{
float value = 0;
unsigned index = 0;
index = Analog_Value_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_VALUES) {
value = Present_Value[index];
}
return value;
}
bool Analog_Value_Present_Value_Set(
uint32_t object_instance,
float value,
uint8_t priority)
{
unsigned index = 0;
bool status = false;
priority = priority;
index = Analog_Value_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_VALUES) {
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
(priority != 6 /* reserved */ ) &&
(value >= 0.0) && (value <= 100.0)) {
Present_Value[index] = value;
/* 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;
}
}
return status;
}
/* note: the object name must be unique within this device */
bool Analog_Value_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32] = ""; /* okay for single thread */
unsigned index = 0;
bool status = false;
index = Analog_Value_Instance_To_Index(object_instance);
if (index < MAX_ANALOG_VALUES) {
sprintf(text_string, "AV-%lu", object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or -1 on error */
int Analog_Value_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string;
float real_value = 1.414F;
BACNET_CHARACTER_STRING char_string = { 0 };
#if 0
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
#endif
uint8_t *apdu = NULL;
if ((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], rpdata->object_type,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Analog_Value_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], rpdata->object_type);
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(rpdata->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 (rpdata->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 (rpdata->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(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
if (Present_Value[object_index][rpdata->array_index - 1] ==
ANALOG_LEVEL_NULL)
apdu_len = encode_application_null(&apdu[0]);
else {
real_value =
Present_Value[object_index][rpdata->array_index -
1];
apdu_len =
encode_application_real(&apdu[0], real_value);
}
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->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
(rpdata->object_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 */
#if 0
unsigned int object_index = 0;
unsigned int priority = 0;
#endif
BACNET_APPLICATION_DATA_VALUE value;
int len = 0;
/* 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:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_REAL,
&wp_data->error_class, &wp_data->error_code);
if (status) {
status =
Analog_Value_Present_Value_Set(wp_data->object_instance,
value.type.Real, wp_data->priority);
if (!status) {
if (wp_data->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;
}
}
}
break;
case PROP_OUT_OF_SERVICE:
#if 0
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
object_index =
Analog_Value_Instance_To_Index(wp_data->object_instance);
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
}
break;
#endif
case PROP_UNITS:
#if 0
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_UNSIGNED_INT,
&wp_data->error_class, &wp_data->error_code);
if (status) {
object_index =
Analog_Value_Instance_To_Index(wp_data->object_instance);
Analog_Value_Units[object_index] = value.type.Unsigned_Int;
}
break;
#endif
case PROP_PRIORITY_ARRAY:
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_DESCRIPTION:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
case PROP_RELINQUISH_DEFAULT:
default:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
break;
}
/* not using len at this time */
len = len;
return status;
}
@@ -0,0 +1,976 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRBootloader.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing an interface to the AVR bootloader
* described in Application Note AVR109.
* This class is derived from AVRPRogrammer.
*
*
****************************************************************************/
#include "AVRBootloader.hpp"
#include <sstream>
#include <iomanip>
#define MEM_PROGRESS_GRANULARITY 256 // For use with progress indicator.
/* Constructor */
AVRBootloader::AVRBootloader( CommChannel * _comm ) :
AVRProgrammer::AVRProgrammer( _comm )
{
/* No code here */
}
/* Destructor */
AVRBootloader::~AVRBootloader()
{
/* No code here */
}
bool AVRBootloader::enterProgrammingMode()
{
return true; // Always OK for bootloader.
}
bool AVRBootloader::leaveProgrammingMode()
{
return true; // Always OK for bootloader.
}
bool AVRBootloader::chipErase()
{
/* Send command 'e' */
comm->sendByte( 'e' );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Chip erase failed! "
"Programmer did not return CR after 'e'-command." );
return true; // Indicate supported command.
}
bool AVRBootloader::readOSCCAL( long pos, long * value )
{
return false; // Indicate unsupported command.
}
bool AVRBootloader::readSignature( long * sig0, long * sig1, long * sig2 )
{
/* Send command 's' */
comm->sendByte( 's' );
comm->flushTX();
/* Get actual signature */
*sig2 = comm->getByte();
*sig1 = comm->getByte();
*sig0 = comm->getByte();
}
bool AVRBootloader::checkSignature( long sig0, long sig1, long sig2 )
{
long sig[3];
/* Get signature */
readSignature( sig, sig+1, sig+2 );
/* Compare signature */
if( sig[0] != sig0 || sig[1] != sig1 || sig[2] != sig2 )
{
ostringstream msg;
msg << "Signature does not match selected device! ";
msg << "Actual signature: (" << hex
<< "0x" << setw(2) << sig[0] << " "
<< "0x" << setw(2) << sig[1] << " "
<< "0x" << setw(2) << sig[2] << ") "
<< "Signature from XML-file: (" << hex
<< "0x" << setw(2) << sig0 << " "
<< "0x" << setw(2) << sig1 << " "
<< "0x" << setw(2) << sig2 << ").";
throw new ErrorMsg( msg.str() );
}
return true; // Indicate supported command.
}
bool AVRBootloader::writeFlashByte( long address, long value )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Move data if at odd address */
if( address & 0x01 ) // Odd address?
value = (value << 8) | 0x00ff; // Move to high byte of one flash word.
else
value |= 0xff00; // Ensure no-write for high byte.
/* Send low and high byte */
writeFlashLowByte( value & 0xff );
writeFlashHighByte( value >> 8 );
/* Issue page write */
setAddress( address >> 1 ); // The address could be autoincremented.
writeFlashPage();
return true; // Indicate supported command.
}
bool AVRBootloader::writeEEPROMByte( long address, long value )
{
if( address >= 0x10000 )
throw new ErrorMsg( "EEPROM addresses above 64k are currently not supported!" );
setAddress( address );
/* Send data */
comm->sendByte( 'D' );
comm->sendByte( value );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing byte to EEPROM failed! "
"Programmer did not return CR after 'D'-command." );
return true; // Indicate supported command.
}
bool AVRBootloader::writeFlash( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Check that pagesize is set */
if( pagesize == -1 )
throw new ErrorMsg( "Programmer pagesize is not set!" );
/* Check block write support */
comm->sendByte( 'b' );
comm->flushTX();
if( comm->getByte() == 'Y' )
{
Util.log( "Using block mode...\r\n" );
return writeFlashBlock( data ); // Finished writing.
}
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start >> 1 ); // Flash operations use word addresses.
/* Need to write one odd byte first? */
address = start;
if( address & 1 )
{
/* Use only high byte */
writeFlashLowByte( 0xff ); // No-write in low byte.
writeFlashHighByte( data->getData( address ) );
address++;
/* Need to write page? */
if( (address % pagesize) == 0 ||
address > end ) // Just passed page limit or no more bytes to write?
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
/* Write words */
while( (end-address+1) >= 2 ) // More words left?
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address >> 1 );
/* Write words */
writeFlashLowByte( data->getData( address ) );
writeFlashHighByte( data->getData( address+1 ) );
address += 2;
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
/* Need to write page? */
if( (address % pagesize) == 0 ||
address > end ) // Just passed a page limit or no more bytes to write?
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
/* Need to write one even byte before finished? */
if( address == end )
{
/* Use only low byte */
writeFlashLowByte( data->getData( address ) );
writeFlashHighByte( 0xff ); // No-write in high byte.
address+=2;
/* Write page */
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::writeFlashBlock( HEXFile * data )
{
long start, end; // Data address range.
long blocksize; // Bootloader block size.
long bytecount;
long address;
/* Get block size, assuming command 'b' just issued and 'Y' has been read */
blocksize = (comm->getByte() << 8) | comm->getByte();
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Need to write one odd byte first? */
address = start;
if( address & 1 )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Use only high byte */
writeFlashLowByte( 0xff ); // No-write in low byte.
writeFlashHighByte( data->getData( address ) );
address++;
/* Need to write page? */
if( (address % pagesize) == 0 ||
address > end ) // Just passed page limit or no more bytes to write?
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
/* Need to write from middle to end of block first? */
if( (address % blocksize) > 0 ) // In the middle of a block?
{
bytecount = blocksize - (address % blocksize); // Bytes left in block.
if( (address+bytecount-1) > end ) // Is that past the write range?
{
bytecount = end-address+1; // Bytes left in write range.
bytecount &= ~0x01; // Adjust to word count.
}
if( bytecount > 0 )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block write */
comm->sendByte( 'B' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
comm->sendByte( data->getData( address ) );
address++;
bytecount--;
}
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash block failed! "
"Programmer did not return CR after 'BxxF'-command." );
Util.progress( "#" ); // Advance progress indicator.
}
}
/* More complete blocks to write? */
while( (end-address+1) >= blocksize )
{
bytecount = blocksize;
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block write */
comm->sendByte( 'B' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
comm->sendByte( data->getData( address ) );
address++;
bytecount--;
}
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash block failed! "
"Programmer did not return CR after 'BxxF'-command." );
Util.progress( "#" ); // Advance progress indicator.
}
/* Any bytes left in last block */
if( (end-address+1) >= 1 )
{
bytecount = (end-address+1); // Get bytes left to write.
if( bytecount & 1 )
bytecount++; // Align to next word boundary.
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block write */
comm->sendByte( 'B' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
if( address > end )
comm->sendByte( 0xff ); // Don't write outside write range.
else
comm->sendByte( data->getData( address ) );
address++;
bytecount--;
}
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash block failed! "
"Programmer did not return CR after 'BxxF'-command." );
Util.progress( "#" ); // Advance progress indicator.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::readFlash( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
if( pagesize == -1 )
throw new ErrorMsg( "Programmer pagesize is not set!" );
/* Check block read support */
comm->sendByte( 'b' );
comm->flushTX();
if( comm->getByte() == 'Y' )
{
Util.log( "Using block mode...\r\n" );
return readFlashBlock( data ); // Finished writing.
}
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start >> 1 ); // Flash operations use word addresses.
/* Need to read one odd byte first? */
address = start;
if( address & 1 )
{
/* Read both, but use only high byte */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address, comm->getByte() ); // High byte.
comm->getByte(); // Dont use low byte.
address++;
}
/* Get words */
while( (end-address+1) >= 2 )
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address >> 1 );
/* Get words */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address+1, comm->getByte() ); // High byte.
data->setData( address, comm->getByte() ); // Low byte.
address += 2;
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
};
/* Need to read one even byte before finished? */
if( address == end )
{
/* Read both, but use only low byte */
comm->sendByte( 'R' );
comm->flushTX();
comm->getByte(); // Dont use high byte.
data->setData( address, comm->getByte() ); // Low byte.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::readFlashBlock( HEXFile * data )
{
long start, end; // Data address range.
long blocksize; // Bootloader block size.
long bytecount;
long address;
/* Get block size, assuming command 'b' just issued and 'Y' has been read */
blocksize = (comm->getByte() << 8) | comm->getByte();
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Need to read one odd byte first? */
address = start;
if( address & 1 )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Use only high word */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address, comm->getByte() ); // High byte.
comm->getByte(); // Low byte.
address++;
}
/* Need to read from middle to end of block first? */
if( (address % blocksize) > 0 ) // In the middle of a block?
{
bytecount = blocksize - (address % blocksize); // Bytes left in block.
if( (address+bytecount-1) > end ) // Is that past the read range?
{
bytecount = end-address+1; // Bytes left in read range.
bytecount &= ~0x01; // Adjust to word count.
}
if( bytecount > 0 )
{
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block read */
comm->sendByte( 'g' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
data->setData( address, comm->getByte() );
address++;
bytecount--;
}
Util.progress( "#" ); // Advance progress indicator.
}
}
/* More complete blocks to read? */
while( (end-address+1) >= blocksize )
{
bytecount = blocksize;
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block read */
comm->sendByte( 'g' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
data->setData( address, comm->getByte() );
address++;
bytecount--;
}
Util.progress( "#" ); // Advance progress indicator.
}
/* Any bytes left in last block */
if( (end-address+1) >= 1 )
{
bytecount = (end-address+1); // Get bytes left to read.
if( bytecount & 1 )
bytecount++; // Align to next word boundary.
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Start Flash block read */
comm->sendByte( 'g' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'F' ); // Flash memory.
while( bytecount > 0 )
{
if( address > end )
comm->getByte(); // Don't read outside write range.
else
data->setData( address, comm->getByte() );
address++;
bytecount--;
}
Util.progress( "#" ); // Advance progress indicator.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::writeEEPROM( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Check block write support */
comm->sendByte( 'b' );
comm->flushTX();
if( comm->getByte() == 'Y' )
{
Util.log( "Using block mode...\r\n" );
return writeEEPROMBlock( data ); // Finished writing.
}
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start );
/* Send data */
address = start;
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address );
/* Send byte */
comm->sendByte( 'D' );
comm->sendByte( data->getData( address ) );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing byte to EEPROM failed! "
"Programmer did not return CR after 'D'-command." );
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
address++;
} while( address <= end );
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::writeEEPROMBlock( HEXFile * data )
{
long start, end; // Data address range.
long blocksize; // Bootloader block size.
long bytecount;
long address;
/* Get block size, assuming command 'b' just issued and 'Y' has been read */
blocksize = (comm->getByte() << 8) | comm->getByte();
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Send data */
address = start;
while( address <= end ) // More bytes to write?
{
bytecount = blocksize; // Try a full block.
if( (address+bytecount-1) > end ) // Is that past the write range?
{
bytecount = end-address+1; // Bytes left in write range.
}
setAddress( address );
/* Start EEPROM block write */
comm->sendByte( 'B' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'E' ); // EEPROM memory.
while( bytecount > 0 )
{
comm->sendByte( data->getData( address ) );
comm->flushTX();
address++;
bytecount--;
}
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing EEPROM block failed! "
"Programmer did not return CR after 'BxxE'-command." );
Util.progress( "#" ); // Advance progress indicator.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::readEEPROM( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Check block write support */
comm->sendByte( 'b' );
comm->flushTX();
if( comm->getByte() == 'Y' )
{
Util.log( "Using block mode...\r\n" );
return readEEPROMBlock( data ); // Finished writing.
}
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start );
/* Read data */
address = start;
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address );
/* Get byte */
comm->sendByte( 'd' );
comm->flushTX();
data->setData( address, comm->getByte() );
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
address++;
} while( address <= end );
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::readEEPROMBlock( HEXFile * data )
{
long start, end; // Data address range.
long blocksize; // Bootloader block size.
long bytecount;
long address;
/* Get block size, assuming command 'b' just issued and 'Y' has been read */
blocksize = (comm->getByte() << 8) | comm->getByte();
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Read data */
address = start;
while( address <= end ) // More bytes to read?
{
bytecount = blocksize; // Try a full block.
if( (address+bytecount-1) > end ) // Is that past the read range?
{
bytecount = end-address+1; // Bytes left in read range.
}
setAddress( address );
/* Start EEPROM block read */
comm->sendByte( 'g' );
comm->sendByte( (bytecount>>8) & 0xff ); // Size, MSB first.
comm->sendByte( bytecount & 0xff );
comm->sendByte( 'E' ); // EEPROM memory.
while( bytecount > 0 )
{
data->setData( address, comm->getByte() );
address++;
bytecount--;
}
Util.progress( "#" ); // Advance progress indicator.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRBootloader::writeLockBits( long bits )
{
/* Send command 'l' */
comm->sendByte( 'l' );
comm->sendByte( bits & 0xff );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing lock bits failed! "
"Programmer did not return CR after 'l'-command." );
return true; // Indicate supported command.
}
bool AVRBootloader::readLockBits( long * bits )
{
/* Send command 'r' */
comm->sendByte( 'r' );
comm->flushTX();
/* Get data */
*bits = comm->getByte();
return true; // Indicate supported command.
}
bool AVRBootloader::writeFuseBits( long bits )
{
return false; // Indicate unsupported command.
}
bool AVRBootloader::readFuseBits( long * bits )
{
long lowfuse, highfuse;
/* Send command 'N' */
comm->sendByte( 'N' );
comm->flushTX();
/* Get high fuse bits */
highfuse = comm->getByte();
/* Send command 'F' */
comm->sendByte( 'F' );
comm->flushTX();
/* Get low fuse bits */
lowfuse = comm->getByte();
*bits = (highfuse << 8) | lowfuse;
return true; // Indicate supported command.
}
bool AVRBootloader::writeExtendedFuseBits( long bits )
{
return false; // Indicate unsupported command.
}
bool AVRBootloader::readExtendedFuseBits( long * bits )
{
/* Send command 'Q' */
comm->sendByte( 'Q' );
comm->flushTX();
/* Get data */
*bits = comm->getByte();
return true; // Indicate supported command.
}
bool AVRBootloader::programmerSoftwareVersion( long * major, long * minor )
{
/* Send command 'V' to get software version */
comm->sendByte( 'V' );
comm->flushTX();
/* Get data */
*major = comm->getByte();
*minor = comm->getByte();
return true; // Indicate supported command.
}
bool AVRBootloader::programmerHardwareVersion( long * major, long * minor )
{
return false; // Indicate unsupported command.
}
void AVRBootloader::setAddress( long address )
{
/* Set current address */
if( address < 0x10000 ) {
comm->sendByte( 'A' );
comm->sendByte( (address >> 8) & 0xff );
comm->sendByte( address & 0xff );
comm->flushTX();
} else {
comm->sendByte( 'H' );
comm->sendByte( (address >> 16) & 0xff );
comm->sendByte( (address >> 8) & 0xff );
comm->sendByte( address & 0xff );
comm->flushTX();
}
/* Should return CR */
if( comm->getByte() != '\r' ) {
throw new ErrorMsg( "Setting address for programming operations failed! "
"Programmer did not return CR after 'A'-command." );
}
}
void AVRBootloader::writeFlashLowByte( long value )
{
comm->sendByte( 'c' );
comm->sendByte( value );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash low byte failed! "
"Programmer did not return CR after 'c'-command." );
}
void AVRBootloader::writeFlashHighByte( long value )
{
comm->sendByte( 'C' );
comm->sendByte( value );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash high byte failed! "
"Programmer did not return CR after 'C'-command." );
}
void AVRBootloader::writeFlashPage()
{
comm->sendByte( 'm' );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash page failed! "
"Programmer did not return CR after 'm'-command." );
}
/* end of file */
@@ -0,0 +1,84 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRBootloader.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing an interface to the AVR bootloader
* described in Application Note AVR109.
* This class is derived from AVRPRogrammer.
*
*
****************************************************************************/
#ifndef AVRBOOTLOADER_HPP
#define AVRBOOTLOADER_HPP
using namespace std;
#include "AVRProgrammer.hpp"
#include "Utility.hpp"
class AVRBootloader : public AVRProgrammer
{
protected:
virtual void setAddress( long address );
virtual void writeFlashLowByte( long value ); // Alwyas low byte first...
virtual void writeFlashHighByte( long value ); // ...then high byte.
virtual void writeFlashPage();
virtual bool writeFlashBlock( HEXFile * data );
virtual bool readFlashBlock( HEXFile * data );
virtual bool writeEEPROMBlock( HEXFile * data );
virtual bool readEEPROMBlock( HEXFile * data );
public:
/* Constructor */
AVRBootloader( CommChannel * _comm );
/* Destructor */
~AVRBootloader();
/* Methods */
virtual bool enterProgrammingMode();
virtual bool leaveProgrammingMode();
virtual bool chipErase();
virtual bool readOSCCAL( long pos, long * value );
virtual bool readSignature( long * sig0, long * sig1, long * sig2 );
virtual bool checkSignature( long sig0, long sig1, long sig2 );
virtual bool writeFlashByte( long address, long value );
virtual bool writeEEPROMByte( long address, long value );
virtual bool writeFlash( HEXFile * data );
virtual bool readFlash( HEXFile * data );
virtual bool writeEEPROM( HEXFile * data );
virtual bool readEEPROM( HEXFile * data );
virtual bool writeLockBits( long bits );
virtual bool readLockBits( long * bits );
virtual bool writeFuseBits( long bits );
virtual bool readFuseBits( long * bits );
virtual bool writeExtendedFuseBits( long bits );
virtual bool readExtendedFuseBits( long * bits );
virtual bool programmerSoftwareVersion( long * major, long * minor );
virtual bool programmerHardwareVersion( long * major, long * minor );
};
#endif
+157
View File
@@ -0,0 +1,157 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRDevice.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 4017 $
* Date : $Date: 2008-06-02 14:26:03 +0200 (ma, 02 jun 2008) $
* Updated by : $Author: khole $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class containing information of device memory sizes etc.
* It also provides funcitons for reading these parameters from
* the PartDescriptionFiles supplied with AVR Studio 4.
*
*
****************************************************************************/
#include "AVRDevice.hpp"
/* Constructor */
AVRDevice::AVRDevice( const string & _deviceName ) :
deviceName( _deviceName )
{
flashSize =
eepromSize = 0;
hasFuseBits = false;
hasExtendedFuseBits = false;
signature0 =
signature1 =
signature2 = 0;
pagesize = -1;
}
/* Destructor */
AVRDevice::~AVRDevice()
{
/* no code here */
}
/* Read parameters from AVR Studio XML files */
void AVRDevice::readParametersFromAVRStudio( vector<string> & searchpath )
{
string path;
string signature;
string cache;
#ifndef NOREGISTRY
/* Locate the directory containing the XML files from the Windows registry database */
try
{
path = Util.getRegistryValue( "SOFTWARE\\Atmel\\AVRTools\\", "AVRToolsPath" );
path += "\\PartDescriptionFiles";
searchpath.push_back( path );
} catch( ErrorMsg * e )
{
delete e;
}
#endif
/* Search for file */
path.erase();
int i;
for( i = 0; i < searchpath.size(); i++ )
{
path = searchpath[i] + "\\" + deviceName + ".xml";
if( Util.fileExists( path ) )
break;
}
if( i == searchpath.size() )
throw new ErrorMsg( "Device XML file not found in search path!" );
/* Parse the file for required info */
Util.log( "Parsing '" + path + "'...\r\n" );
XMLFile f( path ); // Load XML info
flashSize = atoi( f.getValue( "AVRPART\\MEMORY\\PROG_FLASH" ).c_str() );
eepromSize = atoi( f.getValue( "AVRPART\\MEMORY\\EEPROM" ).c_str() );
cache += "<AVRPART><MEMORY><PROG_FLASH>";
cache += f.getValue( "AVRPART\\MEMORY\\PROG_FLASH" );
cache += "</PROG_FLASH><EEPROM>";
cache += f.getValue( "AVRPART\\MEMORY\\EEPROM" );
cache += "</EEPROM>";
if( f.exists( "AVRPART\\MEMORY\\BOOT_CONFIG" ) )
{
pagesize = atoi( f.getValue( "AVRPART\\MEMORY\\BOOT_CONFIG\\PAGESIZE" ).c_str() );
pagesize <<= 1; // We want pagesize in bytes.
cache += "<BOOT_CONFIG><PAGESIZE>";
cache += f.getValue( "AVRPART\\MEMORY\\BOOT_CONFIG\\PAGESIZE" );
cache += "</PAGESIZE></BOOT_CONFIG>";
}
cache += "</MEMORY>";
if( f.exists( "AVRPART\\FUSE" ) )
{
hasFuseBits = true;
cache += "<FUSE>";
if( f.exists( "AVRPART\\FUSE\\EXTENDED" ) )
{
hasExtendedFuseBits = true;
cache += "<EXTENDED></EXTENDED>";
}
cache += "</FUSE>";
}
signature = f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR000" );
signature.erase( 0, 1 ); // Remove the $ character.
signature0 = Util.convertHex( signature );
signature = f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR001" );
signature.erase( 0, 1 ); // Remove the $ character.
signature1 = Util.convertHex( signature );
signature = f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR002" );
signature.erase( 0, 1 ); // Remove the $ character.
signature2 = Util.convertHex( signature );
cache += "<ADMIN><SIGNATURE><ADDR000>";
cache += f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR000" );
cache += "</ADDR000><ADDR001>";
cache += f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR001" );
cache += "</ADDR001><ADDR002>";
cache += f.getValue( "AVRPART\\ADMIN\\SIGNATURE\\ADDR002" );
cache += "</ADDR002></SIGNATURE></ADMIN></AVRPART>\r\n";
/* Save cached file to application directory */
Util.log( "Saving cached XML parameters...\r\n" );
Util.saveString( cache, searchpath[1] + "\\" + deviceName + ".xml" );
}
void AVRDevice::getSignature( long * sig0, long * sig1, long * sig2 )
{
if( sig0 == NULL || sig1 == NULL || sig2 == NULL )
throw new ErrorMsg( "Cannot copy signature bytes to NULL-pointers!" );
*sig0 = signature0;
*sig1 = signature1;
*sig2 = signature2;
}
/* end of file */
+69
View File
@@ -0,0 +1,69 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRDevice.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class containing information of device memory sizes etc.
* It also provides funcitons for reading these parameters from
* the PartDescriptionFiles supplied with AVR Studio 4.
*
*
****************************************************************************/
#ifndef AVRDEVICE_HPP
#define AVRDEVICE_HPP
using namespace std;
#include <string>
#include <vector>
#include "Utility.hpp"
#include "XMLParser.hpp"
#include "ErrorMsg.hpp"
class AVRDevice
{
protected:
string deviceName; // The name of the device, eg. ATmega128.
long flashSize; // Size of Flash memory in bytes.
long eepromSize; // Size of EEPROM memory in bytes.
bool hasFuseBits; // Does this device have fuse bits at all?
bool hasExtendedFuseBits; // Does this device have extended fuses?
long signature0;
long signature1;
long signature2; // The three signature bytes, read from XML PartDescriptionFiles.
long pagesize; // Flash page size.
public:
/* Constructor */
AVRDevice( const string & _deviceName );
/* Destructor */
~AVRDevice();
/* Methods */
void readParametersFromAVRStudio( vector<string> & searchpath );
long getFlashSize() { return flashSize; }
long getEEPROMSize() { return eepromSize; }
long getPageSize() { return pagesize; }
bool getFuseStatus() { return hasFuseBits; }
bool getXFuseStatus() { return hasExtendedFuseBits; }
void getSignature( long * sig0, long * sig1, long * sig2 );
};
#endif
@@ -0,0 +1,714 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRInSystemProg.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing an interface to the AVR ISP described
* in Application Note AVR910. This class is derived from AVRPRogrammer.
*
*
****************************************************************************/
#include "AVRInSystemProg.hpp"
#include <sstream>
#include <iomanip>
#define MEM_PROGRESS_GRANULARITY 256 // For use with progress indicator.
/* Constructor */
AVRInSystemProg::AVRInSystemProg( CommChannel * _comm ) :
AVRProgrammer::AVRProgrammer( _comm )
{
/* No code here */
}
/* Destructor */
AVRInSystemProg::~AVRInSystemProg()
{
/* No code here */
}
bool AVRInSystemProg::enterProgrammingMode()
{
/* Must select a device from the AVRISP device code table first */
comm->sendByte( 'T' );
comm->sendByte( 0x64 ); // Select ATmega163, any device in the table will do.
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Entering programming mode failed! "
"Programmer did not return CR after 'T'-command." );
/* Send command 'P' */
comm->sendByte( 'P' );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Entering programming mode failed! "
"Programmer did not return CR after 'P'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::leaveProgrammingMode()
{
/* Send command 'L' */
comm->sendByte( 'L' );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Leaving programming mode failed! "
"Programmer did not return CR after 'L'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::chipErase()
{
/* Send command 'e' */
comm->sendByte( 'e' );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Chip erase failed! "
"Programmer did not return CR after 'e'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readOSCCAL( long pos, long * value )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x38 );
comm->sendByte( 0x00 );
comm->sendByte( pos );
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
*value = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "OSCCAL value readout failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readSignature( long * sig0, long * sig1, long * sig2 )
{
/* Send command 's' */
comm->sendByte( 's' );
comm->flushTX();
/* Get actual signature */
*sig2 = comm->getByte();
*sig1 = comm->getByte();
*sig0 = comm->getByte();
}
bool AVRInSystemProg::checkSignature( long sig0, long sig1, long sig2 )
{
long sig[3];
/* Get signature */
readSignature( sig, sig+1, sig+2 );
/* Compare signature */
if( sig[0] != sig0 || sig[1] != sig1 || sig[2] != sig2 )
{
ostringstream msg;
msg << "Signature does not match selected device! ";
msg << "Actual signature: (" << hex
<< "0x" << setw(2) << sig[0] << " "
<< "0x" << setw(2) << sig[1] << " "
<< "0x" << setw(2) << sig[2] << ") "
<< "Signature from XML-file: (" << hex
<< "0x" << setw(2) << sig0 << " "
<< "0x" << setw(2) << sig1 << " "
<< "0x" << setw(2) << sig2 << ").";
throw new ErrorMsg( msg.str() );
}
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeFlashByte( long address, long value )
{
if( address >= 0x20000 )
throw new ErrorMsg( "Flash addresses above 128k are currently not supported!" );
setAddress( address >> 1 ); // Flash operations use word addresses.
/* Move data if at odd address */
if( address & 0x01 ) // Odd address?
value = (value << 8) | 0x00ff; // Move to high byte of one flash word.
else
value |= 0xff00; // Ensure no-write for high byte.
/* Send low and high byte */
writeFlashLowByte( value & 0xff );
writeFlashHighByte( value >> 8 );
/* Issue page write if required */
if( pagesize != -1 )
{
setAddress( address >> 1 ); // The address could be autoincremented.
writeFlashPage();
}
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeEEPROMByte( long address, long value )
{
if( address >= 0x10000 )
throw new ErrorMsg( "EEPROM addresses above 64k are currently not supported!" );
setAddress( address );
/* Send data */
comm->sendByte( 'D' );
comm->sendByte( value );
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing byte to EEPROM failed! "
"Programmer did not return CR after 'D'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeFlash( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Check that pagesize is set */
if( pagesize == -1 )
throw new ErrorMsg( "Programmer pagesize is not set!" );
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start >> 1 ); // Flash operations use word addresses.
/* Need to write one odd byte first? */
address = start;
if( address & 1 )
{
/* Use only high byte */
writeFlashLowByte( 0xff ); // No-write in low byte.
writeFlashHighByte( data->getData( address ) );
address++;
/* Need to write page? */
if( pagesize != -1 )
{
if( !(address % pagesize) ) // Just passed page limit?
{
setAddress( (address-1) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
}
/* Write words */
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address >> 1 );
/* Write words */
writeFlashLowByte( data->getData( address ) );
writeFlashHighByte( data->getData( address+1 ) );
address += 2;
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
/* Need to write page? */
if( pagesize != -1 )
{
if( (address % pagesize) == 0 ) // Just passed a page boundary?
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
setAddress( address >> 1 );
}
}
} while( address < end );
/* Need to write one even byte before finished? */
if( address == end )
{
/* Use only low byte */
writeFlashLowByte( data->getData( address ) );
writeFlashHighByte( 0xff ); // No-write in high byte.
}
/* Need to write page? */
if( pagesize != -1 )
{
if( address == end || // One extra byte written...
(end+1)%pagesize != 0 ) // ...or end is not on page boundary.
{
setAddress( (address-2) >> 1 ); // Set to an address inside the page.
writeFlashPage();
}
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRInSystemProg::readFlash( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
if( pagesize == -1 )
throw new ErrorMsg( "Programmer pagesize is not set!" );
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start >> 1 ); // Flash operations use word addresses.
/* Need to read one odd byte first? */
address = start;
if( address & 1 )
{
/* Read both, but use only high byte */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address, comm->getByte() ); // High byte.
comm->getByte(); // Dont use low byte.
address++;
}
/* Get words */
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address >> 1 );
/* Get words */
comm->sendByte( 'R' );
comm->flushTX();
data->setData( address+1, comm->getByte() ); // High byte.
data->setData( address, comm->getByte() ); // Low byte.
address += 2;
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
} while( address < end );
/* Need to read one even byte before finished? */
if( address == end )
{
/* Read both, but use only low byte */
comm->sendByte( 'R' );
comm->flushTX();
comm->getByte(); // Dont use high byte.
data->setData( address-1, comm->getByte() ); // Low byte.
}
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeEEPROM( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start );
/* Send data */
address = start;
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address );
/* Send byte */
comm->sendByte( 'D' );
comm->sendByte( data->getData( address ) );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing byte to EEPROM failed! "
"Programmer did not return CR after 'D'-command." );
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
address++;
} while( address <= end );
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRInSystemProg::readEEPROM( HEXFile * data )
{
long start, end; // Data address range.
bool autoincrement; // Bootloader supports address autoincrement?
long address;
/* Get range from HEX file */
start = data->getRangeStart();
end = data->getRangeEnd();
/* Check autoincrement support */
comm->sendByte( 'a' );
comm->flushTX();
if( comm->getByte() == 'Y' )
autoincrement = true;
else
autoincrement = false;
/* Set initial address */
setAddress( start );
/* Send data */
address = start;
do
{
/* Need to set address again? */
if( !autoincrement )
setAddress( address );
/* Get byte */
comm->sendByte( 'd' );
comm->flushTX();
data->setData( address, comm->getByte() );
if( (address % MEM_PROGRESS_GRANULARITY) == 0 )
Util.progress( "#" ); // Advance progress indicator.
address++;
} while( address <= end );
Util.progress( "\r\n" ); // Finish progress indicator.
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeLockBits( long bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0xac );
comm->sendByte( 0xe0 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( bits );
comm->flushTX();
comm->getByte(); // Ignore return code from SPI communication.
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Writing lock bits failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readLockBits( long * bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x58 );
comm->sendByte( 0x00 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
*bits = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Lock byte readout failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeFuseBits( long bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0xac );
comm->sendByte( 0xa0 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( bits & 0xff );
comm->flushTX();
comm->getByte(); // Ignore return code from SPI communication.
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Low fuse byte programming failed! "
"Programmer did not return CR after '.'-command." );
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0xac );
comm->sendByte( 0xa8 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( bits >> 8 );
comm->flushTX();
comm->getByte(); // Ignore return code from SPI communication.
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "High fuse byte programming failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readFuseBits( long * bits )
{
long low, high;
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x50 );
comm->sendByte( 0x00 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
low = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Low fuse byte readout failed! "
"Programmer did not return CR after '.'-command." );
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x58 );
comm->sendByte( 0x08 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
high = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Low fuse byte readout failed! "
"Programmer did not return CR adter '.'-command." );
/* Put low and high together */
*bits = (high << 8) | low;
return true; // Indicate supported command.
}
bool AVRInSystemProg::writeExtendedFuseBits( long bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0xac );
comm->sendByte( 0xa4 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( bits );
comm->flushTX();
comm->getByte(); // Ignore return code from SPI communication.
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Extended fuse byte programming failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::readExtendedFuseBits( long * bits )
{
/* Use AVRISP's 4-byte universal command */
comm->sendByte( '.' );
comm->sendByte( 0x50 );
comm->sendByte( 0x08 );
comm->sendByte( 0x00 ); // Dummy.
comm->sendByte( 0x00 ); // Dummy.
comm->flushTX();
*bits = comm->getByte();
if( comm->getByte() != '\r' ) // Check return code from command.
throw new ErrorMsg( "Extended fuse byte readout failed! "
"Programmer did not return CR after '.'-command." );
return true; // Indicate supported command.
}
bool AVRInSystemProg::programmerSoftwareVersion( long * major, long * minor )
{
/* Send command 'V' to get software version */
comm->sendByte( 'V' );
comm->flushTX();
/* Get data */
*major = comm->getByte();
*minor = comm->getByte();
return true; // Indicate supported command.
}
bool AVRInSystemProg::programmerHardwareVersion( long * major, long * minor )
{
/* Send command 'v' to get hardware version */
comm->sendByte( 'v' );
comm->flushTX();
/* Get data */
*major = comm->getByte();
*minor = comm->getByte();
return true; // Indicate supported command.
}
void AVRInSystemProg::setAddress( long address )
{
/* Set current address */
comm->sendByte( 'A' );
comm->sendByte( address >> 8 ); // High byte of address.
comm->sendByte( address & 0xff ); // Low byte.
comm->flushTX();
/* Should return CR */
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Setting address for programming operations failed! "
"Programmer did not return CR after 'A'-command." );
}
void AVRInSystemProg::writeFlashLowByte( long value )
{
comm->sendByte( 'c' );
comm->sendByte( value );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash low byte failed! "
"Programmer did not return CR after 'c'-command." );
}
void AVRInSystemProg::writeFlashHighByte( long value )
{
comm->sendByte( 'C' );
comm->sendByte( value );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash high byte failed! "
"Programmer did not return CR after 'C'-command." );
}
void AVRInSystemProg::writeFlashPage()
{
comm->sendByte( 'm' );
comm->flushTX();
if( comm->getByte() != '\r' )
throw new ErrorMsg( "Writing Flash page failed! "
"Programmer did not return CR after 'm'-command." );
}
/* end of file */
@@ -0,0 +1,78 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRInSystemProg.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing an interface to the AVR ISP described
* in Application Note AVR910. This class is derived from AVRPRogrammer.
*
*
****************************************************************************/
#ifndef AVRINSYSTEMPROG_HPP
#define AVRINSYSTEMPROG_HPP
using namespace std;
#include "AVRProgrammer.hpp"
#include "Utility.hpp"
class AVRInSystemProg : public AVRProgrammer
{
protected:
void setAddress( long address );
void writeFlashLowByte( long value ); // Alwyas low byte first...
void writeFlashHighByte( long value ); // ...then high byte.
void writeFlashPage();
public:
/* Constructor */
AVRInSystemProg( CommChannel * _comm );
/* Destructor */
~AVRInSystemProg();
/* Methods */
virtual bool enterProgrammingMode();
virtual bool leaveProgrammingMode();
virtual bool chipErase();
virtual bool readOSCCAL( long pos, long * value );
virtual bool readSignature( long * sig0, long * sig1, long * sig2 );
virtual bool checkSignature( long sig0, long sig1, long sig2 );
virtual bool writeFlashByte( long address, long value );
virtual bool writeEEPROMByte( long address, long value );
virtual bool writeFlash( HEXFile * data );
virtual bool readFlash( HEXFile * data );
virtual bool writeEEPROM( HEXFile * data );
virtual bool readEEPROM( HEXFile * data );
virtual bool writeLockBits( long bits );
virtual bool readLockBits( long * bits );
virtual bool writeFuseBits( long bits );
virtual bool readFuseBits( long * bits );
virtual bool writeExtendedFuseBits( long bits );
virtual bool readExtendedFuseBits( long * bits );
virtual bool programmerSoftwareVersion( long * major, long * minor );
virtual bool programmerHardwareVersion( long * major, long * minor );
};
#endif
+169
View File
@@ -0,0 +1,169 @@
[Project]
FileName=AVROSP.dev
Name=AVROSP
UnitCount=12
Type=1
Ver=1
ObjFiles=
Includes=
Libs=
PrivateResource=
ResourceIncludes=
MakeIncludes=
Compiler=
CppCompiler=
Linker=
IsCpp=1
Icon=
ExeOutput=
ObjectOutput=
OverrideOutput=0
OverrideOutputName=AVROSP.exe
HostApplication=
Folders=
CommandLine= -dATmega16 -if\temp\rnd8KB.hex -pf
IncludeVersionInfo=0
SupportXPThemes=0
CompilerSet=0
CompilerSettings=000000000000000100
UseCustomMakefile=0
CustomMakefile=
[Unit1]
FileName=main.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[VersionInfo]
Major=0
Minor=1
Release=1
Build=1
LanguageID=1033
CharsetID=1252
CompanyName=
FileVersion=
FileDescription=Developed using the Dev-C++ IDE
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=
AutoIncBuildNr=0
[Unit2]
FileName=CommChannel.cpp
CompileCpp=1
Folder=Serialtest
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit3]
FileName=ErrorMsg.cpp
CompileCpp=1
Folder=Serialtest
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit4]
FileName=JobInfo.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit5]
FileName=AVRDevice.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit6]
FileName=HEXParser.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit7]
FileName=XMLParser.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit8]
FileName=AVRBootloader.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit9]
FileName=AVRProgrammer.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit10]
FileName=Utility.cpp
CompileCpp=1
Folder=
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit11]
FileName=SerialPort.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit12]
FileName=AVRInSystemProg.cpp
CompileCpp=1
Folder=AVROSP
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
@@ -0,0 +1,70 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRProgrammer.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : An abstract class containing a framework for a generic
* programmer for AVR parts. Reading and writing Flash, EEPROM
* lock bits and all fuse bits and reading OSCCAL and reading
* signature bytes are supported.
*
*
****************************************************************************/
#include "AVRProgrammer.hpp"
/* Constructor */
AVRProgrammer::AVRProgrammer( CommChannel * _comm ) :
pagesize( -1 )
{
if( _comm == NULL )
throw new ErrorMsg( "NULL pointer provided for communication channel!" );
comm = _comm;
}
/* Destructor */
AVRProgrammer::~AVRProgrammer()
{
/* No code here */
}
string AVRProgrammer::readProgrammerID( CommChannel * _comm )
{
string id( "1234567" ); // Reserve 7 characters.
if( _comm == NULL )
throw new ErrorMsg( "NULL pointer provided for communication channel!" );
/* Synchonize with programmer */
for( int i = 0; i < 10; i++ )
_comm->sendByte( 27 ); // Send ESC
/* Send 'S' command to programmer */
_comm->sendByte( 'S' );
_comm->flushTX();
/* Read 7 characters */
for( long i = 0; i < id.size(); i++ )
{
id[i] = _comm->getByte();
}
return id;
}
/* end of file */
@@ -0,0 +1,84 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : AVRProgrammer.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : An abstract class containing a framework for a generic
* programmer for AVR parts. Reading and writing Flash, EEPROM
* lock bits and all fuse bits and reading OSCCAL and reading
* signature bytes are supported.
*
*
****************************************************************************/
#ifndef AVRPROGRAMMER_HPP
#define AVRPROGRAMMER_HPP
using namespace std;
#include "ErrorMsg.hpp"
#include "HEXParser.hpp"
#include "CommChannel.hpp"
class AVRProgrammer
{
protected:
long pagesize; // Flash page size.
CommChannel * comm;
public:
/* Constructor */
AVRProgrammer( CommChannel * _comm );
/* Destructor */
~AVRProgrammer();
/* Static member */
static string readProgrammerID( CommChannel * _comm ); // Reads 7-character ID.
/* Methods */
void setPagesize( long _pagesize ) { pagesize = _pagesize; }
virtual bool enterProgrammingMode() = 0;
virtual bool leaveProgrammingMode() = 0;
virtual bool chipErase() = 0;
virtual bool readOSCCAL( long pos, long * value ) = 0;
virtual bool readSignature( long * sig0, long * sig1, long * sig2 ) = 0;
virtual bool checkSignature( long sig0, long sig1, long sig2 ) = 0;
virtual bool writeFlashByte( long address, long value ) = 0;
virtual bool writeEEPROMByte( long address, long value ) = 0;
virtual bool writeFlash( HEXFile * data ) = 0;
virtual bool readFlash( HEXFile * data ) = 0;
virtual bool writeEEPROM( HEXFile * data ) = 0;
virtual bool readEEPROM( HEXFile * data ) = 0;
virtual bool writeLockBits( long bits ) = 0;
virtual bool readLockBits( long * bits ) = 0;
virtual bool writeFuseBits( long bits ) = 0;
virtual bool readFuseBits( long * bits ) = 0;
virtual bool writeExtendedFuseBits( long bits ) = 0;
virtual bool readExtendedFuseBits( long * bits ) = 0;
virtual bool programmerSoftwareVersion( long * major, long * minor ) = 0;
virtual bool programmerHardwareVersion( long * major, long * minor ) = 0;
};
#endif
@@ -0,0 +1,38 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : CommChannel.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : An abstract class for general byte-by-byte communication.
* Serialport, USB, TCP/IP or similar implementations can be derived
* from this class to create a technology-independent
* communication interface.
*
* This abstract class does not provide any constructor as it is
* too specific for this generalized class. Derived classes should
* implement their own constructors for specific communication devices.
*
*
****************************************************************************/
#include "CommChannel.hpp"
/* Destructor */
CommChannel::~CommChannel()
{
/* no code here */
}
/* end of file */
@@ -0,0 +1,61 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : CommChannel.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : An abstract class for general byte-by-byte communication.
* Serialport, USB, TCP/IP or similar implementations can be derived
* from this class to create a technology-independent
* communication interface.
*
* This abstract class does not provide any constructor as it is
* too specific for this generalized class. Derived classes should
* implement their own constructors for specific communication devices.
*
*
****************************************************************************/
#ifndef COMMCHANNEL_HPP
#define COMMCHANNEL_HPP
using namespace std;
class CommChannel
{
public:
// Destructor
virtual ~CommChannel() = 0;
// Open the communication channel.
virtual void openChannel() = 0;
// Close the communication channel.
virtual void closeChannel() = 0;
// Transmit a single byte.
virtual void sendByte( long data ) = 0;
// Receive a single byte.
virtual long getByte() = 0;
// Flush the transmit buffer.
virtual void flushTX() = 0;
// Flush the receive buffer.
virtual void flushRX() = 0;
// Transmit multiple bytes.
virtual void sendMultiple( unsigned char * data, long bufsize ) = 0;
};
#endif
+46
View File
@@ -0,0 +1,46 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : ErrorMsg.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing a container for general error messages. This
* class can be thrown as an exception.
*
*
****************************************************************************/
#include "ErrorMsg.hpp"
ErrorMsg::ErrorMsg( const string & _message ) :
message( _message )
{
// No code here.
}
/* Destructor */
ErrorMsg::~ErrorMsg()
{
// No code here.
}
/* Get message */
const string & ErrorMsg::What()
{
return message;
}
/* end of file */
+49
View File
@@ -0,0 +1,49 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : ErrorMsg.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing a container for general error messages. This
* class can be thrown as an exception.
*
*
****************************************************************************/
#ifndef ERRORMSG_HPP
#define ERRORMSG_HPP
using namespace std;
#include <stdlib.h>
#include <iostream>
#include <string>
class ErrorMsg
{
protected:
string message; // Contains the error message.
public:
// Constructors taking the string as parameter.
ErrorMsg( const string & _message );
// Destructor
~ErrorMsg();
// Function returning the error msg.
virtual const string & What();
};
#endif
+364
View File
@@ -0,0 +1,364 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : HEXParser.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A simple Intel HEX file format reader/writer.
*
*
****************************************************************************/
#include "HEXParser.hpp"
/* Internal struct for managing HEX records */
struct HEXRecord // Intel HEX file record
{
unsigned char length; // Record length in number of data bytes.
unsigned long offset; // Offset address.
unsigned char type; // Record type.
unsigned char * data; // Optional data bytes.
};
void HEXFile::writeRecord( ofstream & f, HEXRecord * recp )
{
unsigned char checksum;
long recordPos; // Position inside record data field
/* Calculate checksum */
checksum = recp->length;
checksum += (unsigned char) ((recp->offset >> 8) & 0xff);
checksum += (unsigned char) (recp->offset & 0xff);
checksum += recp->type;
/* Write record header */
f.fill('0');
f << ":" << hex
<< setw(2) << (long) recp->length
<< setw(4) << (long) recp->offset
<< setw(2) << (long) recp->type;
/* Write data bytes */
for( recordPos = 0; recordPos < recp->length; recordPos++ )
{
checksum += recp->data[ recordPos ]; // Further checksum calculation
f << hex << setw(2) << (long) recp->data[ recordPos ];
}
/* Write checksum */
checksum = 0 - checksum; // Final checksum preparation
f << setw(2) << (long) checksum << endl;
/* Check for errors */
if( !f.good() )
throw new ErrorMsg( "Error writing HEX record to file!" );
}
void HEXFile::parseRecord( const string & hexLine, HEXRecord * recp )
{
unsigned char checksum;
long recordPos; // Position inside record data fields.
if( hexLine.size() < 11 ) // At least 11 characters.
throw new ErrorMsg( "Wrong HEX file format, missing fields! "
"Line from file was: (" + hexLine + ")." );
/* Check format for line */
if( hexLine[0] != ':' ) // Always start with colon.
throw new ErrorMsg( "Wrong HEX file format, does not start with colon! "
"Line from file was: (" + hexLine + ")." );
/* Parse length, offset and type */
recp->length = Util.convertHex( hexLine.substr( 1, 2 ) );
recp->offset = Util.convertHex( hexLine.substr( 3, 4 ) );
recp->type = Util.convertHex( hexLine.substr( 7, 2 ) );
/* We now know how long the record should be */
if( hexLine.size() < (11+recp->length*2) )
throw new ErrorMsg( "Wrong HEX file format, missing fields! "
"Line from file was: (" + hexLine + ")." );
/* Process checksum */
checksum = recp->length;
checksum += (unsigned char) ((recp->offset >> 8) & 0xff);
checksum += (unsigned char) (recp->offset & 0xff);
checksum += recp->type;
/* Parse data fields */
if( recp->length )
{
recp->data = new unsigned char[ recp->length ];
/* Read data from record */
for( recordPos = 0; recordPos < recp->length; recordPos++ )
{
recp->data[ recordPos ] = Util.convertHex( hexLine.substr( 9 + recordPos*2, 2 ) );
checksum += recp->data[ recordPos ];
}
}
/* Correct checksum? */
checksum += Util.convertHex( hexLine.substr( 9 + recp->length*2, 2 ) );
if( checksum != 0 )
{
throw new ErrorMsg( "Wrong checksum for HEX record! "
"Line from file was: (" + hexLine + ")." );
}
}
/* Constructor */
HEXFile::HEXFile( long buffersize, long value )
{
if( buffersize <= 0 )
throw new ErrorMsg( "Cannot have zero-size HEX buffer!" );
data = new unsigned char[ buffersize ];
if( !data )
throw new ErrorMsg( "Memory allocation failed for HEX-line-buffer!" );
size = buffersize;
clearAll( value );
}
/* Destructor */
HEXFile::~HEXFile()
{
if( data ) delete data;
}
void HEXFile::readFile( const string & _filename )
{
ifstream f;
string hexLine; // Contains one line of the HEX file.
HEXRecord rec; // Temp record.
long baseAddress; // Base address for extended addressing modes.
long dataPos; // Data position in record.
/* Attempt to open file */
f.open( _filename.c_str(), ios::in );
if( !f )
throw new ErrorMsg( "Error opening HEX file for input!" );
/* Prepare */
baseAddress = 0;
start = size;
end = 0;
/* Parse records */
f >> hexLine; // Read one line.
while( !f.eof() )
{
Util.progress( "#" ); // Advance progress indicator.
/* Process record according to type */
parseRecord( hexLine, &rec );
switch( rec.type )
{
case 0x00 : // Data record ?
/* Copy data */
if( baseAddress + rec.offset + rec.length > size )
throw new ErrorMsg( "HEX file defines data outside buffer limits! "
"Make sure file does not contain data outside device "
"memory limits. "
"Line from file was: (" + hexLine + ")." );
for( dataPos = 0; dataPos < rec.length; dataPos++ )
data[ baseAddress + rec.offset + dataPos ] = rec.data[ dataPos ];
/* Update byte usage */
if( baseAddress + rec.offset < start )
start = baseAddress + rec.offset;
if( baseAddress + rec.offset + rec.length - 1 > end )
end = baseAddress + rec.offset + rec.length - 1;
break;
case 0x02 : // Extended segment address record ?
baseAddress = (rec.data[0] << 8) | rec.data[1];
baseAddress <<= 4;
break;
case 0x03 : // Start segment address record ?
break; // Ignore it, since we have no influence on execution start address.
case 0x04 : // Extended linear address record ?
baseAddress = (rec.data[0] << 8) | rec.data[1];
baseAddress <<= 16;
break;
case 0x05 : // Start linear address record ?
break; // Ignore it, since we have no influence on exectuion start address.
case 0x01 : // End of file record ?
f.close();
Util.progress( "\r\n" ); // Finish progress indicator.
return;
default:
throw new ErrorMsg( "Unsupported HEX record format! "
"Line from file was: (" + hexLine + ")." );
}
f >> hexLine; // Read next line.
}
/* We should not end up here */
throw new ErrorMsg( "Premature end of file encountered! Make sure file "
"contains an EOF-record." );
}
void HEXFile::writeFile( const string & _filename )
{
ofstream f;
HEXRecord rec; // Temp record.
long baseAddress; // Absolute data position.
long offset; // Offset from base address.
long dataPos; // Position inside data record.
enum
{
_first,
_writing,
_passed64k
} status; // Write status, see usage below.
/* Attempt to create file */
f.open( _filename.c_str(), ios::out );
if( !f )
throw new ErrorMsg( "Error opening HEX file for output!" );
/* Prepare */
status = _first;
rec.data = new unsigned char[ 16 ]; // Use only 16 byte records.
baseAddress = start & ~0xffff; // 64K aligned address.
offset = start & 0xffff; // Offset from the aligned address.
dataPos = 0;
/* Write first base address record to HEX file */
rec.length = 2;
rec.offset = 0;
rec.type = 0x02;
rec.data[1] = 0x00;
rec.data[0] = baseAddress >> 12; // Give 4k page index.
writeRecord( f, &rec ); // Write the HEX record to file.
/* Write all bytes in used range */
do
{
/* Put data into record */
rec.data[ dataPos ] = data[ baseAddress + offset + dataPos ];
dataPos++;
/* Check if we need to write out the current data record */
if( offset + dataPos >= 0x10000 || // Reached 64k boundary?
dataPos >= 16 || // Data record full?
baseAddress + offset + dataPos > end ) // End of used range reached?
{
/* Write current data record */
rec.length = dataPos;
rec.offset = offset;
rec.type = 0x00; // Data record.
Util.progress( "#" ); // Advance progress indicator.
writeRecord( f, &rec );
offset += dataPos;
dataPos = 0;
}
/* Check if we have passed a 64k boundary */
if( offset + dataPos >= 0x10000 )
{
/* Update address pointers */
offset -= 0x10000;
baseAddress += 0x10000;
/* Write new base address record to HEX file */
rec.length = 2;
rec.offset = 0;
rec.type = 0x02;
rec.data[0] = baseAddress >> 12; // Give 4k page index.
rec.data[1] = 0x00;
writeRecord( f, &rec ); // Write the HEX record to file.
}
} while( baseAddress + offset + dataPos <= end );
/* Write EOF record */
rec.length = 0;
rec.offset = 0;
rec.type = 0x01;
writeRecord( f, &rec );
f.close();
Util.progress( "\r\n" ); // Finish progress indicator.
}
void HEXFile::setUsedRange( long _start, long _end )
{
if( _start < 0 || _end >= size || _start > _end )
throw new ErrorMsg( "Invalid range! Start must be 0 or larger, end must be "
"inside allowed memory range." );
start = _start;
end = _end;
}
void HEXFile::clearAll( long value )
{
for( long i = 0; i < size; i++ )
data[i] = (unsigned char) (value & 0xff);
}
long HEXFile::getData( long address )
{
if( address < 0 || address >= size )
throw new ErrorMsg( "Address outside legal range!" );
return data[ address ];
}
void HEXFile::setData( long address, long value )
{
if( address < 0 || address >= size )
throw new ErrorMsg( "Address outside legal range!" );
data[ address ] = (unsigned char) (value & 0xff);
}
/* end of file */
+67
View File
@@ -0,0 +1,67 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : HEXParser.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A simple Intel HEX file format reader/writer.
*
*
****************************************************************************/
#ifndef HEXPARSER_HPP
#define HEXPARSER_HPP
using namespace std;
#include "ErrorMsg.hpp"
#include "Utility.hpp"
#include <iostream>
#include <fstream>
#include <iomanip>
struct HEXRecord; // Preliminary definition.
class HEXFile
{
protected:
unsigned char * data; // Holds the data bytes.
long start, end; // Used data range.
long size; // Size of databuffer.
void writeRecord( ofstream & f, HEXRecord * recp );
void parseRecord( const string & hexLine, HEXRecord * recp );
public:
/* Constructor */
HEXFile( long buffersize, long value = 0xff );
/* Destructor */
~HEXFile();
/* Methods */
void readFile( const string & _filename ); // Read data from HEX file.
void writeFile( const string & _filename ); // Write data to HEX file.
void setUsedRange( long _start, long _end ); // Sets the used range.
void clearAll( long value = 0xff ); // Set databuffer to this value.
long getRangeStart() { return start; }
long getRangeEnd() { return end; }
long getData( long address );
void setData( long address, long value );
long getSize() { return size; }
};
#endif
File diff suppressed because it is too large Load Diff
+105
View File
@@ -0,0 +1,105 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : JobInfo.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class holding information on what the AVR Open-Source Programmer
* should do. The information is derived from the command-line.
*
*
****************************************************************************/
#ifndef JOBINFO_HPP
#define JOBINFO_HPP
using namespace std;
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include "ErrorMsg.hpp"
#include "AVRProgrammer.hpp"
#include "AVRBootloader.hpp"
#include "AVRInSystemProg.hpp"
#include "AVRDevice.hpp"
#include "SerialPort.hpp"
#include "Utility.hpp"
class JobInfo
{
protected:
long convertHex( char * txt );
void help();
void doDeviceIndependent( AVRProgrammer * prog );
void doDeviceDependent( AVRProgrammer * prog, AVRDevice * avr );
bool showHelp; // Show help screen?
bool silentMode; // No text output?
bool noProgressIndicator; // Do not show progress indicators?
bool readSignature; // Output signature bytes to screen?
bool chipErase; // Erase chip before any programming operations?
bool getHWrevision; // Get hardware revision of programmer?
bool getSWrevision; // Get software revision of programmer?
bool programFlash; // Flash programming desired?
bool programEEPROM; // E2 programming desired?
bool readFlash; // Flash readout desired?
bool readEEPROM; // E2 readout desired?
bool verifyFlash; // Flash verification desired?
bool verifyEEPROM; // E2 verification desired?
bool readLockBits; // Lock bit readout desired?
bool readFuseBits; // Fuse bit readout desired?
bool readOSCCAL; // Read or use specified OSCCAL value, if -O is used?
string deviceName; // Specified device name.
string inputFileFlash; // Input file for Flash writing and verification.
string inputFileEEPROM; // Input file for E2 writing and verification.
string outputFileFlash; // Output file for Flash readout.
string outputFileEEPROM; // Output file for E2 readout.
long OSCCAL_Parameter; // Value of the -O parameter, -1 if unspecified.
long OSCCAL_FlashAddress; // Where to put OSCCAL value in flash, -1 if not.
long OSCCAL_EEPROMAddress; // Where to put OSCCAL value in E2, -1 if not.
long programLockBits; // Change lock bits to this value, -1 if not.
long verifyLockBits; // Verify lock bits against this value, -1 if not.
long programFuseBits; // Change fuse bits to this value, -1 if not.
long programExtendedFuseBits; // Same as above for extended fuse bits.
long verifyFuseBits; // Verify fuse bits against this value, -1 if not.
long verifyExtendedFuseBits; // Same as above for extended fuse bits.
long memoryFillPattern; // Fill unspecified locations, -1 if not.
long flashStartAddress; // Limit Flash operations, -1 if not.
long flashEndAddress; // ...to this address, inclusive, -1 if not.
long eepromStartAddress; // Same as above for E2.
long eepromEndAddress; // ...
long comPort; // Desired COM port to use, -1 if unspecified.
vector<string> searchpath; // Search path for XML-files.
public:
JobInfo(); // Constructor
void parseCommandline( int argc, char *argv[] );
void doJob();
};
#endif
+203
View File
@@ -0,0 +1,203 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : SerialPort.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing serial communication through the PC COM port.
* This class is derived from the CommChannel abstract class.
*
*
****************************************************************************/
#include "SerialPort.hpp"
/* Constructor */
SerialPort::SerialPort( long _portNumber, long _timeout )
{
if( _timeout < 0 )
throw new ErrorMsg( "Negative COM-port timeout not allowed!" );
if( _portNumber < 1 || _portNumber > 99 )
throw new ErrorMsg( "Only COM1 to COM99 is supported!" );
/* Initialize internal parameters */
portNumber = _portNumber;
timeout = _timeout;
channelOpen = false;
}
/* Destructor */
SerialPort::~SerialPort()
{
closeChannel();
}
/* Open the communication channel */
void SerialPort::openChannel()
{
/* CreateFile expects a constant char, or char from the heap */
static char comName[64] = "COM1";
COMMTIMEOUTS comTimeouts;
/* Check if channel already open */
if( channelOpen )
throw new ErrorMsg( "Channel already open! Cannot open port twice." );
/* Generate COM filename and attempt open */
if (portNumber < 10) {
comName[3] = '0' + portNumber;
} else if (portNumber < 100) {
/* For COM ports greater than 9 you have to use a special syntax
for CreateFile. The syntax also works for COM ports 1-9. */
/* http://support.microsoft.com/kb/115831 */
sprintf(comName, "\\\\.\\COM%ld", portNumber);
}
serialHandle = CreateFile( comName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
/* Print error and return if failed opening port */
if( serialHandle == INVALID_HANDLE_VALUE )
throw new ErrorMsg( "Error opening COM port!" );
channelOpen = true;
/* Store old COM port settings */
if( !GetCommTimeouts( serialHandle, &oldComTimeouts ) )
throw new ErrorMsg( "Error reading COM port settings!" );
/* Get another copy of the COM settings, and change them */
if( !GetCommTimeouts( serialHandle, &comTimeouts ) )
throw new ErrorMsg( "Error reading COM port settings!" );
comTimeouts.ReadIntervalTimeout = MAXDWORD;
comTimeouts.ReadTotalTimeoutConstant = 0;
comTimeouts.ReadTotalTimeoutMultiplier = 0;
/* Apply new settings */
if( !SetCommTimeouts( serialHandle, &comTimeouts ) )
throw new ErrorMsg( "Error changing COM port settings!" );
}
/* Close the communication channel */
void SerialPort::closeChannel()
{
if( !channelOpen )
return;
/* Restore old COM parameters */
if( !SetCommTimeouts( serialHandle, &oldComTimeouts ) )
throw new ErrorMsg( "Error changing COM port settings!" );
/* Release port */
if( serialHandle != INVALID_HANDLE_VALUE )
if( !CloseHandle( serialHandle ) )
throw new ErrorMsg( "Error closing COM port!" );
channelOpen = false;
}
/* Transmit a single byte */
void SerialPort::sendByte( long data )
{
DWORD written;
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot send to unopened channel." );
/* Attempt writing */
if( !WriteFile( serialHandle, &data, 1, &written, NULL ) )
throw new ErrorMsg( "Error writing byte to COM port!" );
}
/* Receive a single byte */
long SerialPort::getByte()
{
time_t startTime;
startTime = time( NULL ); // Read current time in seconds
DWORD readnum;
unsigned char data;
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot read from unopened channel." );
/* Attempt receiving byte until timeout limit exceeded */
do
{
/* Read byte from port */
if( !ReadFile( serialHandle, &data, 1, &readnum, NULL ) )
{
throw new ErrorMsg( "Error reading byte from COM port!" );
}
if( readnum == 1 )
return ((long) data) & 0xff;
} while( time(NULL) - startTime < timeout );
/* Timeout */
throw new ErrorMsg( "Timeout during COM-port read operation!" );
}
/* Flush the transmit buffer */
void SerialPort::flushTX()
{
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot flush an unopened channel." );
/* Purge data from write buffer */
if( !PurgeComm( serialHandle, PURGE_TXCLEAR ) )
throw new ErrorMsg( "Error flushing COM port TX buffer!" );
}
/* Flush the receive buffer */
void SerialPort::flushRX()
{
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot flush an unopened channel." );
/* Purge data from write buffer */
if( !PurgeComm( serialHandle, PURGE_RXCLEAR ) )
throw new ErrorMsg( "Error flushing COM port RX buffer!" );
}
/* Transmit multiple bytes */
void SerialPort::sendMultiple( unsigned char * data, long bufsize )
{
DWORD written;
/* Check if channel is open */
if( !channelOpen )
throw new ErrorMsg( "Channel not open! Cannot write to unopened channel." );
/* Attempt writing */
if( !WriteFile( serialHandle, data, bufsize, &written, NULL ) )
throw new ErrorMsg( "Error writing multiple bytes to COM port!" );
}
/* end of file */
@@ -0,0 +1,75 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : SerialPort.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class providing serial communication through the PC COM port.
* This class is derived from the CommChannel abstract class.
*
*
****************************************************************************/
#ifndef SERIALPORT_HPP
#define SERIALPORT_HPP
using namespace std;
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <time.h>
#include <iostream>
#include "CommChannel.hpp"
#include "ErrorMsg.hpp"
class SerialPort : public CommChannel
{
protected:
long portNumber; // COMx port number.
long timeout; // Desired timeout limit when receiving data.
HANDLE serialHandle; // Win32 device handle for the com port.
COMMTIMEOUTS oldComTimeouts; // Store old serial port timeout parameters.
bool channelOpen; // Is channel open?
public:
// Constructor taking port number, baudrate and
// timeout limit as parameters.
SerialPort( long portnumber, long timeout );
// Destructor.
~SerialPort();
// Open the communication channel.
virtual void openChannel();
// Close the communication channel.
virtual void closeChannel();
// Transmit a single byte.
virtual void sendByte( long data );
// Receive a single byte.
virtual long getByte();
// Flush the transmit buffer.
virtual void flushTX();
// Flush the receive buffer.
virtual void flushRX();
// Transmit multiple bytes.
virtual void sendMultiple( unsigned char * data, long bufsize );
};
#endif
+181
View File
@@ -0,0 +1,181 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : Utility.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class holding misc. utility methods used in AVROSP.
*
*
****************************************************************************/
#include "Utility.hpp"
#include <iostream>
#include <fstream>
#include <stdlib.h>
/* Global object */
Utility Util;
/* Constructor */
Utility::Utility() :
noLog( false ),
noProgress( false )
{
/* No code here */
}
/* Destructor */
Utility::~Utility()
{
/* No code here */
}
void Utility::log( const string & txt )
{
if( !noLog )
cout << txt;
}
void Utility::progress( const string & txt )
{
if( !noProgress )
cout << txt;
}
long Utility::convertHex( const string & txt )
{
long result = 0;
long digit;
long i;
if( txt.size() == 0 )
throw new ErrorMsg( "Cannot convert zero-length hex-string to number!" );
if( txt.size() > 8 )
throw new ErrorMsg( "Hex conversion overflow! Too many hex digits in string." );
for( i = 0; i < txt.size(); i++ )
{
/* Convert hex digit */
if( txt[i] >= '0' && txt[i] <= '9' )
digit = txt[i] - '0';
else if( txt[i] >= 'a' && txt[i] <= 'f' )
digit = txt[i] - 'a' + 10;
else if( txt[i] >= 'A' && txt[i] <= 'F' )
digit = txt[i] - 'A' + 10;
else
throw new ErrorMsg( "Invalid hex digit found!" );
/* Add digit as least significant 4 bits of result */
result = (result << 4) | digit;
}
return result;
}
string Utility::convertLong( long num, long radix )
{
char buf[18];
string res;
itoa( num, buf, radix );
res = buf;
return res;
}
void Utility::parsePath( vector<string> & list )
{
/* Get environment variable and parse if it exists */
char * pathptr = getenv( "PATH" );
if( pathptr != NULL && pathptr[0] != 0 ) {
string path = pathptr;
int pos;
while( (pos = path.find_first_of( ";" )) < path.length() ) {
list.push_back( path.substr( 0, pos ) );
path.erase( 0, pos+1 );
}
list.push_back( path ); // Last directory.
}
}
bool Utility::fileExists( string filename )
{
/* Attempt to open file */
ifstream f;
f.open( filename.c_str(), ios::in );
if( !f ) {
return false;
} else {
f.close();
return true;
}
}
void Utility::saveString( string txt, string filename )
{
ofstream f;
f.open( filename.c_str(), ios::out );
if( !f )
throw new ErrorMsg( "Error opening HEX file for output!" );
f << txt;
f.close();
}
#ifndef NOREGISTRY
string Utility::getRegistryValue( const string & path, const string & value )
{
/* Code modified from MSDN */
const long BUFSIZE=1000;
string result;
HKEY hKey;
char szAVRPath[BUFSIZE];
DWORD dwBufLen=BUFSIZE;
LONG lRet;
/* Open key */
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, path.c_str(), 0, KEY_QUERY_VALUE, &hKey );
if( lRet != ERROR_SUCCESS )
throw new ErrorMsg( "Error when opening registry key: (" + path + ")!" );
/* Get value */
lRet = RegQueryValueEx( hKey, value.c_str(), NULL, NULL, (LPBYTE) szAVRPath, &dwBufLen);
if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) )
throw new ErrorMsg( "Error when reading key value: (" + value + ")!" );
/* Clean up and return result */
RegCloseKey( hKey );
result = szAVRPath;
return result;
}
#endif
/* end of file */
+70
View File
@@ -0,0 +1,70 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : Utility.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A class holding misc. utility methods used in AVROSP.
*
*
****************************************************************************/
#ifndef UTILITY_HPP
#define UTILITY_HPP
using namespace std;
#ifndef NOREGISTRY
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <vector>
#include <string>
#include "ErrorMsg.hpp"
class Utility
{
protected:
bool noLog;
bool noProgress;
public:
/* Constructor */
Utility();
/* Destructor */
~Utility();
/* Methods */
void muteLog() { noLog = true; }
void muteProgress() { noProgress = true; }
void log( const string & txt );
void progress( const string & txt );
long convertHex( const string & txt );
string convertLong( long num, long radix = 10 );
void parsePath( vector<string> & list );
bool fileExists( string filename );
void saveString( string txt, string filename );
#ifndef NOREGISTRY
string getRegistryValue( const string & path, const string & value );
#endif
};
extern Utility Util;
#endif
+637
View File
@@ -0,0 +1,637 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : XMLParser.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 3419 $
* Date : $Date: 2008-02-22 09:56:34 +0100 (fr, 22 feb 2008) $
* Updated by : $Author: khole $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A simple XML DOM-like parser. It builds a complete tree from
* the XML file. IT supports <section/> tags, but not tag attributes.
*
*
****************************************************************************/
#include "XMLParser.hpp"
/* Private classes */
enum XMLNodeType
{
xml_node,
xml_subtree
};
/* Abstract class. XMLTree and XMLNode is derived from this class */
class XMLAbstractNode
{
protected:
string name; // Name of this node.
XMLNodeType type;
public:
/* Constructor */
XMLAbstractNode( const string & _name, XMLNodeType _type );
/* Destructor */
~XMLAbstractNode();
/* Methods */
const string & getName();
XMLNodeType getType();
bool isName( const string & _name ); // Compare name to _name.
virtual void print() = 0;
};
/* Class describing a subtree, derived from XMLAbstractNode */
class XMLTree : public XMLAbstractNode
{
protected:
list<XMLAbstractNode *> nodes; // Nodes contained in this tree.
public:
/* Constructor */
XMLTree( const string & _name );
/* Destructor */
~XMLTree();
/* Methods */
void addNode( XMLAbstractNode * newnode );
bool containsNode( const string & _name ); // Searches for name in list.
XMLAbstractNode * getNode( const string & _name );
void print();
};
/* Class describing an ordinary string-valued node, derived from XMLAbstractNode */
class XMLNode : public XMLAbstractNode
{
protected:
string value; // String value.
public:
/* Constructor */
XMLNode( const string & _name, const string & _value );
/* Destructor */
~XMLNode();
/* Methods */
bool isEmpty(); // Contains an empty string?
const string & getValue();
void print();
};
void XMLFile::removeComments( string & txt )
{
long pos = 0; // Everything up to this point is clean.
long startFoundAt; // Comment start and end found at these positions.
long endFoundAt;
/* Search and remove all comment tags */
do
{
/* Search for comment start */
startFoundAt = txt.find( "<!--", pos );
/* Exit the search loop if no comment is found */
if( startFoundAt == string::npos )
{
pos = txt.size();
break;
}
/* Search for comment end */
endFoundAt = txt.find( "-->", startFoundAt );
/* Error if start but no end is found */
if( endFoundAt == string::npos )
throw new ErrorMsg( "Unclosed comment tag encountered! "
"Comment start-tag '<!--' found, but no "
"closing '-->'." );
/* Remove comment tag */
txt.erase( startFoundAt, endFoundAt - startFoundAt + 3 );
pos = startFoundAt; // Prepare for next search.
} while( pos < txt.size() );
}
void XMLFile::removeStartXML( string & txt )
{
long pos = 0; // Everything up to this point is clean.
long startFoundAt; // Comment start and end found at these positions.
long endFoundAt;
/* Search and remove the <?xml tag */
startFoundAt = txt.find( "<?xml", pos );
/* Exit the search loop if not found */
if( startFoundAt == string::npos )
{
pos = txt.size();
return;
}
/* Search for end */
endFoundAt = txt.find( ">", startFoundAt );
/* Remove tag */
txt.erase( startFoundAt, endFoundAt - startFoundAt );
}
void XMLFile::removeAttributes( string & txt )
{
long pos; // Everything up to this point is clean.
long startFoundAt; // Tag start and end found at these positions.
long endFoundAt;
long spaceFoundAt; // Space before attribute found at this position.
long slashFoundAt; // Ending slash found at this position.
/* Convert all whitespace to plain spaces, just to make things easier */
for( pos = 0; pos < txt.size(); pos++ )
{
if( txt[pos] == '\n' || txt[pos] == '\r' || txt[pos] == '\t' )
txt.replace( pos, 1, " " );
}
pos = 0;
/* Search and clean all tags */
do
{
/* Search for tag start */
startFoundAt = txt.find( "<", pos );
/* Exit loop if no tag is found */
if( startFoundAt == string::npos )
break;
/* Search for comment end */
endFoundAt = txt.find( ">", startFoundAt );
/* Error if start but no end is found */
if( endFoundAt == string::npos )
throw new ErrorMsg( "Unclosed tag encountered! "
"Tag start token '<' found, but not "
"closing '>'." );
/* Remove whitespace before tag name */
while( txt[startFoundAt+1] == ' ' )
{
txt.erase( startFoundAt+1, 1 ); // Remove.
endFoundAt--; // String has now shrunk.
}
/* Search for space before attributes */
spaceFoundAt = txt.find( " ", startFoundAt );
if( spaceFoundAt < endFoundAt && spaceFoundAt != string::npos ) // Space found inside tag?
{
// If empty tag, we dont want to remove the / in />
if ( txt.at(endFoundAt-1) == '/' )
{
endFoundAt--;
}
/* Remove attributes */
txt.erase( spaceFoundAt, endFoundAt - spaceFoundAt );
endFoundAt -= endFoundAt - spaceFoundAt; // String has now shrunk.
}
pos = endFoundAt + 1; // Prepare for next search.
} while( pos < txt.size() );
}
void XMLFile::readFile( const string & _filename )
{
ifstream f; // XML file stream.
string contents; // XML file contents.
string templine;
/* Attempt to open file */
f.open( _filename.c_str(), ios::in );
if( !f )
throw new ErrorMsg( "Error opening XML file for input!" );
/* Read everything into the contents string */
contents.erase();
templine.erase();
do
{
contents += templine + " ";
f >> templine; // This will cause EOF only when reading from the end.
} while( !f.eof() );
f.close();
/* Remove comments and tag attributes */
removeComments( contents );
removeAttributes( contents );
removeStartXML ( contents );
/* Create root node */
root = new XMLTree( "root" );
parseFragment( contents, root );
Util.progress( "\r\n" ); // Finish progress indicator.
}
void XMLFile::parseFragment( string & fragment, XMLTree * parent )
{
long startFoundAt; // Tag start and end found at these positions.
long endFoundAt;
string closingString; // Search string used for finding closing tag.
long closingFoundAt; // Closing tag found at this position.
string tagName; // These are for recently created nodes.
string tagValue;
XMLTree * newTree;
XMLNode * newNode;
long nestedFoundAt; // Nested tags found at this position.
/* Find top level tags */
Util.progress( "#" ); // Advance progress indicator.
while( true ) // Wait for break from inside.
{
/* Find start of tag */
startFoundAt = fragment.find( "<", 0 );
if( startFoundAt == string::npos ) // Exit loop if no tags found.
break;
/* Check if this is a closing tag for a higher level tag pair */
if( fragment[startFoundAt+1] == '/' )
break; // Exit loop.
/* Find end of tag */
endFoundAt = fragment.find( ">", startFoundAt );
if( endFoundAt == string::npos ) // Error if end not found.
throw new ErrorMsg( "Unclosed tag encountered! "
"Tag start token '<' found, but no "
"closing '>'." );
/* Extract name of tag */
tagName = fragment.substr( startFoundAt+1, endFoundAt-startFoundAt-1 );
if( tagName.size() == 0 ) // Error if zero-length tag name.
throw new ErrorMsg( "Unnamed tag encountered! "
"No text between '<' and '>'." );
/* Remove tag from fragment */
fragment.erase( 0, startFoundAt+tagName.size()+2 );
/* Check if it is an empty tag */
if( tagName[tagName.size()-1] == '/' )
{
/* Create a new empty ordinary node */
tagName.erase( tagName.size()-1 ); // Remove the slash.
tagValue.erase(); // This tag has no value.
newNode = new XMLNode( tagName, tagValue );
parent->addNode( newNode );
} else
{
/* Find the matching closing tag for this pair */
closingString.erase();
closingString += "</" + tagName + ">";
closingFoundAt = fragment.find( closingString, 0 );
if( closingFoundAt == string::npos ) // Error if not found.
throw new ErrorMsg( "Closing tag not found! "
"Opening tag '<" + tagName + ">' found, "
"but not closing '" + closingString + "'." );
/* Check for tags inside this tag pair, indicating a subtree */
nestedFoundAt = fragment.find( "<", 0 );
if( nestedFoundAt == closingFoundAt ) // No other tags inside?
{
/* Extract contents within tag pair */
tagValue = fragment.substr( 0, closingFoundAt );
/* Create new ordinary node */
newNode = new XMLNode( tagName, tagValue );
parent->addNode( newNode );
} else
{
/* Create new subtree and parse it's fragment */
newTree = new XMLTree( tagName );
parent->addNode( newTree );
parseFragment( fragment, newTree );
/* Check that we can still find the closing tag */
closingFoundAt = fragment.find( closingString, 0 );
if( closingFoundAt == string::npos )
throw new ErrorMsg( "Closing tag not found! "
"Opening tag '<" + tagName + ">' found, "
"but not closing '" + closingString + "'." );
}
/* Remove value and closing tag from fragment */
fragment.erase( 0, closingFoundAt + closingString.size() );
}
};
}
/* Constructor */
XMLFile::XMLFile( const string & _filename )
{
readFile( _filename );
}
/* Destructor */
XMLFile::~XMLFile()
{
if( root != NULL )
delete root;
}
bool XMLFile::exists( const string & path )
{
XMLAbstractNode * currentNode = root;
XMLTree * currentTree;
long namePos; // Position for current tag name in path.
long separatorPos; // Position for #-separator following tag name.
string tagName; // Current tag name.
namePos = 0;
while( true ) // This will break out from the inside.
{
/* Find separator or set pos to end of text */
separatorPos = path.find( "\\", namePos );
if( separatorPos == string::npos )
separatorPos = path.size();
/* Extract tag name and check if it exists */
tagName = path.substr( namePos, separatorPos-namePos );
currentTree = (XMLTree *) currentNode; // It is indeed a tree.
if( !currentTree->containsNode( tagName ) )
return false; // Not found.
currentNode = currentTree->getNode( tagName );
/* Are there more tags in the path? */
if( separatorPos < path.size() )
{
/* Now, the current node better be a tree */
if( currentNode->getType() != xml_subtree )
{
return false; // Not found.
} else
{
namePos = separatorPos + 1; // Advance position in path.
}
} else
{
break; // Found, exit loop.
}
}
return true; // Found!
}
const string & XMLFile::getValue( const string & path )
{
XMLAbstractNode * currentNode = root;
XMLTree * currentTree;
long namePos; // Position for current tag name in path.
long separatorPos; // Position for #-separator following tag name.
string tagName; // Current tag name.
namePos = 0;
while( true ) // This will break out from the inside.
{
/* Find separator or set pos to end of text */
separatorPos = path.find( "\\", namePos );
if( separatorPos == string::npos )
separatorPos = path.size();
/* Extract tag name and check if it exists */
tagName = path.substr( namePos, separatorPos-namePos );
currentTree = (XMLTree *) currentNode; // It is indeed a tree.
if( !currentTree->containsNode( tagName ) )
throw new ErrorMsg( "Node '" + tagName + "' not found!" );
currentNode = currentTree->getNode( tagName );
/* Are there more tags in the path? */
if( separatorPos < path.size() )
{
/* Now, the current node better be a tree */
if( currentNode->getType() != xml_subtree )
{
throw new ErrorMsg( "Illegal path: (" + path + ")!" );
} else
{
namePos = separatorPos + 1; // Advance position in path.
}
} else
{
break; // Found, exit loop.
}
}
/* Check that the current node is an ordinary node */
if( currentNode->getType() != xml_node )
throw new ErrorMsg( "Node '" + tagName + "' is not an element!" );
return ((XMLNode *) currentNode)->getValue();
}
void XMLFile::print()
{
root->print();
}
/* Constructor */
XMLAbstractNode::XMLAbstractNode( const string & _name, XMLNodeType _type ) :
name( _name ),
type( _type )
{
// Node code here.
}
/* Destructor */
XMLAbstractNode::~XMLAbstractNode()
{
// No code here.
}
const string & XMLAbstractNode::getName()
{
return name;
}
XMLNodeType XMLAbstractNode::getType()
{
return type;
}
bool XMLAbstractNode::isName( const string & _name )
{
return (name == _name);
}
/* Constructor */
XMLTree::XMLTree( const string & _name ) :
XMLAbstractNode::XMLAbstractNode( _name, xml_subtree )
{
// No code here.
}
/* Destructor */
XMLTree::~XMLTree()
{
/* Create an iterator for the list */
list<XMLAbstractNode *>::iterator i;
/* Destruct all contained nodes */
for( i = nodes.begin(); i != nodes.end(); i++ )
{
delete (*i);
}
}
void XMLTree::addNode( XMLAbstractNode * newnode )
{
nodes.push_back( newnode );
}
bool XMLTree::containsNode( const string & _name )
{
/* Create an iterator for the list */
list<XMLAbstractNode *>::iterator i;
/* Search for the node with name _name */
i = nodes.begin();
while( i != nodes.end() )
{
if( (*i)->isName( _name ) )
return true;
i++;
}
return false;
}
XMLAbstractNode * XMLTree::getNode( const string & _name )
{
/* Create an iterator for the list */
list<XMLAbstractNode *>::iterator i;
/* Search for the node with name _name */
i = nodes.begin();
while( i != nodes.end() )
{
if( (*i)->isName( _name ) )
return *i;
i++;
}
return NULL;
}
void XMLTree::print()
{
/* Create an iterator for the list */
list<XMLAbstractNode *>::iterator i;
cout << "TREE[ Name: \"" << name << "\" ]:" << endl;
/* Search for the node with name _name */
i = nodes.begin();
while( i != nodes.end() )
{
(*i)->print();
i++;
}
cout << ":END[\"" << name << "\"]" << endl;
}
/* Constructor */
XMLNode::XMLNode( const string & _name, const string & _value ) :
XMLAbstractNode::XMLAbstractNode( _name, xml_node ),
value( _value )
{
// No code here.
}
/* Destructor */
XMLNode::~XMLNode()
{
// Node code here.
}
bool XMLNode::isEmpty()
{
return value.empty();
}
const string & XMLNode::getValue()
{
return value;
}
void XMLNode::print()
{
cout << "NODE[ Name: \"" << name << "\" Value: \"" << value << "\" ]" << endl;
}
/* end of file */
+65
View File
@@ -0,0 +1,65 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : XMLParser.hpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 3419 $
* Date : $Date: 2008-02-22 09:56:34 +0100 (fr, 22 feb 2008) $
* Updated by : $Author: khole $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : A simple XML DOM-like parser. It builds a complete tree from
* the XML file. IT supports <section/> tags, but not tag attributes.
*
*
****************************************************************************/
#ifndef XMLPARSER_HPP
#define XMLPARSER_HPP
using namespace std;
#include "ErrorMsg.hpp"
#include "Utility.hpp"
#include <iostream>
#include <fstream>
#include <list>
class XMLAbstractNode; // Preliminary definitions.
class XMLTree;
class XMLNode;
/* Main XML file class. Contains search methods and entire XML tree */
class XMLFile
{
protected:
XMLTree * root; // The root node, either a subtree or an ordinary node.
void XMLFile::removeStartXML( string & txt ); // Remove the start xml tag.
void removeComments( string & txt ); // Remove comment tags.
void removeAttributes( string & txt ); // Remove attributes from tags.
void readFile( const string & _filename ); // Read XML file.
void parseFragment( string & fragment, XMLTree * parent );
public:
/* Constructors */
XMLFile( const string & _filename );
/* Destructor */
~XMLFile();
/* Methods */
bool exists( const string & path ); // Checks if node exists.
const string & getValue( const string & path ); // Get node value.
void print();
};
#endif
+47
View File
@@ -0,0 +1,47 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : main.cpp
* Compiler : Dev-C++ 4.9.8.0 - http://bloodshed.net/dev/
* Revision : $Revision: 1163 $
* Date : $Date: 2006-08-02 15:38:16 +0200 (on, 02 aug 2006) $
* Updated by : $Author: ohlia $
*
* Support mail : avr@atmel.com
*
* Target platform : Win32
*
* AppNote : AVR911 - AVR Open-source Programmer
*
* Description : AVROSP main entry function.
*
*
****************************************************************************/
#include "JobInfo.hpp"
#include <vector>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
JobInfo j;
try
{
j.parseCommandline( argc, argv );
j.doJob();
}
catch( ErrorMsg * e )
{
cout << endl << "An error occurred:" << endl;
cout << " [" << e->What() << "]" << endl;
delete e;
}
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
Made with the free Dev-C++ IDE
http://bloodshed.net/dev/
File diff suppressed because one or more lines are too long
+20
View File
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Atmel Studio Solution File, Format Version 11.00
Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "BACnet Development Kit", "bacnet.cproj", "{1CEFD571-4B50-48FD-B75E-0E968EBBD698}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|AVR = Debug|AVR
Release|AVR = Release|AVR
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1CEFD571-4B50-48FD-B75E-0E968EBBD698}.Debug|AVR.ActiveCfg = Debug|AVR
{1CEFD571-4B50-48FD-B75E-0E968EBBD698}.Debug|AVR.Build.0 = Debug|AVR
{1CEFD571-4B50-48FD-B75E-0E968EBBD698}.Release|AVR.ActiveCfg = Release|AVR
{1CEFD571-4B50-48FD-B75E-0E968EBBD698}.Release|AVR.Build.0 = Release|AVR
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+220
View File
@@ -0,0 +1,220 @@
/**************************************************************************
*
* Copyright (C) 2010 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 <stdbool.h>
/* hardware layer includes */
#include "hardware.h"
#include "timer.h"
#include "seeprom.h"
#include "nvdata.h"
#include "rs485.h"
#include "input.h"
#include "adc.h"
#include "led.h"
/* BACnet Stack includes */
#include "datalink.h"
#include "npdu.h"
#include "handlers.h"
#include "client.h"
#include "txbuf.h"
#include "dcc.h"
#include "iam.h"
#include "device.h"
#include "ai.h"
#include "av.h"
#include "bi.h"
#include "bo.h"
/* me */
#include "bacnet.h"
/* MAC Address of MS/TP */
static uint8_t MSTP_MAC_Address;
/* timer for device communications control */
static struct itimer DCC_Timer;
#define DCC_CYCLE_SECONDS 1
static bool seeprom_version_test(
void)
{
uint16_t version = 0;
uint16_t id = 0;
bool status = false;
int rv;
rv = seeprom_bytes_read(NV_SEEPROM_TYPE_0, (uint8_t *) & id, 2);
if (rv > 0) {
rv = seeprom_bytes_read(NV_SEEPROM_VERSION_0, (uint8_t *) & version,
2);
}
if ((rv > 0) && (id == SEEPROM_ID) && (version == SEEPROM_VERSION)) {
status = true;
} else if (rv > 0) {
version = SEEPROM_VERSION;
id = SEEPROM_ID;
seeprom_bytes_write(NV_SEEPROM_TYPE_0, (uint8_t *) & id, 2);
seeprom_bytes_write(NV_SEEPROM_VERSION_0, (uint8_t *) & version, 2);
} else {
while (1) {
/* SEEPROM is faulty! */
}
}
return status;
}
static void device_id_init(uint8_t mac)
{
uint32_t device_id = 0;
/* Get the device ID from the eeprom */
eeprom_bytes_read(NV_EEPROM_DEVICE_0, (uint8_t *) & device_id,
sizeof(device_id));
if (device_id < BACNET_MAX_INSTANCE) {
Device_Set_Object_Instance_Number(device_id);
} else {
/* use the DIP switch address as the Device ID if unconfigured */
Device_Set_Object_Instance_Number(MSTP_MAC_Address);
}
}
void bacnet_init(
void)
{
uint8_t max_master = 0;
MSTP_MAC_Address = input_address();
dlmstp_set_mac_address(MSTP_MAC_Address);
eeprom_bytes_read(NV_EEPROM_MAX_MASTER, &max_master, 1);
if (max_master > 127) {
max_master = 127;
}
dlmstp_set_max_master(max_master);
dlmstp_init(NULL);
/* test for valid data structure in SEEPROM */
if (!seeprom_version_test()) {
/* do something when SEEPROM is invalid - i.e. init to defaults */
}
/* initialize objects */
Device_Init(NULL);
device_id_init(MSTP_MAC_Address);
/* set up our confirmed service unrecognized service handler - required! */
apdu_set_unrecognized_service_handler_handler
(handler_unrecognized_service);
/* we need to handle who-is to support dynamic device binding */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_HAS, handler_who_has);
/* Set the handlers for any confirmed services that we support. */
/* We must implement read property - it's required! */
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROP_MULTIPLE,
handler_read_property_multiple);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
handler_reinitialize_device);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
handler_write_property);
/* handle communication so we can shutup when asked */
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control);
/* start the cyclic 1 second timer for DCC */
timer_interval_start_seconds(&DCC_Timer, DCC_CYCLE_SECONDS);
/* Hello World! */
Send_I_Am(&Handler_Transmit_Buffer[0]);
}
static uint8_t PDUBuffer[MAX_MPDU];
void bacnet_task(
void)
{
uint8_t mstp_mac_address;
uint16_t pdu_len;
BACNET_ADDRESS src; /* source address */
uint16_t value;
bool button_value;
uint8_t i;
BACNET_BINARY_PV binary_value = BINARY_INACTIVE;
BACNET_POLARITY polarity;
bool out_of_service;
mstp_mac_address = input_address();
if (MSTP_MAC_Address != mstp_mac_address) {
/* address changed! */
MSTP_MAC_Address = mstp_mac_address;
dlmstp_set_mac_address(MSTP_MAC_Address);
device_id_init(MSTP_MAC_Address);
Send_I_Am(&Handler_Transmit_Buffer[0]);
}
/* handle the inputs */
value = adc_result_10bit(7);
Analog_Input_Present_Value_Set(0, value);
for (i = 0; i < 5; i++) {
button_value = input_button_value(i);
if (button_value) {
binary_value = BINARY_ACTIVE;
} else {
binary_value = BINARY_INACTIVE;
}
Binary_Input_Present_Value_Set(i, binary_value);
}
/* Binary Output */
for (i = 0; i < 2; i++) {
out_of_service = Binary_Output_Out_Of_Service(i);
if (!out_of_service) {
binary_value = Binary_Output_Present_Value(i);
polarity = Binary_Output_Polarity(i);
if (polarity != POLARITY_NORMAL) {
if (binary_value == BINARY_ACTIVE) {
binary_value = BINARY_INACTIVE;
} else {
binary_value = BINARY_ACTIVE;
}
}
if (binary_value == BINARY_ACTIVE) {
if (i == 0) {
led_on(LED_2);
} else {
led_on(LED_3);
}
} else {
if (i == 0) {
led_off(LED_2);
} else {
led_off(LED_3);
}
}
}
}
/* handle the communication timer */
if (timer_interval_expired(&DCC_Timer)) {
timer_interval_reset(&DCC_Timer);
dcc_timer_seconds(DCC_CYCLE_SECONDS);
}
/* handle the messaging */
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
if (pdu_len) {
npdu_handler(&src, &PDUBuffer[0], pdu_len);
}
}
+355
View File
@@ -0,0 +1,355 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<ProjectVersion>6.1</ProjectVersion>
<ToolchainName>com.Atmel.AVRGCC8.C</ToolchainName>
<ProjectGuid>{1cefd571-4b50-48fd-b75e-0e968ebbd698}</ProjectGuid>
<avrdevice>ATmega644P</avrdevice>
<avrdeviceseries>none</avrdeviceseries>
<OutputType>Executable</OutputType>
<Language>C</Language>
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
<OutputFileExtension>.elf</OutputFileExtension>
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
<AssemblyName>BACnet Development Kit</AssemblyName>
<Name>BACnet Development Kit</Name>
<RootNamespace>BACnet Development Kit</RootNamespace>
<ToolchainFlavour>Native</ToolchainFlavour>
<KeepTimersRunning>true</KeepTimersRunning>
<OverrideVtor>false</OverrideVtor>
<OverrideVtorValue />
<eraseonlaunchrule>0</eraseonlaunchrule>
<ProgFlashFromRam>true</ProgFlashFromRam>
<RamSnippetAddress>0x20000000</RamSnippetAddress>
<CacheFlash>true</CacheFlash>
<UncachedRange />
<BootSegment>2</BootSegment>
<AsfFrameworkConfig>
<framework-data xmlns="">
<options />
<configurations />
<files />
<documentation help="" />
<offline-documentation help="" />
<dependencies>
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.8.1" />
</dependencies>
</framework-data>
</AsfFrameworkConfig>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ToolchainSettings>
<AvrGcc>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols><ListValues>
<Value>BACDL_MSTP</Value>
<Value>MAX_APDU=128</Value>
<Value>BIG_ENDIAN=0</Value>
<Value>MAX_TSM_TRANSACTIONS=0</Value>
<Value>MSTP_PDU_PACKET_COUNT=2</Value>
<Value>MAX_CHARACTER_STRING_BYTES=64</Value>
<Value>MAX_OCTET_STRING_BYTES=64</Value>
<Value>NDEBUG</Value>
</ListValues></avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths><ListValues>
<Value>..</Value>
<Value>../../../demo/object</Value>
<Value>../../../include</Value>
<Value>../../../ports/bdk-atxx4-mstp</Value>
</ListValues></avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.linker.libraries.Libraries><ListValues><Value>libm</Value></ListValues></avrgcc.linker.libraries.Libraries>
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
</AvrGcc>
</ToolchainSettings>
<UsesExternalMakeFile>False</UsesExternalMakeFile>
<BuildTarget>all</BuildTarget>
<CleanTarget>clean</CleanTarget>
<ExternalMakeFilePath>D:\code\bacnet-stack\ports\bdk-atxx4-mstp\Makefile</ExternalMakeFilePath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ToolchainSettings>
<AvrGcc>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols><ListValues>
<Value>BACDL_MSTP</Value>
<Value>MAX_APDU=128</Value>
<Value>BIG_ENDIAN=0</Value>
<Value>MAX_TSM_TRANSACTIONS=0</Value>
<Value>MSTP_PDU_PACKET_COUNT=2</Value>
<Value>MAX_CHARACTER_STRING_BYTES=64</Value>
<Value>MAX_OCTET_STRING_BYTES=64</Value>
<Value>DEBUG</Value>
</ListValues></avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths><ListValues><Value>..</Value><Value>../../../demo/object</Value><Value>../../../include</Value></ListValues></avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.linker.libraries.Libraries><ListValues><Value>libm</Value></ListValues></avrgcc.linker.libraries.Libraries>
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
<avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>
</AvrGcc>
</ToolchainSettings>
<UsesExternalMakeFile>False</UsesExternalMakeFile>
<BuildTarget>all</BuildTarget>
<CleanTarget>clean</CleanTarget>
<ExternalMakeFilePath>D:\code\bacnet-stack\ports\bdk-atxx4-mstp\Makefile</ExternalMakeFilePath>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\demo\handler\h_dcc.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\h_dcc.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\h_npdu.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\h_npdu.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\h_rd.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\h_rd.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\h_rp.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\h_rp.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\h_rpm.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\h_rpm.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\h_whohas.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\h_whohas.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\h_whois.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\h_whois.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\h_wp.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\h_wp.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\noserv.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\noserv.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\s_iam.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\s_iam.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\s_ihave.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\s_ihave.c</Link>
</Compile>
<Compile Include="..\..\demo\handler\txbuf.c">
<SubType>compile</SubType>
<Link>BACnet Handlers\txbuf.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\adc.c">
<SubType>compile</SubType>
<Link>adc.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\ai.c">
<SubType>compile</SubType>
<Link>ai.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\av.c">
<SubType>compile</SubType>
<Link>av.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\bacnet.c">
<SubType>compile</SubType>
<Link>bacnet.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\bi.c">
<SubType>compile</SubType>
<Link>bi.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\bname.c">
<SubType>compile</SubType>
<Link>bname.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\bo.c">
<SubType>compile</SubType>
<Link>bo.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\device.c">
<SubType>compile</SubType>
<Link>device.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\dlmstp.c">
<SubType>compile</SubType>
<Link>dlmstp.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\eeprom.c">
<SubType>compile</SubType>
<Link>eeprom.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\fuses.c">
<SubType>compile</SubType>
<Link>fuses.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\init.c">
<SubType>compile</SubType>
<Link>init.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\input.c">
<SubType>compile</SubType>
<Link>input.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\led.c">
<SubType>compile</SubType>
<Link>led.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\main.c">
<SubType>compile</SubType>
<Link>main.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\rs485.c">
<SubType>compile</SubType>
<Link>rs485.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\seeprom.c">
<SubType>compile</SubType>
<Link>seeprom.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\serial.c">
<SubType>compile</SubType>
<Link>serial.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\stack.c">
<SubType>compile</SubType>
<Link>stack.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\test.c">
<SubType>compile</SubType>
<Link>test.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\timer.c">
<SubType>compile</SubType>
<Link>timer.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\timer2.c">
<SubType>compile</SubType>
<Link>timer2.c</Link>
</Compile>
<Compile Include="..\..\ports\bdk-atxx4-mstp\watchdog.c">
<SubType>compile</SubType>
<Link>watchdog.c</Link>
</Compile>
<Compile Include="..\..\src\abort.c">
<SubType>compile</SubType>
<Link>BACnet Core\abort.c</Link>
</Compile>
<Compile Include="..\..\src\apdu.c">
<SubType>compile</SubType>
<Link>BACnet Core\apdu.c</Link>
</Compile>
<Compile Include="..\..\src\bacaddr.c">
<SubType>compile</SubType>
<Link>BACnet Core\bacaddr.c</Link>
</Compile>
<Compile Include="..\..\src\bacapp.c">
<SubType>compile</SubType>
<Link>BACnet Core\bacapp.c</Link>
</Compile>
<Compile Include="..\..\src\bacdcode.c">
<SubType>compile</SubType>
<Link>BACnet Core\bacdcode.c</Link>
</Compile>
<Compile Include="..\..\src\bacerror.c">
<SubType>compile</SubType>
<Link>BACnet Core\bacerror.c</Link>
</Compile>
<Compile Include="..\..\src\bacint.c">
<SubType>compile</SubType>
<Link>BACnet Core\bacint.c</Link>
</Compile>
<Compile Include="..\..\src\bacreal.c">
<SubType>compile</SubType>
<Link>BACnet Core\bacreal.c</Link>
</Compile>
<Compile Include="..\..\src\bacstr.c">
<SubType>compile</SubType>
<Link>BACnet Core\bacstr.c</Link>
</Compile>
<Compile Include="..\..\src\crc.c">
<SubType>compile</SubType>
<Link>BACnet Core\crc.c</Link>
</Compile>
<Compile Include="..\..\src\dcc.c">
<SubType>compile</SubType>
<Link>BACnet Core\dcc.c</Link>
</Compile>
<Compile Include="..\..\src\fifo.c">
<SubType>compile</SubType>
<Link>BACnet Core\fifo.c</Link>
</Compile>
<Compile Include="..\..\src\iam.c">
<SubType>compile</SubType>
<Link>BACnet Core\iam.c</Link>
</Compile>
<Compile Include="..\..\src\ihave.c">
<SubType>compile</SubType>
<Link>BACnet Core\ihave.c</Link>
</Compile>
<Compile Include="..\..\src\memcopy.c">
<SubType>compile</SubType>
<Link>BACnet Core\memcopy.c</Link>
</Compile>
<Compile Include="..\..\src\npdu.c">
<SubType>compile</SubType>
<Link>BACnet Core\npdu.c</Link>
</Compile>
<Compile Include="..\..\src\rd.c">
<SubType>compile</SubType>
<Link>BACnet Core\rd.c</Link>
</Compile>
<Compile Include="..\..\src\reject.c">
<SubType>compile</SubType>
<Link>BACnet Core\reject.c</Link>
</Compile>
<Compile Include="..\..\src\ringbuf.c">
<SubType>compile</SubType>
<Link>BACnet Core\ringbuf.c</Link>
</Compile>
<Compile Include="..\..\src\rp.c">
<SubType>compile</SubType>
<Link>BACnet Core\rp.c</Link>
</Compile>
<Compile Include="..\..\src\rpm.c">
<SubType>compile</SubType>
<Link>BACnet Core\rpm.c</Link>
</Compile>
<Compile Include="..\..\src\whohas.c">
<SubType>compile</SubType>
<Link>BACnet Core\whohas.c</Link>
</Compile>
<Compile Include="..\..\src\whois.c">
<SubType>compile</SubType>
<Link>BACnet Core\whois.c</Link>
</Compile>
<Compile Include="..\..\src\wp.c">
<SubType>compile</SubType>
<Link>BACnet Core\wp.c</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="BACnet Handlers" />
<Folder Include="BACnet Core" />
</ItemGroup>
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
</Project>
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<workspace>
<project>
<path>$WS_DIR$\bacnet.ewp</path>
</project>
<batchBuild/>
</workspace>
+41
View File
@@ -0,0 +1,41 @@
/**************************************************************************
*
* Copyright (C) 2010 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 BACNET_H
#define BACNET_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void bacnet_init(
void);
void bacnet_task(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+82
View File
@@ -0,0 +1,82 @@
<!DOCTYPE CrossStudio_Project_File>
<solution Name="bacnet" version="2">
<project Name="bacnet">
<configuration Name="Common" Platform="AVR" Target="ATmega644P" avr_architecture="V2E" avr_debug_interface="JTAG" avr_flash_size="128K" build_use_hardware_multiplier="Yes" c_preprocessor_definitions="BACDL_MSTP;MAX_APDU=128;BIG_ENDIAN=0;MAX_TSM_TRANSACTIONS=0;MAX_CHARACTER_STRING_BYTES=64;MAX_OCTET_STRING_BYTES=64;BACAPP_BOOLEAN;BACAPP_REAL;BACAPP_OBJECT_ID;BACAPP_UNSIGNED;BACAPP_ENUMERATED;BACAPP_CHARACTER_STRING;WRITE_PROPERTY" c_user_include_directories="$(ProjectDir);$(ProjectDir)/crossworks;$(ProjectDir)/../../include;$(ProjectDir)/../../demo/handler;$(ProjectDir)/../../demo/object" linker_call_stack_size="1024" linker_memory_map_file="$(PackagesDir)/targets/avr/ATmega644P.xml" project_directory="" project_type="Executable"/>
<folder Name="Source Files">
<configuration Name="Common" filter="c;h;s;asm;inc;s90"/>
<file file_name="adc.c">
<configuration Name="Common" c_user_include_directories="."/>
</file>
<file file_name="ai.c"/>
<file file_name="av.c"/>
<file file_name="bacnet.c"/>
<file file_name="bi.c"/>
<file file_name="bname.c"/>
<file file_name="bo.c"/>
<file file_name="device.c"/>
<file file_name="dlmstp.c"/>
<file file_name="eeprom.c"/>
<file file_name="init.c"/>
<file file_name="input.c"/>
<file file_name="led.c"/>
<file file_name="main.c"/>
<file file_name="rs485.c"/>
<file file_name="seeprom.c"/>
<file file_name="serial.c"/>
<file file_name="stack.c"/>
<file file_name="test.c"/>
<file file_name="timer2.c"/>
<file file_name="timer.c"/>
<file file_name="watchdog.c"/>
</folder>
<folder Name="System Files" file_name="">
<configuration Name="Common" filter="xml"/>
<file file_name="$(StudioDir)/src/crt0.asm"/>
</folder>
<folder Name="BACnet - default handlers">
<file file_name="../../demo/handler/h_dcc.c"/>
<file file_name="../../demo/handler/h_npdu.c"/>
<file file_name="../../demo/handler/h_rd.c"/>
<file file_name="../../demo/handler/h_rp.c"/>
<file file_name="../../demo/handler/h_rpm.c"/>
<file file_name="../../demo/handler/h_whohas.c"/>
<file file_name="../../demo/handler/h_whois.c"/>
<file file_name="../../demo/handler/h_wp.c"/>
<file file_name="../../demo/handler/noserv.c"/>
<file file_name="../../demo/handler/s_iam.c"/>
<file file_name="../../demo/handler/s_ihave.c"/>
<file file_name="../../demo/handler/txbuf.c"/>
</folder>
<folder Name="BACnet - core">
<file file_name="../../src/abort.c"/>
<file file_name="../../src/apdu.c"/>
<file file_name="../../src/bacaddr.c"/>
<file file_name="../../src/bacapp.c"/>
<file file_name="../../src/bacdcode.c"/>
<file file_name="../../src/bacerror.c"/>
<file file_name="../../src/bacint.c"/>
<file file_name="../../src/bacreal.c"/>
<file file_name="../../src/bacstr.c"/>
<file file_name="../../src/crc.c"/>
<file file_name="../../src/dcc.c"/>
<file file_name="../../src/fifo.c"/>
<file file_name="../../src/iam.c"/>
<file file_name="../../src/ihave.c"/>
<file file_name="../../src/memcopy.c"/>
<file file_name="../../src/npdu.c"/>
<file file_name="../../src/rd.c"/>
<file file_name="../../src/reject.c"/>
<file file_name="../../src/ringbuf.c"/>
<file file_name="../../src/rp.c"/>
<file file_name="../../src/rpm.c"/>
<file file_name="../../src/whohas.c"/>
<file file_name="../../src/whois.c"/>
<file file_name="../../src/wp.c"/>
</folder>
</project>
<configuration Name="AVR Debug" inherited_configurations="AVR;Debug"/>
<configuration Name="AVR" Platform="AVR" hidden="Yes"/>
<configuration Name="Debug" build_debug_information="Yes" hidden="Yes"/>
<configuration Name="AVR Release" inherited_configurations="AVR;Release"/>
<configuration Name="Release" build_debug_information="No" c_preprocessor_definitions="NDEBUG" hidden="Yes" optimize_block_locality="Yes" optimize_copy_propagation="Yes" optimize_cross_calling="Standard" optimize_cross_jumping="Yes" optimize_dead_code="Yes" optimize_jump_chaining="Yes" optimize_jump_threading="Yes" optimize_tail_merging="Yes"/>
</solution>
+245
View File
@@ -0,0 +1,245 @@
/**************************************************************************
*
* 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 "bi.h"
#include "handlers.h"
#ifndef MAX_BINARY_INPUTS
#define MAX_BINARY_INPUTS 5
#endif
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Binary_Input_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_POLARITY,
-1
};
static const int Binary_Input_Properties_Optional[] = {
-1
};
static const int Binary_Input_Properties_Proprietary[] = {
-1
};
void Binary_Input_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired) {
*pRequired = Binary_Input_Properties_Required;
}
if (pOptional) {
*pOptional = Binary_Input_Properties_Optional;
}
if (pProprietary) {
*pProprietary = Binary_Input_Properties_Proprietary;
}
return;
}
void Binary_Input_Init(
void)
{
unsigned i;
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;
index = Binary_Input_Instance_To_Index(object_instance);
if (index < MAX_BINARY_INPUTS) {
value = Present_Value[index];
}
return value;
}
bool Binary_Input_Present_Value_Set(
uint32_t object_instance,
BACNET_BINARY_PV value)
{
unsigned index = 0;
index = Binary_Input_Instance_To_Index(object_instance);
if (index < MAX_BINARY_INPUTS) {
Present_Value[index] = value;
return true;
}
return false;
}
bool Binary_Input_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32]; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_INPUTS) {
sprintf(text_string, "BI-%lu", object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* 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 = { 0 };
BACNET_POLARITY polarity = POLARITY_NORMAL;
BACNET_BINARY_PV value = BINARY_INACTIVE;
BACNET_CHARACTER_STRING char_string = { 0 };
uint8_t *apdu = NULL;
if ((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], rpdata->object_type,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Binary_Input_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], rpdata->object_type);
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 = BACNET_STATUS_ERROR;
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 = BACNET_STATUS_ERROR;
}
return apdu_len;
}
+206
View File
@@ -0,0 +1,206 @@
/**************************************************************************
*
* Copyright (C) 2011 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 <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "hardware.h"
#include "bacdef.h"
#include "bacdcode.h"
#include "bacstr.h"
#include "nvdata.h"
#include "seeprom.h"
#include "device.h"
#include "bname.h"
static bool bacnet_name_isvalid(
uint8_t encoding,
uint8_t length,
char *str)
{
bool valid = false;
if ((encoding < MAX_CHARACTER_STRING_ENCODING) &&
(length <= NV_EEPROM_NAME_SIZE)) {
if (encoding == CHARACTER_UTF8) {
valid = utf8_isvalid(str, length);
} else {
valid = true;
}
}
return valid;
}
bool bacnet_name_save(
uint16_t offset,
uint8_t encoding,
char *str,
uint8_t length)
{
uint8_t buffer[NV_EEPROM_NAME_SIZE] = { 0 };
uint8_t i = 0;
if (bacnet_name_isvalid(encoding, length, str)) {
eeprom_bytes_write(NV_EEPROM_NAME_LENGTH(offset), &length, 1);
eeprom_bytes_write(NV_EEPROM_NAME_ENCODING(offset),
(uint8_t *) & encoding, 1);
for (i = 0; i < length; i++) {
buffer[i] = str[i];
}
eeprom_bytes_write(NV_EEPROM_NAME_STRING(offset), &buffer[0],
NV_EEPROM_NAME_SIZE);
return true;
}
return false;
}
bool bacnet_name_set(
uint16_t offset,
BACNET_CHARACTER_STRING * char_string)
{
uint8_t encoding = 0;
uint8_t length = 0;
char *str = NULL;
length = characterstring_length(char_string);
encoding = characterstring_encoding(char_string);
str = characterstring_value(char_string);
return bacnet_name_save(offset, encoding, str, length);
}
bool bacnet_name_write_unique(
uint16_t offset,
int object_type,
uint32_t object_instance,
BACNET_CHARACTER_STRING * char_string,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
{
bool status = false;
size_t length = 0;
uint8_t encoding = 0;
int duplicate_type = 0;
uint32_t duplicate_instance = 0;
length = characterstring_length(char_string);
if (length < 1) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
} else if (length <= NV_EEPROM_NAME_SIZE) {
encoding = characterstring_encoding(char_string);
if (encoding < MAX_CHARACTER_STRING_ENCODING) {
if (Device_Valid_Object_Name(char_string, &duplicate_type,
&duplicate_instance)) {
if ((duplicate_type == object_type) &&
(duplicate_instance == object_instance)) {
/* writing same name to same object */
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_DUPLICATE_NAME;
}
} else {
status = bacnet_name_set(offset, char_string);
if (status) {
Device_Inc_Database_Revision();
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
}
return status;
}
/* no required minumum length or duplicate checking */
bool bacnet_name_write(
uint16_t offset,
BACNET_CHARACTER_STRING * char_string,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code)
{
bool status = false;
size_t length = 0;
uint8_t encoding = 0;
length = characterstring_length(char_string);
if (length <= NV_EEPROM_NAME_SIZE) {
encoding = characterstring_encoding(char_string);
if (encoding < MAX_CHARACTER_STRING_ENCODING) {
status = bacnet_name_set(offset, char_string);
if (!status) {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
}
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
}
return status;
}
void bacnet_name_init(
uint16_t offset,
char *default_string)
{
(void) bacnet_name_save(offset, CHARACTER_UTF8, default_string,
strlen(default_string));
}
void bacnet_name(
uint16_t offset,
BACNET_CHARACTER_STRING * char_string,
char *default_string)
{
uint8_t encoding = 0;
uint8_t length = 0;
char name[NV_EEPROM_NAME_SIZE + 1] = "";
eeprom_bytes_read(NV_EEPROM_NAME_ENCODING(offset), &encoding, 1);
eeprom_bytes_read(NV_EEPROM_NAME_LENGTH(offset), &length, 1);
eeprom_bytes_read(NV_EEPROM_NAME_STRING(offset), (uint8_t *) & name,
NV_EEPROM_NAME_SIZE);
if (bacnet_name_isvalid(encoding, length, name)) {
characterstring_init(char_string, encoding, &name[0], length);
} else if (default_string) {
bacnet_name_init(offset, default_string);
characterstring_init_ansi(char_string, default_string);
}
}
+66
View File
@@ -0,0 +1,66 @@
/**************************************************************************
*
* Copyright (C) 2010 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 BACNET_NAME_H
#define BACNET_NAME_H
#include <stdint.h>
#include "bacstr.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
bool bacnet_name_set(
uint16_t eeprom_offset,
BACNET_CHARACTER_STRING * char_string);
void bacnet_name_init(
uint16_t eeprom_offset,
char *default_string);
bool bacnet_name_save(
uint16_t offset,
uint8_t encoding,
char *str,
uint8_t length);
void bacnet_name(
uint16_t eeprom_offset,
BACNET_CHARACTER_STRING * char_string,
char *default_string);
bool bacnet_name_write_unique(
uint16_t offset,
int object_type,
uint32_t object_instance,
BACNET_CHARACTER_STRING * char_string,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code);
/* no required minumum length or duplicate checking */
bool bacnet_name_write(
uint16_t offset,
BACNET_CHARACTER_STRING * char_string,
BACNET_ERROR_CLASS * error_class,
BACNET_ERROR_CODE * error_code);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+557
View File
@@ -0,0 +1,557 @@
/**************************************************************************
*
* Copyright (C) 2009 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 Output 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 "hardware.h"
#include "led.h"
#include "nvdata.h"
#include "bo.h"
#include "handlers.h"
#ifndef MAX_BINARY_OUTPUTS
#define MAX_BINARY_OUTPUTS 2
#endif
/* When all the priorities are level null, the present value returns */
/* the Relinquish Default value */
#define RELINQUISH_DEFAULT BINARY_INACTIVE
/* Here is our Priority Array.*/
static uint8_t Binary_Output_Level[MAX_BINARY_OUTPUTS][BACNET_MAX_PRIORITY];
/* Writable out-of-service allows others to play with our Present Value */
/* without changing the physical output */
static uint8_t Out_Of_Service[MAX_BINARY_OUTPUTS];
/* polarity - normal or inverse */
static uint8_t Polarity[MAX_BINARY_OUTPUTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Binary_Output_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_POLARITY,
PROP_PRIORITY_ARRAY,
PROP_RELINQUISH_DEFAULT,
-1
};
static const int Binary_Output_Properties_Optional[] = {
PROP_ACTIVE_TEXT,
PROP_INACTIVE_TEXT,
-1
};
static const int Binary_Output_Properties_Proprietary[] = {
-1
};
void Binary_Output_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Binary_Output_Properties_Required;
if (pOptional)
*pOptional = Binary_Output_Properties_Optional;
if (pProprietary)
*pProprietary = Binary_Output_Properties_Proprietary;
return;
}
/* we simply have 0-n object instances. */
bool Binary_Output_Valid_Instance(
uint32_t object_instance)
{
if (object_instance < MAX_BINARY_OUTPUTS)
return true;
return false;
}
/* we simply have 0-n object instances. */
unsigned Binary_Output_Count(
void)
{
return MAX_BINARY_OUTPUTS;
}
/* we simply have 0-n object instances. */
uint32_t Binary_Output_Index_To_Instance(
unsigned index)
{
return index;
}
/* we simply have 0-n object instances. */
unsigned Binary_Output_Instance_To_Index(
uint32_t object_instance)
{
unsigned index = MAX_BINARY_OUTPUTS;
if (object_instance < MAX_BINARY_OUTPUTS)
index = object_instance;
return index;
}
static BACNET_BINARY_PV Present_Value(
unsigned int index)
{
BACNET_BINARY_PV value = RELINQUISH_DEFAULT;
BACNET_BINARY_PV current_value = RELINQUISH_DEFAULT;
unsigned i = 0;
if (index < MAX_BINARY_OUTPUTS) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
current_value = (BACNET_BINARY_PV) Binary_Output_Level[index][i];
if (current_value != BINARY_NULL) {
value = (BACNET_BINARY_PV) Binary_Output_Level[index][i];
break;
}
}
}
return value;
}
BACNET_BINARY_PV Binary_Output_Present_Value(
uint32_t object_instance)
{
unsigned index = 0;
index = Binary_Output_Instance_To_Index(object_instance);
return Present_Value(index);
}
bool Binary_Output_Present_Value_Set(
uint32_t instance,
BACNET_BINARY_PV binary_value,
unsigned priority)
{ /* 0..15 */
bool status = false;
if (instance < MAX_BINARY_OUTPUTS) {
if (priority < BACNET_MAX_PRIORITY) {
Binary_Output_Level[instance][priority] = (uint8_t) binary_value;
seeprom_bytes_write(NV_SEEPROM_BINARY_OUTPUT(instance,
NV_SEEPROM_BO_PRIORITY_ARRAY_1 + priority),
&Binary_Output_Level[instance][priority], 1);
status = true;
}
}
return status;
}
bool Binary_Output_Polarity_Set(
uint32_t instance,
BACNET_POLARITY polarity)
{
bool status = false;
if (instance < MAX_BINARY_OUTPUTS) {
if (polarity < MAX_POLARITY) {
Polarity[instance] = polarity;
seeprom_bytes_write(NV_SEEPROM_BINARY_OUTPUT(instance,
NV_SEEPROM_BO_POLARITY), &Polarity[instance], 1);
status = true;
}
}
return status;
}
BACNET_POLARITY Binary_Output_Polarity(
uint32_t instance)
{
BACNET_POLARITY polarity = POLARITY_NORMAL;
if (instance < MAX_BINARY_OUTPUTS) {
polarity = (BACNET_POLARITY) Polarity[instance];
}
return polarity;
}
void Binary_Output_Out_Of_Service_Set(
uint32_t instance,
bool flag)
{
if (instance < MAX_BINARY_OUTPUTS) {
Out_Of_Service[instance] = flag;
seeprom_bytes_write(NV_SEEPROM_BINARY_OUTPUT(instance,
NV_SEEPROM_BO_OUT_OF_SERVICE), &Out_Of_Service[instance], 1);
}
}
bool Binary_Output_Out_Of_Service(
uint32_t instance)
{
bool flag = false;
if (instance < MAX_BINARY_OUTPUTS) {
flag = Out_Of_Service[instance];
}
return flag;
}
/* note: the object name must be unique within this device */
bool Binary_Output_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
static char text_string[32]; /* okay for single thread */
bool status = false;
if (object_instance < MAX_BINARY_OUTPUTS) {
sprintf(text_string, "BO-%lu", object_instance);
status = characterstring_init_ansi(object_name, text_string);
}
return status;
}
/* return apdu len, or -1 on error */
int Binary_Output_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int len = 0;
int apdu_len = 0; /* return value */
BACNET_BIT_STRING bit_string = { 0 };
BACNET_CHARACTER_STRING char_string = { 0 };
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
unsigned object_index = 0;
unsigned i = 0;
bool state = false;
uint8_t *apdu = NULL;
if ((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], rpdata->object_type,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Binary_Output_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], rpdata->object_type);
break;
case PROP_PRESENT_VALUE:
present_value =
Binary_Output_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:
object_index =
Binary_Output_Instance_To_Index(rpdata->object_instance);
state = Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_POLARITY:
object_index =
Binary_Output_Instance_To_Index(rpdata->object_instance);
apdu_len =
encode_application_enumerated(&apdu[0],
Polarity[object_index]);
break;
case PROP_PRIORITY_ARRAY:
/* Array element zero is the number of elements in the array */
if (rpdata->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 (rpdata->array_index == BACNET_ARRAY_ALL) {
object_index =
Binary_Output_Instance_To_Index(rpdata->object_instance);
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
/* FIXME: check if we have room before adding it to APDU */
present_value = (BACNET_BINARY_PV)
Binary_Output_Level[object_index][i];
if (present_value == BINARY_NULL) {
len = encode_application_null(&apdu[apdu_len]);
} else {
len =
encode_application_enumerated(&apdu[apdu_len],
present_value);
}
/* add it if we have room */
if ((apdu_len + len) < MAX_APDU)
apdu_len += len;
else {
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
}
} else {
object_index =
Binary_Output_Instance_To_Index(rpdata->object_instance);
if (rpdata->array_index <= BACNET_MAX_PRIORITY) {
present_value = (BACNET_BINARY_PV)
Binary_Output_Level[object_index][rpdata->array_index -
1];
if (present_value == BINARY_NULL) {
apdu_len = encode_application_null(&apdu[apdu_len]);
} else {
apdu_len =
encode_application_enumerated(&apdu[apdu_len],
present_value);
}
} else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_RELINQUISH_DEFAULT:
present_value = RELINQUISH_DEFAULT;
apdu_len = encode_application_enumerated(&apdu[0], present_value);
break;
case PROP_ACTIVE_TEXT:
characterstring_init_ansi(&char_string, "on");
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_INACTIVE_TEXT:
characterstring_init_ansi(&char_string, "off");
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
default:
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) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(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 Binary_Output_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value */
unsigned int priority = 0;
BACNET_BINARY_PV level = BINARY_NULL;
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
/* 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:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
&wp_data->error_class, &wp_data->error_code);
if (status) {
priority = wp_data->priority;
/* Command priority 6 is reserved for use by Minimum On/Off
algorithm and may not be used for other purposes in any
object. */
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
(priority != 6 /* reserved */ ) &&
(value.type.Enumerated <= MAX_BINARY_PV)) {
level = (BACNET_BINARY_PV) value.type.Enumerated;
priority--;
Binary_Output_Present_Value_Set(wp_data->object_instance,
level, priority);
} 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. */
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
} else {
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_NULL,
&wp_data->error_class, &wp_data->error_code);
if (status) {
level = BINARY_NULL;
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Binary_Output_Present_Value_Set
(wp_data->object_instance, level, priority);
} else if (priority == 6) {
status = false;
/* 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 {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
}
break;
case PROP_OUT_OF_SERVICE:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_BOOLEAN,
&wp_data->error_class, &wp_data->error_code);
if (status) {
Binary_Output_Out_Of_Service_Set(wp_data->object_instance,
value.type.Boolean);
}
break;
case PROP_POLARITY:
status =
WPValidateArgType(&value, BACNET_APPLICATION_TAG_ENUMERATED,
&wp_data->error_class, &wp_data->error_code);
if (status) {
if (value.type.Enumerated < MAX_POLARITY) {
Binary_Output_Polarity_Set(wp_data->object_instance,
(BACNET_POLARITY) value.type.Enumerated);
} else {
status = false;
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
}
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_STATUS_FLAGS:
case PROP_EVENT_STATE:
case PROP_PRIORITY_ARRAY:
case PROP_RELINQUISH_DEFAULT:
case PROP_ACTIVE_TEXT:
case PROP_INACTIVE_TEXT:
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;
}
/* not using len at this time */
len = len;
return status;
}
void Binary_Output_Init(
void)
{
unsigned i, j;
/* initialize all the analog output priority arrays, polarity, and
out-of-service properties. */
for (i = 0; i < MAX_BINARY_OUTPUTS; i++) {
seeprom_bytes_read(NV_SEEPROM_BINARY_OUTPUT(i, NV_SEEPROM_BO_POLARITY),
&Polarity[i], 1);
if (Polarity[i] >= MAX_POLARITY) {
Binary_Output_Polarity_Set(i, POLARITY_NORMAL);
}
seeprom_bytes_read(NV_SEEPROM_BINARY_OUTPUT(i,
NV_SEEPROM_BO_OUT_OF_SERVICE), &Out_Of_Service[i], 1);
if (Out_Of_Service[i] > 1) {
Binary_Output_Out_Of_Service_Set(i, false);
}
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
seeprom_bytes_read(NV_SEEPROM_BINARY_OUTPUT(i,
NV_SEEPROM_BO_PRIORITY_ARRAY_1 + j),
&Binary_Output_Level[i][j], 1);
}
}
return;
}
+245
View File
@@ -0,0 +1,245 @@
# Hey Emacs, this is a -*- makefile -*-
# AVR-GCC Makefile template, derived from the WinAVR template (which
# is public domain), believed to be neutral to any flavor of "make"
# (GNU make, BSD make, SysV make)
MCU = atmega644p
FORMAT = ihex
TARGET = bootloader
SRC = main.c serial.c
ASRC =
OPT = s
BASEADDR = 0xF800
# Name of this Makefile (used for "make depend").
MAKEFILE = Makefile
# Debugging format.
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
DEBUG = stabs
# Compiler flag to set the C Standard level.
# c89 - "ANSI" C
# gnu89 - c89 plus GCC extensions
# c99 - ISO C99 standard (not yet fully implemented)
# gnu99 - c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here
CDEFS =
#CDEFS += -DREMOVE_FLASH_BYTE_SUPPORT
#CDEFS += -DREMOVE_EEPROM_BYTE_SUPPORT
#CDEFS += -DREMOVE_FUSE_AND_LOCK_BIT_SUPPORT
#CDEFS += -DREMOVE_AVRPROG_SUPPORT
#CDEFS += -DREMOVE_BLOCK_SUPPORT
# Place -I options here
CINCS =
CDEBUG = -g$(DEBUG)
CWARN = -Wall -Wstrict-prototypes
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CTUNING) $(CEXTRA)
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
#Additional libraries.
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
PRINTF_LIB =
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
SCANF_LIB =
MATH_LIB = -lm
# External memory options
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref
LDFLAGS = -Ttext=$(BASEADDR) $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
# Programming support using avrdude. Settings and variables.
# jtag2fast = Atmel JTAG ICE mkII, running at 115200 Bd
# jtag2slow = Atmel JTAG ICE mkII, running at 19200 Bd
# avrispmkII = AVR ISP MKII
#AVRDUDE_PROGRAMMER = jtag2fast
AVRDUDE_PROGRAMMER = avrispmkII
#AVRDUDE_PROGRAMMER = dragon_isp
#AVRDUDE_PROGRAMMER = dragon_jtag
#
# # port--serial or parallel port to which your
# # hardware programmer is attached
# # usb can just be usb
# # /dev/ttya
AVRDUDE_PORT = usb
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
# Disable auto-erase so that the chip can be initially
# programmed with application code, with the bootloader code added second
AVRDUDE_AUTOERASE = -D
AVRDUDE_BASIC = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS = $(AVRDUDE_BASIC)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
AVRDUDE_FLAGS += $(AVRDUDE_AUTOERASE)
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
MV = mv -f
# Define all object files.
OBJ = $(SRC:.c=.o) $(ASRC:.S=.o)
# Define all listing files.
LST = $(ASRC:.S=.lst) $(SRC:.c=.lst)
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: build
build: elf hex eep
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
# Program the device.
install: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT=$(OBJCOPY) --debugging \
--change-section-address .data-0x800000 \
--change-section-address .bss-0x800000 \
--change-section-address .noinit-0x800000 \
--change-section-address .eeprom-0x810000
coff: $(TARGET).elf
$(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof
extcoff: $(TARGET).elf
$(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof
.SUFFIXES: .elf .hex .eep .lss .sym
.elf.hex:
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
.elf.eep:
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
# Create extended listing file from ELF output file.
.elf.lss:
$(OBJDUMP) -h -S $< > $@
# Create a symbol table from ELF output file.
.elf.sym:
$(NM) -n $< > $@
# Link: create ELF output file from object files.
$(TARGET).elf: $(OBJ)
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
.c.o:
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C source files.
.c.s:
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
.S.o:
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Target: clean project.
clean:
$(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \
$(TARGET).map $(TARGET).sym $(TARGET).lss \
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d)
depend:
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
then \
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
$(MAKEFILE).$$$$ && \
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
fi
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
>> $(MAKEFILE); \
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE)
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend
@@ -0,0 +1 @@
<AVRStudio><MANAGEMENT><ProjectName>bootloader</ProjectName><Created>27-May-2009 06:28:56</Created><LastEdit>27-May-2009 06:28:56</LastEdit><ICON>241</ICON><ProjectType>0</ProjectType><Created>27-May-2009 06:28:56</Created><Version>4</Version><Build>4, 15, 0, 623</Build><ProjectTypeName>AVR GCC</ProjectTypeName></MANAGEMENT><CODE_CREATION><ObjectFile></ObjectFile><EntryFile></EntryFile><SaveFolder>D:\code\bacnet-stack\ports\bdk-atxx4-mstp\bootloader\</SaveFolder></CODE_CREATION><DEBUG_TARGET><CURRENT_TARGET>JTAGICE mkII</CURRENT_TARGET><CURRENT_PART>ATmega644P.xml</CURRENT_PART><BREAKPOINTS></BREAKPOINTS><IO_EXPAND><HIDE>false</HIDE></IO_EXPAND><REGISTERNAMES><Register>R00</Register><Register>R01</Register><Register>R02</Register><Register>R03</Register><Register>R04</Register><Register>R05</Register><Register>R06</Register><Register>R07</Register><Register>R08</Register><Register>R09</Register><Register>R10</Register><Register>R11</Register><Register>R12</Register><Register>R13</Register><Register>R14</Register><Register>R15</Register><Register>R16</Register><Register>R17</Register><Register>R18</Register><Register>R19</Register><Register>R20</Register><Register>R21</Register><Register>R22</Register><Register>R23</Register><Register>R24</Register><Register>R25</Register><Register>R26</Register><Register>R27</Register><Register>R28</Register><Register>R29</Register><Register>R30</Register><Register>R31</Register></REGISTERNAMES><COM>Auto</COM><COMType>0</COMType><WATCHNUM>0</WATCHNUM><WATCHNAMES><Pane0></Pane0><Pane1></Pane1><Pane2></Pane2><Pane3></Pane3></WATCHNAMES><BreakOnTrcaeFull>0</BreakOnTrcaeFull></DEBUG_TARGET><Debugger><Triggers></Triggers></Debugger><AVRGCCPLUGIN><FILES/><CONFIGS><CONFIG><NAME>default</NAME><USESEXTERNALMAKEFILE>NO</USESEXTERNALMAKEFILE><EXTERNALMAKEFILE></EXTERNALMAKEFILE><PART>atmega128</PART><HEX>1</HEX><LIST>1</LIST><MAP>1</MAP><OUTPUTFILENAME>bootloader.elf</OUTPUTFILENAME><OUTPUTDIR>default\</OUTPUTDIR><ISDIRTY>0</ISDIRTY><OPTIONS/><INCDIRS/><LIBDIRS/><LIBS/><LINKOBJECTS/><OPTIONSFORALL>-Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums</OPTIONSFORALL><LINKEROPTIONS></LINKEROPTIONS><SEGMENTS/></CONFIG></CONFIGS><LASTCONFIG>default</LASTCONFIG></AVRGCCPLUGIN><IOView><usergroups/><sort sorted="0" column="0" ordername="1" orderaddress="1" ordergroup="1"/></IOView><Files></Files><Events><Bookmarks></Bookmarks></Events><Trace><Filters></Filters></Trace></AVRStudio>
+58
View File
@@ -0,0 +1,58 @@
/* definitions generated by preprocessor, copy into defines.h */
#ifndef PPINC
#define _ATMEGA644P /* device select: _ATMEGAxxxx */
#define _B2048 /* boot size select: _Bxxxx (words), powers of two only */
#ifdef __ICCAVR__
#include "iom644.h"
#endif
#if __GNUC__
#include <avr/io.h>
#if (__GNUC__ <= 4) && (__GNUC_MINOR__ < 3)
#if !defined(EEWE) && defined(EEPE)
#define EEWE EEPE
#endif
#if !defined(EEMWE) && defined(EEMPE)
#define EEMWE EEMPE
#endif
#endif
#endif
/* define pin for enter-self-prog-mode */
#define PROGPORT PORTB
#define PROGPIN PINB
#define PROG_NO PB0
/* baud rate register value calculation */
#define CPU_FREQ 18430000
#define BAUD_RATE 115200
#define BRREG_VALUE 9
/* definitions for UART control */
#define BAUD_RATE_LOW_REG UBRR1
#define UART_CONTROL_REG UCSR1B
#define ENABLE_TRANSMITTER_BIT TXEN1
#define ENABLE_RECEIVER_BIT RXEN1
#define UART_STATUS_REG UCSR1A
#define TRANSMIT_COMPLETE_BIT TXC1
#define RECEIVE_COMPLETE_BIT RXC1
#define UART_DATA_REG UDR1
/* definitions for SPM control */
#define SPMCR_REG SPMCSR
#define PAGESIZE 256
#define APP_END 61440
/*#define LARGE_MEMORY */
/* definitions for device recognition */
#define PARTCODE 0
#define SIGNATURE_BYTE_1 0x1E
#define SIGNATURE_BYTE_2 0x96
#define SIGNATURE_BYTE_3 0x0A
/* indicate that preprocessor result is included */
#define PPINC
#endif
+74
View File
@@ -0,0 +1,74 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : flash.h
* Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5)
* Revision : $Revision: 1.7 $
* Date : $Date: Tuesday, June 07, 200 $
* Updated by : $Author: raapeland $
*
* Support mail : avr@atmel.com
*
* Target platform : All AVRs with bootloader support
*
* AppNote : AVR109 - Self-programming
*
* Description : Flash operations for AVR109 Self-programming
****************************************************************************/
#if defined(__ICCAVR__)
/* IAR Embedded Workbench */
#include <inavr.h>
#define _GET_LOCK_BITS() __AddrToZByteToSPMCR_LPM( (void __flash *) 0x0001, 0x09 )
#define _GET_LOW_FUSES() __AddrToZByteToSPMCR_LPM( (void __flash *) 0x0000, 0x09 )
#define _GET_HIGH_FUSES() __AddrToZByteToSPMCR_LPM( (void __flash *) 0x0003, 0x09 )
#define _GET_EXTENDED_FUSES() __AddrToZByteToSPMCR_LPM( (void __flash *) 0x0002, 0x09 )
#define _SET_LOCK_BITS(data) __DataToR0ByteToSPMCR_SPM( data, 0x09 )
#define _ENABLE_RWW_SECTION() __DataToR0ByteToSPMCR_SPM( 0x00, 0x11 )
#define _WAIT_FOR_SPM() while( SPMCR_REG & (1<<SPMEN) );
#ifndef LARGE_MEMORY
#define _LOAD_PROGRAM_MEMORY(addr) __load_program_memory( (const unsigned char __flash *) (addr) )
#define _FILL_TEMP_WORD(addr,data) __AddrToZWordToR1R0ByteToSPMCR_SPM( (void __flash *) (addr), data, 0x01 )
#define _PAGE_ERASE(addr) __AddrToZByteToSPMCR_SPM( (void __flash *) (addr), 0x03 )
#define _PAGE_WRITE(addr) __AddrToZByteToSPMCR_SPM( (void __flash *) (addr), 0x05 )
#else /* LARGE_MEMORY */
#define _LOAD_PROGRAM_MEMORY(addr) __extended_load_program_memory( (const unsigned char __farflash *) (addr) )
#define _FILL_TEMP_WORD(addr,data) __AddrToZ24WordToR1R0ByteToSPMCR_SPM( (void __farflash *) (addr), data, 0x01 )
#define _PAGE_ERASE(addr) __AddrToZ24ByteToSPMCR_SPM( (void __farflash *) (addr), 0x03 )
#define _PAGE_WRITE(addr) __AddrToZ24ByteToSPMCR_SPM( (void __farflash *) (addr), 0x05 )
#endif /* LARGE_MEMORY */
#elif __GNUC__ > 0
/* AVR-GCC/avr-libc */
#include <avr/boot.h>
#include <avr/pgmspace.h>
#if defined(GET_LOCK_BITS) /* avr-libc >= 1.2.5 */
#define _GET_LOCK_BITS() boot_lock_fuse_bits_get(GET_LOCK_BITS)
#define _GET_LOW_FUSES() boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS)
#define _GET_HIGH_FUSES() boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS)
#define _GET_EXTENDED_FUSES() boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS)
#endif /* defined(GET_LOCK_BITS) */
#define _SET_LOCK_BITS(data) boot_lock_bits_set(~data)
#define _ENABLE_RWW_SECTION() boot_rww_enable()
#define _WAIT_FOR_SPM() boot_spm_busy_wait()
#ifndef LARGE_MEMORY
#define _LOAD_PROGRAM_MEMORY(addr) pgm_read_byte_near(addr)
#else /* LARGE_MEMORY */
#define _LOAD_PROGRAM_MEMORY(addr) pgm_read_byte_far(addr)
#endif /* LARGE_MEMORY */
#define _FILL_TEMP_WORD(addr,data) boot_page_fill(addr, data)
#define _PAGE_ERASE(addr) boot_page_erase(addr)
#define _PAGE_WRITE(addr) boot_page_write(addr)
#else
#error "Don't know your compiler."
#endif
+466
View File
@@ -0,0 +1,466 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : main.c
* Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5)
* Revision : $Revision: 1.7 $
* Date : $Date: Tuesday, June 07, 200 $
* Updated by : $Author: raapeland $
*
* Support mail : avr@atmel.com
*
* Target platform : All AVRs with bootloader support
*
* AppNote : AVR109 - Self-programming
*
* Description : This Program allows an AVR with bootloader capabilities to
* Read/write its own Flash/EEprom. To enter Programming mode
* an input pin is checked. If this pin is pulled low, programming mode
* is entered. If not, normal execution is done from $0000
* "reset" vector in Application area.
*
* Preparations : Use the preprocessor.xls file for obtaining a customized
* defines.h file and linker-file code-segment definition for
* the device you are compiling for.
****************************************************************************/
#include "defines.h"
#include "serial.h"
#include "flash.h"
/* Uncomment the following to save code space */
/*#define REMOVE_AVRPROG_SUPPORT */
/*#define REMOVE_FUSE_AND_LOCK_BIT_SUPPORT */
/*#define REMOVE_BLOCK_SUPPORT */
/*#define REMOVE_EEPROM_BYTE_SUPPORT */
/*#define REMOVE_FLASH_BYTE_SUPPORT */
/*
* GCC doesn't optimize long int arithmetics very clever. As the
* address only needs to be larger than 16 bits for the ATmega128 and
* above (where flash consumptions isn't much of an issue as the
* entire boot loader will still fit even into the smallest possible
* boot loader section), save space by using a 16-bit variable for the
* smaller devices.
*/
#ifdef LARGE_MEMORY
#define ADDR_T unsigned long
#else /* !LARGE_MEMORY */
#define ADDR_T unsigned int
#endif /* LARGE_MEMORY */
#ifndef REMOVE_BLOCK_SUPPORT
unsigned char BlockLoad(
unsigned int size,
unsigned char mem,
ADDR_T * address);
void BlockRead(
unsigned int size,
unsigned char mem,
ADDR_T * address);
/* BLOCKSIZE should be chosen so that the following holds: BLOCKSIZE*n = PAGESIZE, where n=1,2,3... */
#define BLOCKSIZE PAGESIZE
#endif /* REMOVE_BLOCK_SUPPORT */
#ifdef __ICCAVR__
__C_task void main(
void)
#else /* ! __ICCAVR__ */
int main(
void)
#endif /* __ICCAVR__ */
{
ADDR_T address;
unsigned int temp_int;
unsigned char val;
/* Initialization */
void (
*funcptr) (
void) = 0x0000; /* Set up function pointer to RESET vector. */
PROGPORT |= (1 << PROG_NO); /* Enable pull-up on PROG_NO line on PROGPORT. */
initbootuart(); /* Initialize UART. */
/* Branch to bootloader or application code? */
if (!(PROGPIN & (1 << PROG_NO))) { /* If PROGPIN is pulled low, enter programmingmode. */
/* Main loop */
for (;;) {
val = recchar(); /* Wait for command character. */
/* Check autoincrement status. */
if (val == 'a') {
sendchar('Y'); /* Yes, we do autoincrement. */
}
/* Set address. */
else if (val == 'A') { /* Set address... *//* NOTE: Flash addresses are given in words, not bytes. */
address = (recchar() << 8) | recchar(); /* Read address high and low byte. */
sendchar('\r'); /* Send OK back. */
}
/* Chip erase. */
else if (val == 'e') {
for (address = 0; address < APP_END; address += PAGESIZE) { /* NOTE: Here we use address as a byte-address, not word-address, for convenience. */
_WAIT_FOR_SPM();
#ifdef __ICCAVR__
#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */
#endif
_PAGE_ERASE(address);
#ifdef __ICCAVR__
#pragma diag_default=Pe1053 /* Back to default. */
#endif
}
sendchar('\r'); /* Send OK back. */
}
#ifndef REMOVE_BLOCK_SUPPORT
/* Check block load support. */
else if (val == 'b') {
sendchar('Y'); /* Report block load supported. */
sendchar((BLOCKSIZE >> 8) & 0xFF); /* MSB first. */
sendchar(BLOCKSIZE & 0xFF); /* Report BLOCKSIZE (bytes). */
}
/* Start block load. */
else if (val == 'B') {
temp_int = (recchar() << 8) | recchar(); /* Get block size. */
val = recchar(); /* Get memtype. */
sendchar(BlockLoad(temp_int, val, &address)); /* Block load. */
}
/* Start block read. */
else if (val == 'g') {
temp_int = (recchar() << 8) | recchar(); /* Get block size. */
val = recchar(); /* Get memtype */
BlockRead(temp_int, val, &address); /* Block read */
}
#endif /* REMOVE_BLOCK_SUPPORT */
#ifndef REMOVE_FLASH_BYTE_SUPPORT
/* Read program memory. */
else if (val == 'R') {
/* Send high byte, then low byte of flash word. */
_WAIT_FOR_SPM();
_ENABLE_RWW_SECTION();
#ifdef __ICCAVR__
#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */
#endif
sendchar(_LOAD_PROGRAM_MEMORY((address << 1) + 1));
sendchar(_LOAD_PROGRAM_MEMORY((address << 1) + 0));
#ifdef __ICCAVR__
#pragma diag_default=Pe1053 /* Back to default. */
#endif
address++; /* Auto-advance to next Flash word. */
}
/* Write program memory, low byte. */
else if (val == 'c') { /* NOTE: Always use this command before sending high byte. */
temp_int = recchar(); /* Get low byte for later _FILL_TEMP_WORD. */
sendchar('\r'); /* Send OK back. */
}
/* Write program memory, high byte. */
else if (val == 'C') {
temp_int |= (recchar() << 8); /* Get and insert high byte. */
_WAIT_FOR_SPM();
#ifdef __ICCAVR__
#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */
#endif
_FILL_TEMP_WORD((address << 1), temp_int); /* Convert word-address to byte-address and fill. */
#ifdef __ICCAVR__
#pragma diag_default=Pe1053 /* Back to default. */
#endif
address++; /* Auto-advance to next Flash word. */
sendchar('\r'); /* Send OK back. */
}
/* Write page. */
else if (val == 'm') {
if (address >= (APP_END >> 1)) { /* Protect bootloader area. */
sendchar('?');
} else {
_WAIT_FOR_SPM();
#ifdef __ICCAVR__
#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */
#endif
_PAGE_WRITE(address << 1); /* Convert word-address to byte-address and write. */
#ifdef __ICCAVR__
#pragma diag_default=Pe1053 /* Back to default. */
#endif
}
sendchar('\r'); /* Send OK back. */
}
#endif /* REMOVE_FLASH_BYTE_SUPPORT */
#ifndef REMOVE_EEPROM_BYTE_SUPPORT
/* Write EEPROM memory. */
else if (val == 'D') {
_WAIT_FOR_SPM();
EEARL = address; /* Setup EEPROM address. */
EEARH = (address >> 8);
EEDR = recchar(); /* Get byte. */
EECR |= (1 << EEMWE); /* Write byte. */
EECR |= (1 << EEWE);
while (EECR & (1 << EEWE)) /* Wait for write operation to finish. */
;
address++; /* Auto-advance to next EEPROM byte. */
sendchar('\r'); /* Send OK back. */
}
/* Read EEPROM memory. */
else if (val == 'd') {
EEARL = address; /* Setup EEPROM address. */
EEARH = (address >> 8);
EECR |= (1 << EERE); /* Read byte... */
sendchar(EEDR); /* ...and send it back. */
address++; /* Auto-advance to next EEPROM byte. */
}
#endif /* REMOVE_EEPROM_BYTE_SUPPORT */
#ifndef REMOVE_FUSE_AND_LOCK_BIT_SUPPORT
/* Write lockbits. */
else if (val == 'l') {
_WAIT_FOR_SPM();
_SET_LOCK_BITS(recchar()); /* Read and set lock bits. */
sendchar('\r'); /* Send OK back. */
}
#if defined(_GET_LOCK_BITS)
/* Read lock bits. */
else if (val == 'r') {
_WAIT_FOR_SPM();
sendchar(_GET_LOCK_BITS());
}
/* Read fuse bits. */
else if (val == 'F') {
_WAIT_FOR_SPM();
sendchar(_GET_LOW_FUSES());
}
/* Read high fuse bits. */
else if (val == 'N') {
_WAIT_FOR_SPM();
sendchar(_GET_HIGH_FUSES());
}
/* Read extended fuse bits. */
else if (val == 'Q') {
_WAIT_FOR_SPM();
sendchar(_GET_EXTENDED_FUSES());
}
#endif /* defined(_GET_LOCK_BITS) */
#endif /* REMOVE_FUSE_AND_LOCK_BIT_SUPPORT */
#ifndef REMOVE_AVRPROG_SUPPORT
/* Enter and leave programming mode. */
else if ((val == 'P') || (val == 'L')) {
sendchar('\r'); /* Nothing special to do, just answer OK. */
}
/* Exit bootloader. */
else if (val == 'E') {
_WAIT_FOR_SPM();
_ENABLE_RWW_SECTION();
sendchar('\r');
funcptr(); /* Jump to Reset vector 0x0000 in Application Section. */
}
/* Get programmer type. */
else if (val == 'p') {
sendchar('S'); /* Answer 'SERIAL'. */
}
/* Return supported device codes. */
else if (val == 't') {
#if PARTCODE+0 > 0
sendchar(PARTCODE); /* Supports only this device, of course. */
#endif /* PARTCODE */
sendchar(0); /* Send list terminator. */
}
/* Set LED, clear LED and set device type. */
else if ((val == 'x') || (val == 'y') || (val == 'T')) {
recchar(); /* Ignore the command and it's parameter. */
sendchar('\r'); /* Send OK back. */
}
#endif /* REMOVE_AVRPROG_SUPPORT */
/* Return programmer identifier. */
else if (val == 'S') {
sendchar('A'); /* Return 'AVRBOOT'. */
sendchar('V'); /* Software identifier (aka programmer signature) is always 7 characters. */
sendchar('R');
sendchar('B');
sendchar('O');
sendchar('O');
sendchar('T');
}
/* Return software version. */
else if (val == 'V') {
sendchar('1');
sendchar('5');
}
/* Return signature bytes. */
else if (val == 's') {
sendchar(SIGNATURE_BYTE_3);
sendchar(SIGNATURE_BYTE_2);
sendchar(SIGNATURE_BYTE_1);
}
/* The last command to accept is ESC (synchronization). */
else if (val != 0x1b) { /* If not ESC, then it is unrecognized... */
sendchar('?');
}
} /* end: for(;;) */
} else {
_WAIT_FOR_SPM();
_ENABLE_RWW_SECTION();
funcptr(); /* Jump to Reset vector 0x0000 in Application Section. */
}
} /* end: main */
#ifndef REMOVE_BLOCK_SUPPORT
unsigned char BlockLoad(
unsigned int size,
unsigned char mem,
ADDR_T * address)
{
unsigned char buffer[BLOCKSIZE];
unsigned int data;
ADDR_T tempaddress;
/* EEPROM memory type. */
if (mem == 'E') {
/* Fill buffer first, as EEPROM is too slow to copy with UART speed */
for (tempaddress = 0; tempaddress < size; tempaddress++)
buffer[tempaddress] = recchar();
/* Then program the EEPROM */
_WAIT_FOR_SPM();
for (tempaddress = 0; tempaddress < size; tempaddress++) {
EEARL = *address; /* Setup EEPROM address */
EEARH = ((*address) >> 8);
EEDR = buffer[tempaddress]; /* Get byte. */
EECR |= (1 << EEMWE); /* Write byte. */
EECR |= (1 << EEWE);
while (EECR & (1 << EEWE)) /* Wait for write operation to finish. */
;
(*address)++; /* Select next EEPROM byte */
}
return '\r'; /* Report programming OK */
}
/* Flash memory type. */
else if (mem == 'F') { /* NOTE: For flash programming, 'address' is given in words. */
(*address) <<= 1; /* Convert address to bytes temporarily. */
tempaddress = (*address); /* Store address in page. */
do {
data = recchar();
data |= (recchar() << 8);
#ifdef __ICCAVR__
#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */
#endif
_FILL_TEMP_WORD(*address, data);
#ifdef __ICCAVR__
#pragma diag_default=Pe1053 /* Back to default. */
#endif
(*address) += 2; /* Select next word in memory. */
size -= 2; /* Reduce number of bytes to write by two. */
} while (size); /* Loop until all bytes written. */
#ifdef __ICCAVR__
#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */
#endif
_PAGE_WRITE(tempaddress);
#ifdef __ICCAVR__
#pragma diag_default=Pe1053 /* Back to default. */
#endif
_WAIT_FOR_SPM();
_ENABLE_RWW_SECTION();
(*address) >>= 1; /* Convert address back to Flash words again. */
return '\r'; /* Report programming OK */
}
/* Invalid memory type? */
else {
return '?';
}
}
void BlockRead(
unsigned int size,
unsigned char mem,
ADDR_T * address)
{
/* EEPROM memory type. */
if (mem == 'E') { /* Read EEPROM */
do {
EEARL = *address; /* Setup EEPROM address */
EEARH = ((*address) >> 8);
(*address)++; /* Select next EEPROM byte */
EECR |= (1 << EERE); /* Read EEPROM */
sendchar(EEDR); /* Transmit EEPROM dat ato PC */
size--; /* Decrease number of bytes to read */
} while (size); /* Repeat until all block has been read */
}
/* Flash memory type. */
else if (mem == 'F') {
(*address) <<= 1; /* Convert address to bytes temporarily. */
do {
#ifdef __ICCAVR__
#pragma diag_suppress=Pe1053 /* Suppress warning for conversion from long-type address to flash ptr. */
#endif
sendchar(_LOAD_PROGRAM_MEMORY(*address));
sendchar(_LOAD_PROGRAM_MEMORY((*address) + 1));
#ifdef __ICCAVR__
#pragma diag_default=Pe1053 /* Back to default. */
#endif
(*address) += 2; /* Select next word in memory. */
size -= 2; /* Subtract two bytes from number of bytes to read */
} while (size); /* Repeat until all block has been read */
(*address) >>= 1; /* Convert address back to Flash words again. */
}
}
#endif /* REMOVE_BLOCK_SUPPORT */
/* end of file */
+24
View File
@@ -0,0 +1,24 @@
#Extracted from "Part definitions" of preprocessor.xls
#dev include pagesz nrwwpag totpag avr910 sig1 sig2 sig3 baudlo uartc uarts txen rxen txc rxc udr spmcr
ATmega8 iom8.h 32 32 128 0x77 0x1E 0x93 0x07 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
ATmega8515 iom8515.h 32 32 128 0x3B 0x1E 0x93 0x06 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
ATmega8535 iom8535.h 32 32 128 0x6A 0x1E 0x93 0x08 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
ATmega88 iom88.h 32 32 128 0x1E 0x93 0x0A UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
ATmega16 iom16.h 64 16 128 0x75 0x1E 0x94 0x03 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
ATmega162 iom162.h 64 16 128 0x63 0x1E 0x94 0x04 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCR
ATmega163 iom163.h 64 16 128 0x66 0x1E 0x94 0x02 UBRRLO UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
ATmega165 iom165.h 64 16 128 0x1E 0x94 0x07 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
ATmega168 iom168.h 64 16 128 0x1E 0x94 0x06 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
ATmega169 iom169.h 64 16 128 0x79 0x1E 0x94 0x05 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
ATmega32 iom32.h 64 32 256 0x7F 0x1E 0x95 0x02 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
ATmega323 iom323.h 64 16 256 0x73 0x1E 0x95 0x01 UBRRL UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCR
ATmega329 iom329.h 64 32 256 0x1E 0x95 0x03 UBRR UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
ATmega3290 iom3290.h 64 32 256 0x1E 0x95 0x04 UBRR UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
ATmega64 iom64.h 128 32 256 0x46 0x1E 0x96 0x02 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCR
ATmega644 iom644.h 128 32 256 0x1E 0x96 0x09 UBRR0 UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
ATmega644P iom644.h 128 32 256 0x1E 0x96 0x0A UBRR1 UCSR1B UCSR1A TXEN1 RXEN1 TXC1 RXC1 UDR1 SPMCSR
ATmega649 iom649.h 128 32 256 0x1E 0x96 0x03 UBRR UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
ATmega6490 iom6490.h 128 32 256 0x1E 0x96 0x04 UBRR UCSRB UCSRA TXEN RXEN TXC RXC UDR SPMCSR
ATmega128 iom128.h 128 32 512 0x44 0x1E 0x97 0x02 UBRR0L UCSR0B UCSR0A TXEN0 RXEN0 TXC0 RXC0 UDR0 SPMCSR
ATmega128_1 iom128.h 128 32 512 0x44 0x1E 0x97 0x02 UBRR1L UCSR1B UCSR1A TXEN1 RXEN1 TXC1 RXC1 UDR1 SPMCSR
@@ -0,0 +1,171 @@
#! /bin/sh
# Equivalent script to what preprocessor.xls might do.
#
# Run e.g. like
# sh preprocessor.sh ATmega128 4096 PORTD PD4 3686400 9600 > defines.h
#
# Written by Joerg Wunsch, 2005-07-29
PARTFILE=parts.txt
usage()
{
echo "usage: preprocessor.sh device bootsize progport prog_no cpu_freq baud_rate" >& 2
exit 1
}
if [ $# -ne 6 ]
then
usage
fi
if [ ! -f ${PARTFILE} ]
then
echo "part definition file ${PARTFILE} not found" >& 2
exit 1
fi
device="$1"
bootsize="$2"
progport="$3"
prog_no="$4"
cpu_freq="$5"
baud_rate="$6"
# is there a device at all?
if grep -i "^${device} " ${PARTFILE} >/dev/null
then
:
else
echo "device ${device} not found in ${PARTFILE}" >& 2
exit 1
fi
devupper=`echo $device | tr '[a-z]' '[A-Z]'`
# find an awk to use, out of nawk, gawk, or awk
AWK=none
for name in nawk gawk awk
do
set -- `type $name 2>/dev/null`
if [ "x$2" = 'xis' ]
then
AWK=$name
break
fi
done
if [ $AWK = 'none' ]
then
echo "Sorry, no useable awk found" >& 2
exit 1
fi
# OK, now get the individual fields. Unfortunately, the AVR910 device ID
# is optional, and the shell cannot parse that natively. Use awk to
# re-order the fields, and sort the avr910 column last (so we'll get an
# empty variable in read if it is not present).
set -- `grep -i "^${device} " ${PARTFILE} |\
${AWK} -F ' ' \
'{print $1 " " $2 " " $3 " " $4 " " $5 " " $7 " " $8 " " $9 " " $10 " " $11 " " $12 " " $13 " " $14 " " $15 " " $16 " " $17 " " $18 " " $6; exit}'`
dev=$1
include=$2
pagesz=$3
nrwwpag=$4
totpag=$5
sig1=$6
sig2=$7
sig3=$8
baudlo=$9
shift 9
uartc=$1
uarts=$2
txen=$3
rxen=$4
txc=$5
rxc=$6
udr=$7
spmcr=$8
avr910=$9
# Verify boot size
pagebytes=`expr $pagesz \* 2`
maxboot=`expr $nrwwpag \* $pagebytes`
bootbytes=`expr 2 \* $bootsize` || exit 1
if [ \( $bootbytes -ne $maxboot \) -a \
\( $bootbytes -ne `expr $maxboot / 4` \) -a \
\( $bootbytes -ne `expr $maxboot / 2` \) -a \
\( $bootbytes -ne `expr $maxboot \* 3 / 4` \) ]
then
echo "Invalid boot size ${bootsize}, valid: `expr $maxboot / 8`, `expr $maxboot / 4`, `expr $maxboot \* 3 / 8`, `expr $maxboot / 2` words" >& 2
exit 1
fi
if p=`expr $progport : 'PORT\(.\)'`
then
: # ok
else
echo "Invalid port name ${progport}, must be PORTx" >& 2
exit 1
fi
progpin="PIN$p"
brreg=`expr $cpu_freq / \( 16 \* $baud_rate \) - 1` || exit 1
memsize=`expr $totpag \* $pagebytes`
append=`expr $memsize - $bootbytes`
echo "/* definitions generated by preprocessor, copy into defines.h */
#ifndef PPINC
#define _${devupper} // device select: _ATMEGAxxxx
#define _B${bootsize} // boot size select: _Bxxxx (words), powers of two only
#ifdef __ICCAVR__
#include \"${include}\"
#endif
#if __GNUC__
#include <avr/io.h>
#endif
/* define pin for enter-self-prog-mode */
#define PROGPORT ${progport}
#define PROGPIN ${progpin}
#define PROG_NO ${prog_no}
/* baud rate register value calculation */
#define CPU_FREQ ${cpu_freq}
#define BAUD_RATE ${baud_rate}
#define BRREG_VALUE ${brreg}
/* definitions for UART control */
#define BAUD_RATE_LOW_REG ${baudlo}
#define UART_CONTROL_REG ${uartc}
#define ENABLE_TRANSMITTER_BIT ${txen}
#define ENABLE_RECEIVER_BIT ${rxen}
#define UART_STATUS_REG ${uarts}
#define TRANSMIT_COMPLETE_BIT ${txc}
#define RECEIVE_COMPLETE_BIT ${rxc}
#define UART_DATA_REG ${udr}
/* definitions for SPM control */
#define SPMCR_REG ${spmcr}
#define PAGESIZE ${pagebytes}
#define APP_END ${append}"
if [ $memsize -gt 65536 ]
then
echo "#define LARGE_MEMORY"
else
echo "//#define LARGE_MEMORY"
fi
echo "
/* definitions for device recognition */
#define PARTCODE ${avr910}
#define SIGNATURE_BYTE_1 ${sig1}
#define SIGNATURE_BYTE_2 ${sig2}
#define SIGNATURE_BYTE_3 ${sig3}
/* indicate that preprocessor result is included */
#define PPINC
#endif"
echo "(IAR) Replace all code segment definitions in the linker file with the following line:" >& 2
${AWK} 'BEGIN {printf "-Z(CODE)INTVEC,FAR_F,SWITCH,CODE=%X-%X\n", '$append', '$memsize' - 1; exit}' >& 2
Binary file not shown.
+44
View File
@@ -0,0 +1,44 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : serial.c
* Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5)
* Revision : $Revision: 1.7 $
* Date : $Date: Tuesday, June 07, 200 $
* Updated by : $Author: raapeland $
*
* Support mail : avr@atmel.com
*
* Target platform : All AVRs with bootloader support
*
* AppNote : AVR109 - Self-programming
*
* Description : UART communication routines
****************************************************************************/
#include "defines.h"
void initbootuart(
void)
{
BAUD_RATE_LOW_REG = BRREG_VALUE;
UART_CONTROL_REG = (1 << ENABLE_RECEIVER_BIT) | (1 << ENABLE_TRANSMITTER_BIT); /* enable receive and transmit */
}
void sendchar(
unsigned char c)
{
UART_DATA_REG = c; /* prepare transmission */
while (!(UART_STATUS_REG & (1 << TRANSMIT_COMPLETE_BIT))); /* wait until byte sendt */
UART_STATUS_REG |= (1 << TRANSMIT_COMPLETE_BIT); /* delete TXCflag */
}
unsigned char recchar(
void)
{
while (!(UART_STATUS_REG & (1 << RECEIVE_COMPLETE_BIT))); /* wait for data */
return UART_DATA_REG;
}
+25
View File
@@ -0,0 +1,25 @@
/*****************************************************************************
*
* Atmel Corporation
*
* File : serial.h
* Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5)
* Revision : $Revision: 1.7 $
* Date : $Date: Tuesday, June 07, 200 $
* Updated by : $Author: raapeland $
*
* Support mail : avr@atmel.com
*
* Target platform : All AVRs with bootloader support
*
* AppNote : AVR109 - Self-programming
*
* Description : Header file for serial.c
****************************************************************************/
void initbootuart(
void);
void sendchar(
unsigned char);
unsigned char recchar(
void);
+20
View File
@@ -0,0 +1,20 @@
#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
#endif
+951
View File
@@ -0,0 +1,951 @@
/**************************************************************************
*
* 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 <stdlib.h>
#include <string.h>
#include "bacdef.h"
#include "bacdcode.h"
#include "bacstr.h"
#include "bacenum.h"
#include "apdu.h"
#include "dcc.h"
#include "datalink.h"
#include "rs485.h"
#include "version.h"
#include "nvdata.h"
#include "stack.h"
#include "handlers.h"
#include "bname.h"
/* objects */
#include "device.h"
#include "ai.h"
#include "av.h"
#include "bi.h"
#include "bo.h"
/* forward prototype */
int Device_Read_Property_Local(
BACNET_READ_PROPERTY_DATA * rpdata);
bool Device_Write_Property_Local(
BACNET_WRITE_PROPERTY_DATA * wp_data);
static struct my_object_functions {
BACNET_OBJECT_TYPE Object_Type;
object_init_function Object_Init;
object_count_function Object_Count;
object_index_to_instance_function Object_Index_To_Instance;
object_valid_instance_function Object_Valid_Instance;
object_name_function Object_Name;
read_property_function Object_Read_Property;
write_property_function Object_Write_Property;
rpm_property_lists_function Object_RPM_List;
} Object_Table[] = {
{
OBJECT_DEVICE, NULL, /* don't init - recursive! */
Device_Count, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number, Device_Object_Name,
Device_Read_Property_Local, Device_Write_Property_Local,
Device_Property_Lists}, {
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
Analog_Input_Object_Name, Analog_Input_Read_Property, NULL,
Analog_Input_Property_Lists}, {
OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance,
Analog_Value_Object_Name, Analog_Value_Read_Property,
Analog_Value_Write_Property, Analog_Value_Property_Lists}, {
OBJECT_BINARY_INPUT, Binary_Input_Init, Binary_Input_Count,
Binary_Input_Index_To_Instance, Binary_Input_Valid_Instance,
Binary_Input_Object_Name, Binary_Input_Read_Property, NULL,
Binary_Input_Property_Lists}, {
OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count,
Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance,
Binary_Output_Object_Name, Binary_Output_Read_Property,
Binary_Output_Write_Property, Binary_Output_Property_Lists}, {
MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};
/* note: you really only need to define variables for
properties that are writable or that may change.
The properties that are constant can be hard coded
into the read-property encoding. */
static uint32_t Object_Instance_Number;
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
static uint32_t Database_Revision;
static BACNET_REINITIALIZED_STATE Reinitialize_State = BACNET_REINIT_IDLE;
static const char *Reinit_Password = "rehmite";
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Device_Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_SYSTEM_STATUS,
PROP_VENDOR_NAME,
PROP_VENDOR_IDENTIFIER,
PROP_MODEL_NAME,
PROP_FIRMWARE_REVISION,
PROP_APPLICATION_SOFTWARE_VERSION,
PROP_PROTOCOL_VERSION,
PROP_PROTOCOL_REVISION,
PROP_PROTOCOL_SERVICES_SUPPORTED,
PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED,
PROP_OBJECT_LIST,
PROP_MAX_APDU_LENGTH_ACCEPTED,
PROP_SEGMENTATION_SUPPORTED,
PROP_APDU_TIMEOUT,
PROP_NUMBER_OF_APDU_RETRIES,
PROP_DEVICE_ADDRESS_BINDING,
PROP_DATABASE_REVISION,
-1
};
static const int Device_Properties_Optional[] = {
PROP_MAX_MASTER,
PROP_MAX_INFO_FRAMES,
PROP_DESCRIPTION,
PROP_LOCATION,
-1
};
static const int Device_Properties_Proprietary[] = {
512,
513,
9600,
-1
};
static struct my_object_functions *Device_Objects_Find_Functions(
BACNET_OBJECT_TYPE Object_Type)
{
struct my_object_functions *pObject = NULL;
pObject = &Object_Table[0];
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
/* handle each object type */
if (pObject->Object_Type == Object_Type) {
return (pObject);
}
pObject++;
}
return (NULL);
}
/* Encodes the property APDU and returns the length,
or sets the error, and returns BACNET_STATUS_ERROR */
int Device_Read_Property(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = BACNET_STATUS_ERROR;
struct my_object_functions *pObject = NULL;
/* initialize the default return values */
rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
pObject = Device_Objects_Find_Functions(rpdata->object_type);
if (pObject != NULL) {
if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(rpdata->object_instance)) {
if (pObject->Object_Read_Property) {
apdu_len = pObject->Object_Read_Property(rpdata);
}
}
}
return apdu_len;
}
bool Device_Write_Property(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false;
struct my_object_functions *pObject = NULL;
/* initialize the default return values */
pObject = Device_Objects_Find_Functions(wp_data->object_type);
if (pObject) {
if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(wp_data->object_instance)) {
if (pObject->Object_Write_Property) {
status = pObject->Object_Write_Property(wp_data);
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
} else {
wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
}
} else {
wp_data->error_class = ERROR_CLASS_OBJECT;
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
}
return status;
}
static unsigned my_property_list_count(
const int *pList)
{
unsigned property_count = 0;
if (pList) {
while (*pList != -1) {
property_count++;
pList++;
}
}
return property_count;
}
/* for a given object type, returns the special property list */
void Device_Objects_Property_List(
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
struct special_property_list_t *pPropertyList)
{
struct my_object_functions *pObject = NULL;
(void)object_instance;
pPropertyList->Required.pList = NULL;
pPropertyList->Optional.pList = NULL;
pPropertyList->Proprietary.pList = NULL;
/* If we can find an entry for the required object type
* and there is an Object_List_RPM fn ptr then call it
* to populate the pointers to the individual list counters.
*/
pObject = Device_Objects_Find_Functions(object_type);
if ((pObject != NULL) && (pObject->Object_RPM_List != NULL)) {
pObject->Object_RPM_List(&pPropertyList->Required.pList,
&pPropertyList->Optional.pList, &pPropertyList->Proprietary.pList);
}
/* Fetch the counts if available otherwise zero them */
pPropertyList->Required.count =
pPropertyList->Required.pList ==
NULL ? 0 : my_property_list_count(pPropertyList->Required.pList);
pPropertyList->Optional.count =
pPropertyList->Optional.pList ==
NULL ? 0 : my_property_list_count(pPropertyList->Optional.pList);
pPropertyList->Proprietary.count =
pPropertyList->Proprietary.pList ==
NULL ? 0 : my_property_list_count(pPropertyList->Proprietary.pList);
return;
}
void Device_Property_Lists(
const int **pRequired,
const int **pOptional,
const int **pProprietary)
{
if (pRequired)
*pRequired = Device_Properties_Required;
if (pOptional)
*pOptional = Device_Properties_Optional;
if (pProprietary)
*pProprietary = Device_Properties_Proprietary;
return;
}
unsigned Device_Count(
void)
{
return 1;
}
uint32_t Device_Index_To_Instance(
unsigned index)
{
index = index;
return Object_Instance_Number;
}
static char *Device_Name_Default(
void)
{
static char text_string[32]; /* okay for single thread */
sprintf(text_string, "DEVICE-%lu", Object_Instance_Number);
return text_string;
}
bool Device_Object_Name(
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
bool status = false;
if (object_instance == Object_Instance_Number) {
bacnet_name(NV_EEPROM_DEVICE_NAME, object_name, Device_Name_Default());
status = true;
}
return status;
}
bool Device_Reinitialize(
BACNET_REINITIALIZE_DEVICE_DATA * rd_data)
{
bool status = false;
/* Note: you could use a mix of state and password to multiple things */
if (characterstring_ansi_same(&rd_data->password, Reinit_Password)) {
switch (rd_data->state) {
case BACNET_REINIT_COLDSTART:
case BACNET_REINIT_WARMSTART:
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
/* note: you probably want to restart *after* the
simple ack has been sent from the return handler
so just set a flag from here */
Reinitialize_State = rd_data->state;
status = true;
break;
case BACNET_REINIT_STARTBACKUP:
case BACNET_REINIT_ENDBACKUP:
case BACNET_REINIT_STARTRESTORE:
case BACNET_REINIT_ENDRESTORE:
case BACNET_REINIT_ABORTRESTORE:
if (dcc_communication_disabled()) {
rd_data->error_class = ERROR_CLASS_SERVICES;
rd_data->error_code = ERROR_CODE_COMMUNICATION_DISABLED;
} else {
rd_data->error_class = ERROR_CLASS_SERVICES;
rd_data->error_code =
ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED;
}
break;
default:
rd_data->error_class = ERROR_CLASS_SERVICES;
rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
break;
}
} else {
rd_data->error_class = ERROR_CLASS_SECURITY;
rd_data->error_code = ERROR_CODE_PASSWORD_FAILURE;
}
return status;
}
BACNET_REINITIALIZED_STATE Device_Reinitialized_State(
void)
{
return Reinitialize_State;
}
void Device_Init(
object_functions_t * object_table)
{
struct my_object_functions *pObject = NULL;
/* we don't use the object table passed in
since there is extra stuff we don't need in there. */
(void) object_table;
/* our local object table */
pObject = &Object_Table[0];
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
if (pObject->Object_Init) {
pObject->Object_Init();
}
pObject++;
}
dcc_set_status_duration(COMMUNICATION_ENABLE, 0);
}
/* methods to manipulate the data */
uint32_t Device_Object_Instance_Number(
void)
{
return Object_Instance_Number;
}
bool Device_Set_Object_Instance_Number(
uint32_t object_id)
{
bool status = true; /* return value */
if (object_id <= BACNET_MAX_INSTANCE) {
if (object_id != Object_Instance_Number) {
Device_Inc_Database_Revision();
Object_Instance_Number = object_id;
}
} else
status = false;
return status;
}
bool Device_Valid_Object_Instance_Number(
uint32_t object_id)
{
return (Object_Instance_Number == object_id);
}
BACNET_DEVICE_STATUS Device_System_Status(
void)
{
return System_Status;
}
int Device_Set_System_Status(
BACNET_DEVICE_STATUS status,
bool local)
{
/*return value - 0 = ok, -1 = bad value, -2 = not allowed */
int result = -1;
if (status < MAX_DEVICE_STATUS) {
System_Status = status;
result = 0;
}
return result;
}
uint16_t Device_Vendor_Identifier(
void)
{
return BACNET_VENDOR_ID;
}
BACNET_SEGMENTATION Device_Segmentation_Supported(
void)
{
return SEGMENTATION_NONE;
}
uint32_t Device_Database_Revision(
void)
{
return Database_Revision;
}
void Device_Inc_Database_Revision(
void)
{
Database_Revision++;
}
/* Since many network clients depend on the object list */
/* for discovery, it must be consistent! */
unsigned Device_Object_List_Count(
void)
{
unsigned count = 0; /* number of objects */
struct my_object_functions *pObject = NULL;
/* initialize the default return values */
pObject = &Object_Table[0];
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
if (pObject->Object_Count) {
count += pObject->Object_Count();
}
pObject++;
}
return count;
}
bool Device_Object_List_Identifier(
uint32_t array_index,
int *object_type,
uint32_t * instance)
{
bool status = false;
uint32_t count = 0;
uint32_t object_index = 0;
struct my_object_functions *pObject = NULL;
/* array index zero is length - so invalid */
if (array_index == 0) {
return status;
}
object_index = array_index - 1;
/* initialize the default return values */
pObject = &Object_Table[0];
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
if (pObject->Object_Count && pObject->Object_Index_To_Instance) {
object_index -= count;
count = pObject->Object_Count();
if (object_index < count) {
*object_type = pObject->Object_Type;
*instance = pObject->Object_Index_To_Instance(object_index);
status = true;
break;
}
}
pObject++;
}
return status;
}
bool Device_Valid_Object_Name(
BACNET_CHARACTER_STRING * object_name1,
int *object_type,
uint32_t * object_instance)
{
bool found = false;
int type = 0;
uint32_t instance;
uint32_t max_objects = 0, i = 0;
bool check_id = false;
BACNET_CHARACTER_STRING object_name2;
struct my_object_functions *pObject = NULL;
max_objects = Device_Object_List_Count();
for (i = 1; i <= max_objects; i++) {
check_id = Device_Object_List_Identifier(i, &type, &instance);
if (check_id) {
pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE) type);
if ((pObject != NULL) && (pObject->Object_Name != NULL) &&
(pObject->Object_Name(instance, &object_name2) &&
characterstring_same(object_name1, &object_name2))) {
found = true;
if (object_type) {
*object_type = type;
}
if (object_instance) {
*object_instance = instance;
}
break;
}
}
}
return found;
}
bool Device_Valid_Object_Id(
int object_type,
uint32_t object_instance)
{
bool status = false; /* return value */
struct my_object_functions *pObject = NULL;
pObject = Device_Objects_Find_Functions((BACNET_OBJECT_TYPE) object_type);
if ((pObject != NULL) && (pObject->Object_Valid_Instance != NULL)) {
status = pObject->Object_Valid_Instance(object_instance);
}
return status;
}
bool Device_Object_Name_Copy(
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_CHARACTER_STRING * object_name)
{
struct my_object_functions *pObject = NULL;
bool found = false;
pObject = Device_Objects_Find_Functions(object_type);
if ((pObject != NULL) && (pObject->Object_Name != NULL)) {
found = pObject->Object_Name(object_instance, object_name);
}
return found;
}
/* return the length of the apdu encoded or BACNET_STATUS_ERROR for error */
int Device_Read_Property_Local(
BACNET_READ_PROPERTY_DATA * rpdata)
{
int apdu_len = 0; /* return value */
int len = 0; /* apdu len intermediate value */
BACNET_BIT_STRING bit_string = { 0 };
BACNET_CHARACTER_STRING char_string = { 0 };
uint32_t i = 0;
int object_type = 0;
uint32_t instance = 0;
uint32_t count = 0;
uint8_t *apdu = NULL;
struct my_object_functions *pObject = NULL;
if ((rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch ((int) rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
encode_application_object_id(&apdu[0], rpdata->object_type,
rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Device_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], rpdata->object_type);
break;
case PROP_DESCRIPTION:
bacnet_name(NV_EEPROM_DEVICE_DESCRIPTION, &char_string,
"BACnet Development Kit");
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_LOCATION:
bacnet_name(NV_EEPROM_DEVICE_LOCATION, &char_string,
"default location");
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_SYSTEM_STATUS:
apdu_len =
encode_application_enumerated(&apdu[0],
Device_System_Status());
break;
case PROP_VENDOR_NAME:
characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_VENDOR_IDENTIFIER:
apdu_len = encode_application_unsigned(&apdu[0], BACNET_VENDOR_ID);
break;
case PROP_MODEL_NAME:
characterstring_init_ansi(&char_string, "bdk-atxx4-mstp");
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_FIRMWARE_REVISION:
characterstring_init_ansi(&char_string, BACnet_Version);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_APPLICATION_SOFTWARE_VERSION:
characterstring_init_ansi(&char_string, "1.0");
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_PROTOCOL_VERSION:
apdu_len =
encode_application_unsigned(&apdu[0], BACNET_PROTOCOL_VERSION);
break;
case PROP_PROTOCOL_REVISION:
apdu_len =
encode_application_unsigned(&apdu[0],
BACNET_PROTOCOL_REVISION);
break;
case PROP_PROTOCOL_SERVICES_SUPPORTED:
/* Note: list of services that are executed, not initiated. */
bitstring_init(&bit_string);
for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) {
/* automatic lookup based on handlers set */
bitstring_set_bit(&bit_string, (uint8_t) i,
apdu_service_supported((BACNET_SERVICES_SUPPORTED) i));
}
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
/* Note: this is the list of objects that can be in this device,
not a list of objects that this device can access */
bitstring_init(&bit_string);
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
/* initialize all the object types to not-supported */
bitstring_set_bit(&bit_string, (uint8_t) i, false);
}
/* set the object types with objects to supported */
i = 0;
pObject = &Object_Table[i];
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
if ((pObject->Object_Count) && (pObject->Object_Count() > 0)) {
bitstring_set_bit(&bit_string, pObject->Object_Type, true);
}
pObject++;
}
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
break;
case PROP_OBJECT_LIST:
count = Device_Object_List_Count();
/* Array element zero is the number of objects in the list */
if (rpdata->array_index == 0)
apdu_len = encode_application_unsigned(&apdu[0], count);
/* if no index was specified, then try to encode the entire list */
/* into one packet. Note that more than likely you will have */
/* to return an error if the number of encoded objects exceeds */
/* your maximum APDU size. */
else if (rpdata->array_index == BACNET_ARRAY_ALL) {
for (i = 1; i <= count; i++) {
if (Device_Object_List_Identifier(i, &object_type,
&instance)) {
len =
encode_application_object_id(&apdu[apdu_len],
object_type, instance);
apdu_len += len;
/* assume next one is the same size as this one */
/* can we all fit into the APDU? */
if ((apdu_len + len) >= MAX_APDU) {
/* Abort response */
rpdata->error_code =
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
apdu_len = BACNET_STATUS_ABORT;
break;
}
} else {
/* error: internal error? */
rpdata->error_class = ERROR_CLASS_SERVICES;
rpdata->error_code = ERROR_CODE_OTHER;
apdu_len = BACNET_STATUS_ERROR;
break;
}
}
} else {
if (Device_Object_List_Identifier(rpdata->array_index,
&object_type, &instance))
apdu_len =
encode_application_object_id(&apdu[0], object_type,
instance);
else {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
apdu_len = BACNET_STATUS_ERROR;
}
}
break;
case PROP_MAX_APDU_LENGTH_ACCEPTED:
apdu_len = encode_application_unsigned(&apdu[0], MAX_APDU);
break;
case PROP_SEGMENTATION_SUPPORTED:
apdu_len =
encode_application_enumerated(&apdu[0],
Device_Segmentation_Supported());
break;
case PROP_APDU_TIMEOUT:
apdu_len = encode_application_unsigned(&apdu[0], apdu_timeout());
break;
case PROP_NUMBER_OF_APDU_RETRIES:
apdu_len = encode_application_unsigned(&apdu[0], apdu_retries());
break;
case PROP_DEVICE_ADDRESS_BINDING:
/* FIXME: encode the list here, if it exists */
break;
case PROP_DATABASE_REVISION:
apdu_len =
encode_application_unsigned(&apdu[0],
Device_Database_Revision());
break;
case PROP_MAX_INFO_FRAMES:
apdu_len =
encode_application_unsigned(&apdu[0],
dlmstp_max_info_frames());
break;
case PROP_MAX_MASTER:
apdu_len =
encode_application_unsigned(&apdu[0], dlmstp_max_master());
break;
case 512:
apdu_len = encode_application_unsigned(&apdu[0], stack_size());
break;
case 513:
apdu_len = encode_application_unsigned(&apdu[0], stack_unused());
break;
case 9600:
apdu_len =
encode_application_unsigned(&apdu[0], rs485_baud_rate());
break;
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) && (rpdata->object_property != PROP_OBJECT_LIST) &&
(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;
}
bool Device_Write_Property_Local(
BACNET_WRITE_PROPERTY_DATA * wp_data)
{
bool status = false; /* return value - false=error */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
uint8_t max_master = 0;
/* 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_OBJECT_LIST) &&
(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 ((int) wp_data->object_property) {
case PROP_OBJECT_IDENTIFIER:
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
(Device_Set_Object_Instance_Number(value.type.
Object_Id.instance))) {
eeprom_bytes_write(NV_EEPROM_DEVICE_0,
(uint8_t *) & value.type.Object_Id.instance, 4);
/* we could send an I-Am broadcast to let the world know */
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;
}
break;
case PROP_MAX_INFO_FRAMES:
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
if (value.type.Unsigned_Int <= 255) {
dlmstp_set_max_info_frames(value.type.Unsigned_Int);
status = true;
} else {
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;
}
break;
case PROP_MAX_MASTER:
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
if ((value.type.Unsigned_Int > 0) &&
(value.type.Unsigned_Int <= 127)) {
max_master = value.type.Unsigned_Int;
dlmstp_set_max_master(max_master);
eeprom_bytes_write(NV_EEPROM_MAX_MASTER, &max_master, 1);
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;
}
break;
case PROP_OBJECT_NAME:
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
status =
bacnet_name_write_unique(NV_EEPROM_DEVICE_NAME,
wp_data->object_type, wp_data->object_instance,
&value.type.Character_String, &wp_data->error_class,
&wp_data->error_code);
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
}
break;
case PROP_DESCRIPTION:
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
status =
bacnet_name_write(NV_EEPROM_DEVICE_DESCRIPTION,
&value.type.Character_String, &wp_data->error_class,
&wp_data->error_code);
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
}
break;
case PROP_LOCATION:
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
status =
bacnet_name_write(NV_EEPROM_DEVICE_LOCATION,
&value.type.Character_String, &wp_data->error_class,
&wp_data->error_code);
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
}
break;
case 9600:
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
if ((value.type.Unsigned_Int <= 115200) &&
(rs485_baud_rate_set(value.type.Unsigned_Int))) {
status = true;
} else {
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;
}
break;
case PROP_OBJECT_TYPE:
case PROP_VENDOR_NAME:
case PROP_FIRMWARE_REVISION:
case PROP_APPLICATION_SOFTWARE_VERSION:
case PROP_DAYLIGHT_SAVINGS_STATUS:
case PROP_PROTOCOL_VERSION:
case PROP_PROTOCOL_REVISION:
case PROP_PROTOCOL_SERVICES_SUPPORTED:
case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED:
case PROP_OBJECT_LIST:
case PROP_MAX_APDU_LENGTH_ACCEPTED:
case PROP_SEGMENTATION_SUPPORTED:
case PROP_DEVICE_ADDRESS_BINDING:
case PROP_DATABASE_REVISION:
case 512:
case 513:
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
+65
View File
@@ -0,0 +1,65 @@
/**************************************************************************
*
* Copyright (C) 2009 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 <stdlib.h>
#include "hardware.h"
#include "eeprom.h"
/* Internal EEPROM of the AVR - http://supp.iar.com/Support/?note=45745 */
int eeprom_bytes_read(
uint16_t eeaddr, /* EEPROM starting memory address (offset of zero) */
uint8_t * buf, /* data to store */
int len)
{ /* number of bytes of data to read */
int count = 0; /* return value */
while (len) {
__EEGET(buf[count], eeaddr);
count++;
eeaddr++;
len--;
}
return count;
}
int eeprom_bytes_write(
uint16_t eeaddr, /* EEPROM starting memory address */
uint8_t * buf, /* data to send */
int len)
{ /* number of bytes of data */
int count = 0;
while (len) {
__EEPUT(eeaddr, buf[count]);
count++;
eeaddr++;
len--;
}
return count;
}
+46
View File
@@ -0,0 +1,46 @@
/**************************************************************************
*
* Copyright (C) 2009 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 EEPROM_H
#define EEPROM_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int eeprom_bytes_read(
uint16_t ee_address, /* EEPROM starting memory address */
uint8_t * buffer, /* data to store */
int nbytes); /* number of bytes of data to read */
int eeprom_bytes_write(
uint16_t ee_address, /* EEPROM starting memory address */
uint8_t * buffer, /* data to send */
int nbytes); /* number of bytes of data */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+354
View File
@@ -0,0 +1,354 @@
PICS 0
BACnet Protocol Implementation Conformance Statement
--
--
-- BACnet Development Kit
-- bacnetdevelopmentkit.com
-- Author: Steve Karg
--
--
Vendor Name: "BACnet Stack at SourceForge"
Product Name: "bdk-atxx4-mstp"
Product Model Number: "bdk-atxx4-mstp"
Product Description: "BACnet Development Kit"
BIBBs Supported:
{
-- The BIBBs may be any of:
-- DS-RP-A
DS-RP-B
DS-RPM-B
-- DS-RPM-A
-- DS-RPC-A DS-RPC-B
-- DS-WP-A
DS-WP-B
-- DS-WPM-A DS-WPM-B
-- DS-COV-A DS-COV-B
-- DS-COVP-A DS-COVP-B
-- DS-COVU-A DS-COVU-B
-- AE-N-A AE-N-I-B AE-N-E-B
-- AE-ACK-A AE-ACK-B
-- AE-ASUM-A AE-ASUM-B
-- AE-ESUM-A AE-ESUM-B
-- AE-INFO-A AE-INFO-B
-- AE-LS-A AE-LS-B
-- SCHED-A SCHED-I-B SCHED-E-B
-- T-VMT-A T-VMT-I-B T-VMT-E-B
-- T-ATR-A T-ATR-B
-- DM-DDB-A
DM-DDB-B
-- DM-DOB-A
DM-DOB-B
-- DM-DCC-A
DM-DCC-B
-- DM-PT-A DM-PT-B
-- DM-TM-A DM-TM-B
-- DM-TS-A
-- DM-TS-B
-- DM-UTC-A
-- DM-UTC-B
-- DM-RD-A
DM-RD-B
-- DM-BR-A DM-BR-B
-- DM-R-A DM-R-B
-- DM-LM-A DM-LM-B
-- DM-OCD-A DM-OCD-B
-- DM-VT-A DM-VT-B
-- NM-CE-A NM-CE-B
-- NM-RC-A NM-RC-B
}
BACnet Standard Application Services Supported:
{
-- AcknowledgeAlarm Initiate Execute
-- ConfirmedCOVNotification Initiate Execute
-- UnconfirmedCOVNotification Initiate Execute
-- ConfirmedEventNotification Initiate Execute
-- UnconfirmedEventNotification Initiate Execute
-- GetAlarmSummary Initiate Execute
-- GetEnrollmentSummary Initiate Execute
-- AtomicReadFile Initiate Execute
-- AtomicWriteFile Initiate Execute
-- AddListElement Initiate Execute
-- RemoveListElement Initiate Execute
-- CreateObject Initiate Execute
-- DeleteObject Initiate Execute
ReadProperty Execute
-- ReadpropertyConditional Initiate Execute
ReadPropertyMultiple Execute
-- SubscribeCOV Initiate Execute
WriteProperty Execute
-- WritePropertyMultiple Initiate Execute
DeviceCommunicationControl Execute
-- ConfirmedPrivateTransfer Initiate Execute
-- UnconfirmedPrivateTransfer Initiate Execute
-- TimeSynchronization Initiate Execute
Who-Has Execute
I-Have Initiate
Who-Is Execute
I-Am Initiate
-- VT-Open Initiate Execute
-- VT-Close Initiate Execute
-- VT-Data Initiate Execute
-- ConfirmedTextMessage Initiate Execute
-- UnconfirmedTextMessage Initiate Execute
ReinitializeDevice Execute
-- RequestKey Initiate Execute
-- Authenticate Initiate Execute
-- UTCTimeSynchronization Initiate Execute
-- ReadRange Initiate Execute
-- GetEventInformation Initiate Execute
-- LifeSafetyOperation Initiate Execute
-- SubscribeCOVProperty Initiate Execute
-- RequestKey Initiate Execute
-- Authenticate Initiate Execute
}
Standard Object-Types Supported:
{
Analog Input
-- Analog Output Createable Deleteable
Analog Value
-- Averaging Createable Deleteable
Binary Input
Binary Output
-- Binary Value Createable Deleteable
-- Calendar Createable Deleteable
-- Command Createable Deleteable
Device
-- Event Enrollment Createable Deleteable
-- File Createable Deleteable
-- Group Createable Deleteable
-- Loop Createable Deleteable
-- Multi-state Input Createable Deleteable
-- Multi-state Output Createable Deleteable
-- Multi-state Value Createable Deleteable
-- Notification Class Createable Deleteable
-- Program Createable Deleteable
-- Schedule Createable Deleteable
-- Life Safety Point Createable Deleteable
-- Life Safety Zone Createable Deleteable
-- Trend Log Createable Deleteable
-- Load Control Createable Deleteable
}
Data Link Layer Option:
{
-- ISO 8802-3, 10BASE5
-- ISO 8802-3, 10BASE2
-- ISO 8802-3, 10BASET
-- ISO 8802-3, Fiber
-- ARCNET, coax star
-- ARCNET, coax bus
-- ARCNET, twisted pair star
-- ARCNET, twisted pair bus
-- ARCNET, fiber star
MS/TP master. Baud rate(s): 9600, 19200, 38400, 57600, 76800, 115200
-- MS/TP slave. Baud rate(s): 9600
-- Point-To-Point. Modem, Baud rate(s): 14.4k
-- Point-To-Point. Modem, Autobaud range: 9600 to 28.8k
-- BACnet/IP, 'DIX' Ethernet
-- BACnet/IP, PPP
-- Other
}
Character Sets Supported:
{
ANSI X3.4
-- Other Character Sets not supported
-- IBM/Microsoft DBCS
-- JIS C 6226
-- ISO 10646 (ICS-4)
-- ISO 10646 (UCS2)
}
Special Functionality:
{
Maximum APDU size in octets: 128 -- MS/TP Maximum 501 less NL Header
-- Maximum APDU size in octets: 480
-- Segmented Requests Supported, window size: 1
-- Segmented Responses Supported, window size: 1
-- Router
}
List of Objects in Test Device:
{
{
object-identifier: (Device, 90) Writable
object-name: "DEVICE-90" Writable
object-type: Device
system-status: operational
vendor-name: "BACnet Stack at SourceForge"
vendor-identifier: 260
model-name: "bdk-atxx4-mstp"
firmware-revision: "1.0"
application-software-version: "1.0"
protocol-version: 1
protocol-revision: 10
protocol-services-supported: (
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
T,F,T,T, -- Read-Property,, Read-Property-Multiple, Write-Property,
F,T,F,F, -- , Device-Communication-Control,,,
T,F,F,F, -- Reinitialize-Device,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,T,T,F, -- , Who-Has, Who-Is,,
F,F,F,F -- ,,,,
)
protocol-object-types-supported: (
T,F,T,T, -- Analog Input,, Analog Value, Binary Input,
T,F,F,F, -- Binary Output,,,,
T,F,F,F, -- Device,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F,F, -- ,,,,
F,F,F -- ,,,
)
object-list: {
(Device, 90), (Analog Input, 0), (Analog Input, 1), (Analog Value, 0),
(Analog Value, 1), (Binary Input, 0), (Binary Input, 1),
(Binary Input, 2),
(Binary Input, 3), (Binary Input, 4), (Binary Output, 0),
(Binary Output, 1) }
max-apdu-length-accepted: 128
segmentation-supported: no-segmentation
apdu-timeout: 3000
number-of-APDU-retries: 3
device-address-binding: ?
database-revision: ?
max-master: 127 Writable
max-info-frames: 1 Writable
description: "BACnet Development Kit" Writable
location: "default location" Writable
-- Found 12 Objects
},
{
object-identifier: (Analog Input, 0)
object-name: "AI-0"
object-type: Analog Input
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
units: percent
},
{
object-identifier: (Analog Input, 1)
object-name: "AI-1"
object-type: Analog Input
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
units: percent
},
{
object-identifier: (Analog Value, 0)
object-name: "AV-0"
object-type: Analog Value
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
units: percent
},
{
object-identifier: (Analog Value, 1)
object-name: "AV-1"
object-type: Analog Value
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
units: percent
},
{
object-identifier: (Binary Input, 0)
object-name: "BI-0"
object-type: Binary Input
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
polarity: normal
},
{
object-identifier: (Binary Input, 1)
object-name: "BI-1"
object-type: Binary Input
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
polarity: normal
},
{
object-identifier: (Binary Input, 2)
object-name: "BI-2"
object-type: Binary Input
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
polarity: normal
},
{
object-identifier: (Binary Input, 3)
object-name: "BI-3"
object-type: Binary Input
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
polarity: normal
},
{
object-identifier: (Binary Input, 4)
object-name: "BI-4"
object-type: Binary Input
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
polarity: normal
},
{
object-identifier: (Binary Output, 0)
object-name: "BO-0"
object-type: Binary Output
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
polarity: normal
priority-array: ?
relinquish-default: inactive
active-text: "on"
inactive-text: "off"
},
{
object-identifier: (Binary Output, 1)
object-name: "BO-1"
object-type: Binary Output
present-value: ?
status-flags: {false,false,false,false}
event-state: normal
out-of-service: FALSE
polarity: normal
priority-array: ?
relinquish-default: inactive
active-text: "on"
inactive-text: "off"
}
}
End of BACnet Protocol Implementation Conformance Statement
+93
View File
@@ -0,0 +1,93 @@
/************************************************************************
*
* Copyright (C) 2009 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 "hardware.h"
#if defined(__GNUC__) && (__GNUC__ >= 4)
/* AVR fuse settings for ATmega644P */
FUSES = {
/* == LOW FUSE or LFUSE settings == */
/* CKSEL3..0- Clock Select Configuration
CKSEL3 CKSEL2 CKSEL1 CKSEL0 Description
1 1 1 x 1111-1000=Low Power Crystal Oscillator
0 1 1 x 0111-0110=Full Swing Crystal Oscillator
0 1 0 x 0101-0100=Low Frequency Crystal Oscillator
0 0 1 1 Internal 128kHz RC Oscillator
0 0 1 0 Calibrated Internal RC Oscillator
0 0 0 0 External Clock]
SUT1..0 - Clock Start Up Time selection
If CKSEL0=0, then SUT1..0 is 14CK+: 00=4.1ms,01=65ms,10=BOD,11=4.1ms
If CKSEL0=1, then SUT1..0 is 14CK+: 00=65ms,01=BOD,10=4.1ms,11=65ms
BOD means wait until internal Brown Out Detect Voltage is sufficient.
*/
/* CKOUT: clock output on CKOUT pin */
/* CKDIV8: divide clock by 8 */
/* External Ceramic Resonator - configuration */
/* Full Swing Crystal Oscillator Clock Selection */
/* Ceramic resonator, slowly rising power 1K CK 14CK + 65 ms */
/* .low = (FUSE_CKSEL3 & FUSE_SUT0 & FUSE_SUT1), */
/* Crystal Oscillator, 16K CK + 14CK + BOD Enabled */
/* note: fuses are enabled by clearing the bit, so
any fuses listed below are cleared fuses,
or are CKSEL or SUT bits that are zero. */
.low = (FUSE_CKSEL3 & FUSE_SUT1),
/* == HIGH FUSE or HFUSE settings == */
/* BOOTRST: Enable Bootloader Reset Vector */
/* EESAVE: Enable preserve EEPROM on Chip Erase */
/* WDTON: Enable watchdog timer always on */
/* SPIEN: Enable Serial Program and Data Downloading */
/* JTAGEN: Enable JTAG */
/* OCDEN: Enable OCD */
/* BOOTSZ configuration:
BOOTSZ1 BOOTSZ0 Boot Size
------- ------- ---------
1 1 512
1 0 1024
0 1 2048
0 0 4096
*/
/* note: fuses are enabled by clearing the bit, so
any fuses listed below are cleared fuses,
or are BOOTSZ bits that are zero. */
.high = (FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN),
/* == EXTENDED FUSE or EFUSE settings == */
/* BODLEVEL configuration
BODLEVEL2 BODLEVEL1 BODLEVEL0 Voltage
--------- --------- --------- --------
1 1 1 disabled
1 1 0 1.8V
1 0 1 2.7V
1 0 0 4.3V
*/
/* note: fuses are enabled by clearing the bit, so
any fuses listed below are cleared fuses,
or are BODLEVEL bits that are zero. */
/* Brown-out detection VCC=4.3V */
.extended = (FUSE_BODLEVEL1 & FUSE_BODLEVEL0)
};
/* AVR lock bits - unlocked */
LOCKBITS = LOCKBITS_DEFAULT;
#endif
+91
View File
@@ -0,0 +1,91 @@
/**************************************************************************
*
* 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
#if !defined(F_CPU)
/* The processor clock frequency */
#define F_CPU 18432000UL
#endif
/* IAR compiler specific configuration */
#if defined(__ICCAVR__)
#if defined(__ATmega644P__)
#include <iom644p.h>
#endif
#if defined(__ATmega1284P__)
#include <iom1284p.h>
#endif
#endif
/* AVR-GCC compiler specific configuration */
#if defined(__GNUC__)
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/power.h>
#if defined(__AVR_ATmega644P__)
/* defined for ATmega644p */
#elif defined(__AVR_ATmega1284P__)
/* defined for ATmega1284p */
#else
#error For ATmega644P or ATmega1284p only (-mmcu=atmega644p -mmcu=atmega1284p)
#endif
#endif
#if defined (__CROSSWORKS_AVR)
#include <avr.h>
#if (__TARGET_PROCESSOR != ATmega644P)
#error Firmware is configured for ATmega644P only
#endif
#endif
#include "iar2gcc.h"
#include "bits.h"
/* SEEPROM is 24LC128 */
/*#define SEEPROM_PAGE_SIZE 64 */
/*#define SEEPROM_WORD_ADDRESS_16BIT 1 */
/* SEEPROM is 24C16 */
#ifndef SEEPROM_PAGE_SIZE
#define SEEPROM_PAGE_SIZE 16
#endif
#ifndef SEEPROM_WORD_ADDRESS_16BIT
#define SEEPROM_WORD_ADDRESS_16BIT 0
#endif
/* Serial EEPROM address */
#define SEEPROM_I2C_ADDRESS 0xA0
/* Serial EEPROM clocking speed - usually 100000 or 400000 */
#define SEEPROM_I2C_CLOCK 400000L
/* Serial EEPROM max write cycle in milliseconds as defined by datasheet */
#define SEEPROM_WRITE_CYCLE 5
#define LED_2 2
#define LED_3 3
#define LED_4 1
#define LED_5 0
#define MAX_LEDS 4
#endif
Binary file not shown.
+345
View File
@@ -0,0 +1,345 @@
/**************************************************************************
*
* Copyright (C) 2012 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 IAR2GCC_H
#define IAR2GCC_H
/* common embedded extensions for different compilers */
#if !defined(F_CPU)
#error You must define F_CPU - clock frequency!
#endif
#if defined (__CROSSWORKS_AVR)
#include <inavr.h>
#include <stdint.h>
#endif
/* IAR */
#if defined(__ICCAVR__)
#include <inavr.h>
#include <intrinsics.h>
#include <stdint.h>
/* inline function */
static inline void _delay_us(
uint8_t microseconds)
{
do {
__delay_cycles(F_CPU / 1000000UL);
} while (microseconds--);
}
#endif
#if defined(__GNUC__)
#include <util/delay.h>
#endif
/* adjust some definitions to common versions */
#if defined (__CROSSWORKS_AVR)
#if (__TARGET_PROCESSOR == ATmega644P)
#define PRR PRR0
#define UBRR0 UBRR0W
#define UBRR1 UBRR1W
#define PA0 PORTA0
#define PA1 PORTA1
#define PA2 PORTA2
#define PA3 PORTA3
#define PA4 PORTA4
#define PA5 PORTA5
#define PA6 PORTA6
#define PA7 PORTA7
#define PB0 PORTB0
#define PB1 PORTB1
#define PB2 PORTB2
#define PB3 PORTB3
#define PB4 PORTB4
#define PB5 PORTB5
#define PB6 PORTB6
#define PB7 PORTB7
#define PC0 PORTC0
#define PC1 PORTC1
#define PC2 PORTC2
#define PC3 PORTC3
#define PC4 PORTC4
#define PC5 PORTC5
#define PC6 PORTC6
#define PC7 PORTC7
#define PD0 PORTD0
#define PD1 PORTD1
#define PD2 PORTD2
#define PD3 PORTD3
#define PD4 PORTD4
#define PD5 PORTD5
#define PD6 PORTD6
#define PD7 PORTD7
#endif
#endif
/* Input/Output Registers */
#if defined(__GNUC__)
#include <avr/io.h>
typedef struct {
unsigned char bit0:1;
unsigned char bit1:1;
unsigned char bit2:1;
unsigned char bit3:1;
unsigned char bit4:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
} BitRegisterType;
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#define GPIO_BITREG(port,bitnum) \
((volatile BitRegisterType*)_SFR_MEM_ADDR(port) \
)->bit ## bitnum
#define PINA_Bit0 GPIO_BITREG(PINA,0)
#define PINA_Bit1 GPIO_BITREG(PINA,1)
#define PINA_Bit2 GPIO_BITREG(PINA,2)
#define PINA_Bit3 GPIO_BITREG(PINA,3)
#define PINA_Bit4 GPIO_BITREG(PINA,4)
#define PINA_Bit5 GPIO_BITREG(PINA,5)
#define PINA_Bit6 GPIO_BITREG(PINA,6)
#define PINA_Bit7 GPIO_BITREG(PINA,7)
#define PORTA_Bit0 GPIO_BITREG(PORTA,0)
#define PORTA_Bit1 GPIO_BITREG(PORTA,1)
#define PORTA_Bit2 GPIO_BITREG(PORTA,2)
#define PORTA_Bit3 GPIO_BITREG(PORTA,3)
#define PORTA_Bit4 GPIO_BITREG(PORTA,4)
#define PORTA_Bit5 GPIO_BITREG(PORTA,5)
#define PORTA_Bit6 GPIO_BITREG(PORTA,6)
#define PORTA_Bit7 GPIO_BITREG(PORTA,7)
#define PINB_Bit0 GPIO_BITREG(PINB,0)
#define PINB_Bit1 GPIO_BITREG(PINB,1)
#define PINB_Bit2 GPIO_BITREG(PINB,2)
#define PINB_Bit3 GPIO_BITREG(PINB,3)
#define PINB_Bit4 GPIO_BITREG(PINB,4)
#define PINB_Bit5 GPIO_BITREG(PINB,5)
#define PINB_Bit6 GPIO_BITREG(PINB,6)
#define PINB_Bit7 GPIO_BITREG(PINB,7)
#define PORTB_Bit0 GPIO_BITREG(PORTB,0)
#define PORTB_Bit1 GPIO_BITREG(PORTB,1)
#define PORTB_Bit2 GPIO_BITREG(PORTB,2)
#define PORTB_Bit3 GPIO_BITREG(PORTB,3)
#define PORTB_Bit4 GPIO_BITREG(PORTB,4)
#define PORTB_Bit5 GPIO_BITREG(PORTB,5)
#define PORTB_Bit6 GPIO_BITREG(PORTB,6)
#define PORTB_Bit7 GPIO_BITREG(PORTB,7)
#define PINC_Bit0 GPIO_BITREG(PINC,0)
#define PINC_Bit1 GPIO_BITREG(PINC,1)
#define PINC_Bit2 GPIO_BITREG(PINC,2)
#define PINC_Bit3 GPIO_BITREG(PINC,3)
#define PINC_Bit4 GPIO_BITREG(PINC,4)
#define PINC_Bit5 GPIO_BITREG(PINC,5)
#define PINC_Bit6 GPIO_BITREG(PINC,6)
#define PINC_Bit7 GPIO_BITREG(PINC,7)
#define PORTC_Bit0 GPIO_BITREG(PORTC,0)
#define PORTC_Bit1 GPIO_BITREG(PORTC,1)
#define PORTC_Bit2 GPIO_BITREG(PORTC,2)
#define PORTC_Bit3 GPIO_BITREG(PORTC,3)
#define PORTC_Bit4 GPIO_BITREG(PORTC,4)
#define PORTC_Bit5 GPIO_BITREG(PORTC,5)
#define PORTC_Bit6 GPIO_BITREG(PORTC,6)
#define PORTC_Bit7 GPIO_BITREG(PORTC,7)
#define PIND_Bit0 GPIO_BITREG(PIND,0)
#define PIND_Bit1 GPIO_BITREG(PIND,1)
#define PIND_Bit2 GPIO_BITREG(PIND,2)
#define PIND_Bit3 GPIO_BITREG(PIND,3)
#define PIND_Bit4 GPIO_BITREG(PIND,4)
#define PIND_Bit5 GPIO_BITREG(PIND,5)
#define PIND_Bit6 GPIO_BITREG(PIND,6)
#define PIND_Bit7 GPIO_BITREG(PIND,7)
#define PORTD_Bit0 GPIO_BITREG(PORTD,0)
#define PORTD_Bit1 GPIO_BITREG(PORTD,1)
#define PORTD_Bit2 GPIO_BITREG(PORTD,2)
#define PORTD_Bit3 GPIO_BITREG(PORTD,3)
#define PORTD_Bit4 GPIO_BITREG(PORTD,4)
#define PORTD_Bit5 GPIO_BITREG(PORTD,5)
#define PORTD_Bit6 GPIO_BITREG(PORTD,6)
#define PORTD_Bit7 GPIO_BITREG(PORTD,7)
#define GPIOR0_Bit0 GPIO_BITREG(GPIOR0,0)
#define GPIOR0_Bit1 GPIO_BITREG(GPIOR0,1)
#define GPIOR0_Bit2 GPIO_BITREG(GPIOR0,2)
#define GPIOR0_Bit3 GPIO_BITREG(GPIOR0,3)
#define GPIOR0_Bit4 GPIO_BITREG(GPIOR0,4)
#define GPIOR0_Bit5 GPIO_BITREG(GPIOR0,5)
#define GPIOR0_Bit6 GPIO_BITREG(GPIOR0,6)
#define GPIOR0_Bit7 GPIO_BITREG(GPIOR0,7)
#define GPIOR1_Bit0 GPIO_BITREG(GPIOR1,0)
#define GPIOR1_Bit1 GPIO_BITREG(GPIOR1,1)
#define GPIOR1_Bit2 GPIO_BITREG(GPIOR1,2)
#define GPIOR1_Bit3 GPIO_BITREG(GPIOR1,3)
#define GPIOR1_Bit4 GPIO_BITREG(GPIOR1,4)
#define GPIOR1_Bit5 GPIO_BITREG(GPIOR1,5)
#define GPIOR1_Bit6 GPIO_BITREG(GPIOR1,6)
#define GPIOR1_Bit7 GPIO_BITREG(GPIOR1,7)
#define GPIOR2_Bit0 GPIO_BITREG(GPIOR2,0)
#define GPIOR2_Bit1 GPIO_BITREG(GPIOR2,1)
#define GPIOR2_Bit2 GPIO_BITREG(GPIOR2,2)
#define GPIOR2_Bit3 GPIO_BITREG(GPIOR2,3)
#define GPIOR2_Bit4 GPIO_BITREG(GPIOR2,4)
#define GPIOR2_Bit5 GPIO_BITREG(GPIOR2,5)
#define GPIOR2_Bit6 GPIO_BITREG(GPIOR2,6)
#define GPIOR2_Bit7 GPIO_BITREG(GPIOR2,7)
#endif
/* Global Interrupts */
#if defined(__GNUC__)
#define __enable_interrupt() sei()
#define __disable_interrupt() cli()
#endif
/* Interrupts */
#if defined(__ICCAVR__)
#define PRAGMA(x) _Pragma( #x )
#define ISR(vec) \
/* function prototype for use with "require protoptypes" option. */ \
PRAGMA( vector=vec ) __interrupt void handler_##vec(void); \
PRAGMA( vector=vec ) __interrupt void handler_##vec(void)
#elif defined(__GNUC__)
#include <avr/interrupt.h>
#elif defined (__CROSSWORKS_AVR)
#define ISR(vec) void handler_##vec(void) __interrupt[vec]
#else
#error ISR() not defined!
#endif
/* Flash */
#if defined(__ICCAVR__)
#define FLASH_DECLARE(x) __flash x
#elif defined(__GNUC__)
#define FLASH_DECLARE(x) x __attribute__((__progmem__))
#elif defined (__CROSSWORKS_AVR)
#define FLASH_DECLARE (x) const __code x
#endif
/* EEPROM */
#if defined(__ICCAVR__)
#define EEPROM_DECLARE(x) __eeprom x
#elif defined(__GNUC__)
#include <avr/eeprom.h>
#define EEPROM_DECLARE(x) x __attribute__((section (".eeprom")))
#if ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || \
((__GNUC__ == 4) && (__GNUC_MINOR__ == 3) && (__GNUC_PATCHLEVEL__ <= 3)))
/* bug in WinAVR - not quite IAR compatible */
#ifndef __EEPUT
#define __EEPUT _EEPUT
#endif
#ifndef __EEGET
#define __EEGET _EEGET
#endif
#endif
#elif defined (__CROSSWORKS_AVR)
/* use functions defined in crt0.s to mimic IAR macros */
void __uint8_eeprom_store(
unsigned char byte,
unsigned addr);
unsigned char __uint8_eeprom_load(
unsigned addr);
#define __EEPUT(addr, var) \
__uint8_eeprom_store((unsigned char)(var), (unsigned)(addr))
#define __EEGET(var, addr) \
(var) = __uint8_eeprom_load((unsigned)(addr))
#endif
/* IAR intrinsic routines */
#if defined(__GNUC__)
/* FIXME: intrinsic routines: map to assembler for size/speed */
#define __multiply_unsigned(x,y) ((x)*(y))
/* FIXME: __root means to not optimize or strip */
#define __root
#endif
/* watchdog defines in GCC */
#if defined(__ICCAVR__) || defined(__CROSSWORKS_AVR)
#define WDTO_15MS 0
#define WDTO_30MS 1
#define WDTO_60MS 2
#define WDTO_120MS 3
#define WDTO_250MS 4
#define WDTO_500MS 5
#define WDTO_1S 6
#define WDTO_2S 7
#endif
/* power macros in GCC-AVR */
#if (defined(__ICCAVR__) && (defined(__ATmega644P__))) || \
(defined(__CROSSWORKS_AVR) && (__TARGET_PROCESSOR == ATmega644P))
#define power_adc_enable() (PRR &= (uint8_t)~(1 << PRADC))
#define power_spi_enable() (PRR &= (uint8_t)~(1 << PRSPI))
#define power_usart0_enable() (PRR &= (uint8_t)~(1 << PRUSART0))
#define power_usart1_enable() (PRR &= (uint8_t)~(1 << PRUSART1))
#define power_timer0_enable() (PRR &= (uint8_t)~(1 << PRTIM0))
#define power_timer1_enable() (PRR &= (uint8_t)~(1 << PRTIM1))
#define power_timer2_enable() (PRR &= (uint8_t)~(1 << PRTIM2))
#endif
#if (defined(__ICCAVR__) && (defined(__ATmega1284P__))) || \
(defined(__CROSSWORKS_AVR) && (__TARGET_PROCESSOR == ATmega1284P))
#define power_adc_enable() (PRR0 &= (uint8_t)~(1 << PRADC))
#define power_spi_enable() (PRR0 &= (uint8_t)~(1 << PRSPI))
#define power_usart0_enable() (PRR0 &= (uint8_t)~(1 << PRUSART0))
#define power_usart1_enable() (PRR0 &= (uint8_t)~(1 << PRUSART1))
#define power_timer0_enable() (PRR0 &= (uint8_t)~(1 << PRTIM0))
#define power_timer1_enable() (PRR0 &= (uint8_t)~(1 << PRTIM1))
#define power_timer2_enable() (PRR0 &= (uint8_t)~(1 << PRTIM2))
#endif
#if (defined(__GNUC__) && ((__GNUC__ == 4) && (__GNUC_MINOR__ < 5)))
#if defined(__AVR_ATmega644P__)
/* bug in WinAVR - fixed in later versions */
#define power_usart1_enable() (PRR &= (uint8_t)~(1 << PRUSART1))
#elif defined(__AVR_ATmega1284P__)
#define power_usart1_enable() (PRR0 &= (uint8_t)~(1 << PRUSART1))
#endif
#endif
#if defined(__CROSSWORKS_AVR)
#define inline
#endif
#endif
+64
View File
@@ -0,0 +1,64 @@
/**************************************************************************
*
* Copyright (C) 2009 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 "hardware.h"
/* me */
#include "init.h"
void init(
void)
{
/* clear the MCU Status Register */
MCUSR = 0;
/* Initialize the Clock Prescaler */
/* The default CLKPSx bits are factory set to 0011 */
/* Enable the Clock Prescaler */
CLKPR = _BV(CLKPCE);
/* CLKPS3 CLKPS2 CLKPS1 CLKPS0 Clock Division Factor
------ ------ ------ ------ ---------------------
0 0 0 0 1
0 0 0 1 2
0 0 1 0 4
0 0 1 1 8
0 1 0 0 16
0 1 0 1 32
0 1 1 0 64
0 1 1 1 128
1 0 0 0 256
1 x x x Reserved
*/
/* Set the CLKPS3..0 bits to Prescaler of 1 */
CLKPR = 0;
/* Initialize I/O ports */
/* For Port DDRx (Data Direction) Input=0, Output=1 */
/* For Port PORTx (Bit Value) TriState=0, High=1 */
DDRA = 0;
PORTA = 0;
DDRB = 0;
PORTB = 0;
DDRC = 0;
PORTC = 0;
DDRD = 0;
PORTD = 0;
}
+39
View File
@@ -0,0 +1,39 @@
/**************************************************************************
*
* Copyright (C) 2009 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 INIT_H
#define INIT_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void init(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+203
View File
@@ -0,0 +1,203 @@
/**************************************************************************
*
* Copyright (C) 2009 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 <stdbool.h>
#include "hardware.h"
#include "timer.h"
/* me */
#include "input.h"
#ifndef BDK_VERSION
#define BDK_VERSION 4
#endif
static uint8_t Address_Switch;
static uint8_t Buttons;
static struct itimer Debounce_Timer;
#ifndef BDK_V1_HACK
#define BDK_V1_HACK 0
#endif
#if BDK_V1_HACK
/* version 1 BDK workaournd for floating inputs */
static void input_switch_workaround(
void)
{
/* configure the port pins for the switch - as outputs */
BIT_SET(DDRA, DDA0);
BIT_SET(DDRA, DDA1);
BIT_SET(DDRA, DDA2);
BIT_SET(DDRA, DDA3);
BIT_SET(DDRA, DDA4);
BIT_SET(DDRA, DDA5);
BIT_SET(DDRA, DDA6);
/* turn off the outputs */
BIT_CLEAR(PORTA, PORTA0);
BIT_CLEAR(PORTA, PORTA1);
BIT_CLEAR(PORTA, PORTA2);
BIT_CLEAR(PORTA, PORTA3);
BIT_CLEAR(PORTA, PORTA4);
BIT_CLEAR(PORTA, PORTA5);
BIT_CLEAR(PORTA, PORTA6);
/* configure the port pins for the switch - as inputs */
BIT_CLEAR(DDRA, DDA0);
BIT_CLEAR(DDRA, DDA1);
BIT_CLEAR(DDRA, DDA2);
BIT_CLEAR(DDRA, DDA3);
BIT_CLEAR(DDRA, DDA4);
BIT_CLEAR(DDRA, DDA5);
BIT_CLEAR(DDRA, DDA6);
return;
}
#endif
/* debounce the inputs */
void input_task(
void)
{
uint8_t value;
static uint8_t old_address = 0;
static uint8_t old_buttons = 0;
/* only check the inputs every debounce time */
if (timer_interval_expired(&Debounce_Timer)) {
timer_interval_reset(&Debounce_Timer);
/* pins used are PA6, PA5, PA4, PA3, PA2, PA1, PA0 */
#if BDK_V1_HACK
/* version 1 BDK - workaround */
value = (PINA & 0x7F);
#else
/* version 2 BDK - has inverted inputs */
value = ~PINA;
value &= 0x7F;
#endif
if (value == old_address) {
/* stable value */
Address_Switch = old_address;
}
old_address = value;
#if (BDK_VERSION==4)
/* pins used are PB3, PB2, PB1 */
value = BITMASK_CHECK(PINB, 0x0E);
value >>= 1;
#else
/* pins used are PB4, PB3, PB2, PB1, PB0 */
value = BITMASK_CHECK(PINB, 0x1F);
#endif
if (value == old_buttons) {
/* stable value */
Buttons = old_buttons;
}
old_buttons = value;
}
#if BDK_V1_HACK
input_switch_workaround();
#endif
}
uint8_t input_address(
void)
{
return Address_Switch;
}
uint8_t input_rotary_value(
uint8_t index)
{
return Buttons;
}
bool input_button_value(
uint8_t index)
{
bool value = false;
switch (index) {
case 0:
value = BIT_CHECK(Buttons, 0);
break;
case 1:
value = BIT_CHECK(Buttons, 1);
break;
case 2:
value = BIT_CHECK(Buttons, 2);
break;
case 3:
value = BIT_CHECK(Buttons, 3);
break;
case 4:
value = BIT_CHECK(Buttons, 4);
break;
default:
break;
}
return value;
}
void input_init(
void)
{
/* configure the port pins for the switch */
BIT_CLEAR(DDRA, DDA0);
BIT_CLEAR(DDRA, DDA1);
BIT_CLEAR(DDRA, DDA2);
BIT_CLEAR(DDRA, DDA3);
BIT_CLEAR(DDRA, DDA4);
BIT_CLEAR(DDRA, DDA5);
BIT_CLEAR(DDRA, DDA6);
/* activate the internal pull up resistors */
BIT_SET(PORTA, PORTA0);
BIT_SET(PORTA, PORTA1);
BIT_SET(PORTA, PORTA2);
BIT_SET(PORTA, PORTA3);
BIT_SET(PORTA, PORTA4);
BIT_SET(PORTA, PORTA5);
BIT_SET(PORTA, PORTA6);
/* configure the port pins for rotary switch inputs */
#if (BDK_VERSION==4)
BIT_CLEAR(DDRB, DDB1);
BIT_CLEAR(DDRB, DDB2);
BIT_CLEAR(DDRB, DDB3);
/* activate the internal pull up resistors */
BIT_SET(PORTB, PORTB1);
BIT_SET(PORTB, PORTB2);
BIT_SET(PORTB, PORTB3);
#else
BIT_CLEAR(DDRB, DDB1);
BIT_CLEAR(DDRB, DDB2);
BIT_CLEAR(DDRB, DDB3);
BIT_CLEAR(DDRB, DDB4);
/* activate the internal pull up resistors */
BIT_SET(PORTB, PORTB1);
BIT_SET(PORTB, PORTB2);
BIT_SET(PORTB, PORTB3);
BIT_SET(PORTB, PORTB4);
#endif
timer_interval_start(&Debounce_Timer, 30);
}
+46
View File
@@ -0,0 +1,46 @@
/**************************************************************************
*
* Copyright (C) 2009 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 INPUT_H
#define INPUT_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void input_init(
void);
void input_task(
void);
uint8_t input_address(
void);
bool input_button_value(
uint8_t index);
uint8_t input_rotary_value(
uint8_t index);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+226
View File
@@ -0,0 +1,226 @@
/**************************************************************************
*
* Copyright (C) 2009 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 "timer.h"
#include "led.h"
#ifndef BDK_VERSION
#define BDK_VERSION 4
#endif
static struct itimer Off_Delay_Timer[MAX_LEDS];
/*************************************************************************
* Description: Turn on an LED
* Returns: none
* Notes: none
*************************************************************************/
void led_on(
uint8_t index)
{
switch (index) {
case 0:
BIT_SET(PORTD, PD7);
break;
case 1:
BIT_SET(PORTD, PD6);
break;
case 2:
#if (BDK_VERSION==4)
BIT_SET(PORTB, PB0);
#else
BIT_SET(PORTC, PC7);
#endif
break;
case 3:
#if (BDK_VERSION==4)
BIT_SET(PORTB, PB4);
#else
BIT_SET(PORTC, PC6);
#endif
break;
default:
break;
}
if (index < MAX_LEDS) {
timer_interval_no_expire(&Off_Delay_Timer[index]);
}
}
/*************************************************************************
* Description: Turn off an LED
* Returns: none
* Notes: none
*************************************************************************/
void led_off(
uint8_t index)
{
switch (index) {
case 0:
BIT_CLEAR(PORTD, PD7);
break;
case 1:
BIT_CLEAR(PORTD, PD6);
break;
case 2:
#if (BDK_VERSION==4)
BIT_CLEAR(PORTB, PB0);
#else
BIT_CLEAR(PORTC, PC7);
#endif
break;
case 3:
#if (BDK_VERSION==4)
BIT_CLEAR(PORTB, PB4);
#else
BIT_CLEAR(PORTC, PC6);
#endif
break;
default:
break;
}
if (index < MAX_LEDS) {
timer_interval_no_expire(&Off_Delay_Timer[index]);
}
}
/*************************************************************************
* Description: Get the state of the LED
* Returns: true if on, false if off.
* Notes: none
*************************************************************************/
bool led_state(
uint8_t index)
{
switch (index) {
case 0:
return (BIT_CHECK(PIND, PIND7));
case 1:
return (BIT_CHECK(PIND, PIND6));
case 2:
#if (BDK_VERSION==4)
return (BIT_CHECK(PINB, PINC0));
#else
return (BIT_CHECK(PINC, PINC7));
#endif
case 3:
#if (BDK_VERSION==4)
return (BIT_CHECK(PINB, PINC4));
#else
return (BIT_CHECK(PINC, PINC6));
#endif
default:
break;
}
return false;
}
/*************************************************************************
* Description: Toggle the state of the setup LED
* Returns: none
* Notes: none
*************************************************************************/
void led_toggle(
uint8_t index)
{
if (led_state(index)) {
led_off(index);
} else {
led_on(index);
}
}
/*************************************************************************
* Description: Delay before going off to give minimum brightness.
* Returns: none
* Notes: none
*************************************************************************/
void led_off_delay(
uint8_t index,
uint32_t delay_ms)
{
if (index < MAX_LEDS) {
timer_interval_start(&Off_Delay_Timer[index], delay_ms);
}
}
/*************************************************************************
* Description: Turn on, and delay before going off.
* Returns: none
* Notes: none
*************************************************************************/
void led_on_interval(
uint8_t index,
uint16_t interval_ms)
{
if (index < MAX_LEDS) {
led_on(index);
timer_interval_start(&Off_Delay_Timer[index], interval_ms);
}
}
/*************************************************************************
* Description: Task for blinking LED
* Returns: none
* Notes: none
*************************************************************************/
void led_task(
void)
{
uint8_t i; /* loop counter */
for (i = 0; i < MAX_LEDS; i++) {
if (timer_interval_expired(&Off_Delay_Timer[i])) {
timer_interval_no_expire(&Off_Delay_Timer[i]);
led_off(i);
}
}
}
/*************************************************************************
* Description: Initialize the LED hardware
* Returns: none
* Notes: none
*************************************************************************/
void led_init(
void)
{
uint8_t i; /* loop counter */
/* configure the port pins as outputs */
BIT_SET(DDRD, DDD7);
BIT_SET(DDRD, DDD6);
#if (BDK_VERSION==4)
BIT_SET(DDRB, DDB0);
BIT_SET(DDRB, DDB4);
#else
BIT_SET(DDRC, DDC7);
BIT_SET(DDRC, DDC6);
#endif
for (i = 0; i < MAX_LEDS; i++) {
led_on_interval(i, 500);
}
}
+56
View File
@@ -0,0 +1,56 @@
/**************************************************************************
*
* Copyright (C) 2009 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 LED_H
#define LED_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void led_on(
uint8_t index);
void led_on_interval(
uint8_t index,
uint16_t interval_ms);
void led_off(
uint8_t index);
void led_off_delay(
uint8_t index,
uint32_t delay_ms);
void led_toggle(
uint8_t index);
bool led_state(
uint8_t index);
void led_task(
void);
void led_init(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+78
View File
@@ -0,0 +1,78 @@
/************************************************************************
*
* Copyright (C) 2009 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 "hardware.h"
#include "init.h"
#include "stack.h"
#include "timer.h"
#include "input.h"
#include "led.h"
#include "adc.h"
#include "nvdata.h"
#include "timer.h"
#include "rs485.h"
#include "serial.h"
#include "bacnet.h"
#include "test.h"
#include "watchdog.h"
#include "version.h"
/* global - currently the version of the stack */
char *BACnet_Version = BACNET_VERSION_TEXT;
/* For porting to IAR, see:
http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/
int main(
void)
{
init();
/* Configure the watchdog timer - Disabled for debugging */
#ifdef NDEBUG
watchdog_init(2000);
#else
watchdog_init(0);
#endif
timer_init();
adc_init();
input_init();
seeprom_init();
rs485_init();
serial_init();
led_init();
bacnet_init();
test_init();
/* Enable global interrupts */
__enable_interrupt();
for (;;) {
watchdog_reset();
input_task();
bacnet_task();
led_task();
test_task();
}
}
+119
View File
@@ -0,0 +1,119 @@
/************************************************************************
*
* Copyright (C) 2009 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 NVDATA_H
#define NVDATA_H
#include "seeprom.h"
#include "eeprom.h"
/*=============== EEPROM ================*/
/* define the MAC, BAUD, MAX Master, Device Instance internal
so that bootloader *could* use them. */
/* note: MAC could come from DIP switch, or be in non-volatile memory */
#define NV_EEPROM_MAC 0
/* 9=9.6k, 19=19.2k, 38=38.4k, 57=57.6k, 76=76.8k, 115=115.2k */
#define NV_EEPROM_BAUD_K 1
#define NV_EEPROM_MAX_MASTER 2
/* device instance is only 22 bits - easier if we use 32 bits */
#define NV_EEPROM_DEVICE_0 3
#define NV_EEPROM_DEVICE_1 4
#define NV_EEPROM_DEVICE_2 5
#define NV_EEPROM_DEVICE_3 6
/* EEPROM free space - 7..31 */
/* BACnet Names - 32 bytes of data each */
#define NV_EEPROM_NAME_LENGTH(n) ((n)+0)
#define NV_EEPROM_NAME_ENCODING(n) ((n)+1)
#define NV_EEPROM_NAME_STRING(n) ((n)+2)
#define NV_EEPROM_NAME_SIZE 30
#define NV_EEPROM_NAME_OFFSET (1+1+NV_EEPROM_NAME_SIZE)
/* Device Name - starting offset */
#define NV_EEPROM_DEVICE_NAME 32
/* Device Description - starting offset */
#define NV_EEPROM_DEVICE_DESCRIPTION \
(NV_EEPROM_DEVICE_NAME+NV_EEPROM_NAME_OFFSET)
/* Device Location - starting offset */
#define NV_EEPROM_DEVICE_LOCATION \
(NV_EEPROM_DEVICE_DESCRIPTION+NV_EEPROM_NAME_OFFSET)
/* EEPROM free space 128..1024 */
/*=============== SEEPROM ================*/
/* data version - use to check valid version */
#define SEEPROM_ID 0xBAC0
#define SEEPROM_VERSION 0x0001
#define SEEPROM_BYTES_MAX (2*1024)
/* list of SEEPROM addresses */
/* note to developers: define each byte,
even if they are not used explicitly */
#define NV_SEEPROM_TYPE_0 0
#define NV_SEEPROM_TYPE_1 1
#define NV_SEEPROM_VERSION_0 2
#define NV_SEEPROM_VERSION_1 3
/* SEEPROM free space - 4..31 */
#define NV_SEEPROM_BINARY_OUTPUT_0 32
/* BO properties */
#define NV_SEEPROM_BO_POLARITY 0
#define NV_SEEPROM_BO_OUT_OF_SERVICE 1
#define NV_SEEPROM_BO_PRIORITY_ARRAY_1 2
#define NV_SEEPROM_BO_PRIORITY_ARRAY_2 3
#define NV_SEEPROM_BO_PRIORITY_ARRAY_3 4
#define NV_SEEPROM_BO_PRIORITY_ARRAY_4 5
#define NV_SEEPROM_BO_PRIORITY_ARRAY_5 6
#define NV_SEEPROM_BO_PRIORITY_ARRAY_6 7
#define NV_SEEPROM_BO_PRIORITY_ARRAY_7 8
#define NV_SEEPROM_BO_PRIORITY_ARRAY_8 9
#define NV_SEEPROM_BO_PRIORITY_ARRAY_9 10
#define NV_SEEPROM_BO_PRIORITY_ARRAY_10 11
#define NV_SEEPROM_BO_PRIORITY_ARRAY_11 12
#define NV_SEEPROM_BO_PRIORITY_ARRAY_12 13
#define NV_SEEPROM_BO_PRIORITY_ARRAY_13 14
#define NV_SEEPROM_BO_PRIORITY_ARRAY_14 15
#define NV_SEEPROM_BO_PRIORITY_ARRAY_15 16
#define NV_SEEPROM_BO_PRIORITY_ARRAY_16 17
/* formula for paramters */
#define NV_SEEPROM_BINARY_OUTPUT_SIZE 18
#define NV_SEEPROM_BINARY_OUTPUT(n,p) \
(NV_SEEPROM_BINARY_OUTPUT_0 + \
(NV_SEEPROM_BINARY_OUTPUT_SIZE * (n)) + (p))
/* SEEPROM free space - depends on number of BO */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+372
View File
@@ -0,0 +1,372 @@
/**************************************************************************
*
* Copyright (C) 2009 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 <stdlib.h>
#include "hardware.h"
#include "fifo.h"
#include "timer.h"
#include "led.h"
#include "nvdata.h"
/* me */
#include "rs485.h"
/* baud rate */
static uint32_t Baud_Rate = 9600;
/* The minimum time after the end of the stop bit of the final octet of a */
/* received frame before a node may enable its EIA-485 driver: 40 bit times. */
/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */
/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */
/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */
/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */
/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */
/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */
/* 40 bits is 4 octets including a start and stop bit with each octet */
#define Tturnaround (40UL)
/* turnaround_time_milliseconds = (Tturnaround*1000UL)/Baud_Rate; */
/* buffer for storing received bytes - size must be power of two */
static uint8_t Receive_Buffer_Data[128];
static FIFO_BUFFER Receive_Buffer;
static struct etimer Silence_Timer;
/****************************************************************************
* DESCRIPTION: Determines the amount of silence time elapsed
* RETURN: true if the amount of silence time has elapsed
* NOTES: none
*****************************************************************************/
bool rs485_silence_time_elapsed(
uint16_t milliseconds)
{
return timer_elapsed_milliseconds_short(&Silence_Timer, milliseconds);
}
/****************************************************************************
* DESCRIPTION: Resets the silence timer
* RETURN: nothing
* NOTES: none
*****************************************************************************/
void rs485_silence_time_reset(
void)
{
timer_elapsed_start(&Silence_Timer);
}
/****************************************************************************
* DESCRIPTION: Configures the RTS output
* RETURN: nothing
* NOTES: none
*****************************************************************************/
static void rs485_rts_init(
void)
{
/* configure the port pin as an output */
BIT_SET(DDRD, DDD4);
}
/****************************************************************************
* DESCRIPTION: enable the transmit-enable line on the RS-485 transceiver
* RETURN: nothing
* NOTES: none
*****************************************************************************/
void rs485_rts_enable(
bool enable)
{
if (enable) {
BIT_SET(PORTD, PD4);
} else {
BIT_CLEAR(PORTD, PD4);
}
}
/****************************************************************************
* DESCRIPTION: enable the UART receiver and interrupt
* RETURN: nothing
* NOTES: none
*****************************************************************************/
static void rs485_receiver_enable(
void)
{
UCSR0B = _BV(TXEN0) | _BV(RXEN0) | _BV(RXCIE0);
}
/****************************************************************************
* DESCRIPTION: delay for 40 bit times
* RETURN: nothing
* NOTES: none
*****************************************************************************/
void rs485_turnaround_delay(
void)
{
uint8_t nbytes = 4;
/* delay after reception before trasmitting - per MS/TP spec */
/* Transmit 4 dummy bytes with RS485 driver off.
This equals the 40 bit times (1 start, 8 data, 1 stop). */
rs485_rts_enable(false);
while (nbytes) {
/* Send the data byte */
UDR0 = 0xff;
while (!BIT_CHECK(UCSR0A, UDRE0)) {
/* do nothing - wait until Tx buffer is empty */
}
nbytes--;
}
while (!BIT_CHECK(UCSR0A, TXC0)) {
/* do nothing - wait until the entire frame in the
Transmit Shift Register has been shifted out */
}
/* Clear the Transmit Complete flag by writing a one to it. */
BIT_SET(UCSR0A, TXC0);
}
/****************************************************************************
* DESCRIPTION: Interrupt service routine for UART Receiver
* RETURN: nothing
* NOTES: none
*****************************************************************************/
ISR(USART0_RX_vect)
{
uint8_t data_byte;
if (BIT_CHECK(UCSR0A, RXC0)) {
/* data is available */
data_byte = UDR0;
#ifdef MSTP_MONITOR
UDR1 = data_byte;
#endif
(void) FIFO_Put(&Receive_Buffer, data_byte);
}
}
/****************************************************************************
* DESCRIPTION: Checks for data on the receive UART, and handles errors
* RETURN: none
* NOTES: none
*****************************************************************************/
bool rs485_byte_available(
uint8_t * data_register)
{
bool data_available = false; /* return value */
if (!FIFO_Empty(&Receive_Buffer)) {
led_on_interval(LED_4, 1);
if (data_register) {
*data_register = FIFO_Get(&Receive_Buffer);
}
data_available = true;
}
return data_available;
}
/****************************************************************************
* DESCRIPTION: returns an error indication if errors are enabled
* RETURN: nothing
* NOTES: none
*****************************************************************************/
bool rs485_receive_error(
void)
{
return false;
}
/****************************************************************************
* DESCRIPTION: Transmits a frame using the UART
* RETURN: none
* NOTES: none
*****************************************************************************/
void rs485_bytes_send(
uint8_t * buffer, /* data to send */
uint16_t nbytes)
{ /* number of bytes of data */
led_on(LED_5);
while (!BIT_CHECK(UCSR0A, UDRE0)) {
/* do nothing - wait until Tx buffer is empty */
}
while (nbytes) {
/* Send the data byte */
UDR0 = *buffer;
#ifdef MSTP_MONITOR
UDR1 = *buffer;
#endif
while (!BIT_CHECK(UCSR0A, UDRE0)) {
/* do nothing - wait until Tx buffer is empty */
}
buffer++;
nbytes--;
}
/* was the frame sent? */
while (!BIT_CHECK(UCSR0A, TXC0)) {
/* do nothing - wait until the entire frame in the
Transmit Shift Register has been shifted out */
}
/* Clear the Transmit Complete flag by writing a one to it. */
BIT_SET(UCSR0A, TXC0);
timer_elapsed_start(&Silence_Timer);
led_off_delay(LED_5, 1);
return;
}
/****************************************************************************
* DESCRIPTION: Returns the baud rate that we are currently running at
* RETURN: baud rate in bps
* NOTES: none
*****************************************************************************/
uint32_t rs485_baud_rate(
void)
{
return Baud_Rate;
}
/****************************************************************************
* DESCRIPTION: configure the UART baud rate
* RETURN: nothing
* NOTES: none
*****************************************************************************/
static void rs485_baud_rate_configure(
void)
{
/* 2x speed mode */
BIT_SET(UCSR0A, U2X0);
/* configure baud rate */
UBRR0 = (F_CPU / (8UL * Baud_Rate)) - 1;
}
/****************************************************************************
* DESCRIPTION: set the UART baud rate to a standard value
* RETURN: true if the baud rate is valid
* NOTES: none
*****************************************************************************/
bool rs485_baud_rate_set(
uint32_t baud)
{
bool valid = true;
uint8_t baud_k = 0;
switch (baud) {
case 9600:
case 19200:
case 38400:
case 57600:
case 76800:
case 115200:
Baud_Rate = baud;
rs485_baud_rate_configure();
/* store the baud rate */
baud_k = baud / 1000;
eeprom_bytes_write(NV_EEPROM_BAUD_K, &baud_k, 1);
break;
default:
valid = false;
break;
}
return valid;
}
/****************************************************************************
* DESCRIPTION: initialize the hardware UART
* RETURN: nothing
* NOTES: none
*****************************************************************************/
static void rs485_usart_init(
void)
{
/* enable the internal pullup on RXD0 */
BIT_CLEAR(DDRD, DDD0);
BIT_SET(PORTD, PD0);
/* enable Transmit and Receive */
UCSR0B = _BV(TXEN0) | _BV(RXEN0);
/* Set USART Control and Status Register n C */
/* Asynchronous USART 8-bit data, No parity, 1 stop */
/* Set USART Mode Select: UMSELn1 UMSELn0 = 00 for Asynchronous USART */
/* Set Parity Mode: UPMn1 UPMn0 = 00 for Parity Disabled */
/* Set Stop Bit Select: USBSn = 0 for 1 stop bit */
/* Set Character Size: UCSZn2 UCSZn1 UCSZn0 = 011 for 8-bit */
/* Clock Polarity: UCPOLn = 0 when asynchronous mode is used. */
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
power_usart0_enable();
}
/****************************************************************************
* DESCRIPTION: read any non-volatile data
* RETURN: nothing
* NOTES: none
*****************************************************************************/
static void rs485_init_nvdata(
void)
{
uint8_t baud_k = 9; /* from EEPROM value */
eeprom_bytes_read(NV_EEPROM_BAUD_K, &baud_k, 1);
switch (baud_k) {
case 9:
Baud_Rate = 9600;
break;
case 19:
Baud_Rate = 19200;
break;
case 38:
Baud_Rate = 38400;
break;
case 57:
Baud_Rate = 57600;
break;
case 76:
Baud_Rate = 76800;
break;
case 115:
Baud_Rate = 115200;
break;
default:
/* not configured yet */
Baud_Rate = 38400;
baud_k = 38400 / 1000;
eeprom_bytes_write(NV_EEPROM_BAUD_K, &baud_k, 1);
break;
}
rs485_baud_rate_configure();
}
/****************************************************************************
* DESCRIPTION: initialize the module
* RETURN: nothing
* NOTES: none
*****************************************************************************/
void rs485_init(
void)
{
FIFO_Init(&Receive_Buffer, &Receive_Buffer_Data[0],
(unsigned) sizeof(Receive_Buffer_Data));
timer_elapsed_start(&Silence_Timer);
rs485_rts_init();
rs485_usart_init();
rs485_init_nvdata();
rs485_receiver_enable();
rs485_rts_enable(false);
}
+59
View File
@@ -0,0 +1,59 @@
/**************************************************************************
*
* Copyright (C) 2009 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 RS485_H
#define RS485_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void rs485_init(
void);
void rs485_rts_enable(
bool enable);
bool rs485_byte_available(
uint8_t * data_register);
bool rs485_receive_error(
void);
void rs485_bytes_send(
uint8_t * buffer, /* data to send */
uint16_t nbytes); /* number of bytes of data */
uint32_t rs485_baud_rate(
void);
bool rs485_baud_rate_set(
uint32_t baud);
void rs485_turnaround_delay(
void);
void rs485_silence_time_reset(
void);
bool rs485_silence_time_elapsed(
uint16_t milliseconds);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+516
View File
@@ -0,0 +1,516 @@
/**************************************************************************
*
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
* Used algorithm and code from Joerg Wunsch and Ruwan Jayanetti.
* http://www.nongnu.org/avr-libc/user-manual/group__twi__demo.html
*
* 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 <stdlib.h>
#include "hardware.h"
/* me */
#include "seeprom.h"
/* the SEEPROM chip select bits A2, A1, and A0 are grounded */
/* control byte is 0xAx */
#ifndef SEEPROM_I2C_ADDRESS
#define SEEPROM_I2C_ADDRESS 0xA0
#endif
/* SEEPROM Clock Frequency */
#ifndef SEEPROM_I2C_CLOCK
#define SEEPROM_I2C_CLOCK 400000UL
#endif
/* max number of bytes that can be written in a single write */
#ifndef SEEPROM_PAGE_SIZE
#define SEEPROM_PAGE_SIZE 128
#endif
/* word addressing - is it 8-bit or 16-bit */
#ifndef SEEPROM_WORD_ADDRESS_16BIT
#define SEEPROM_WORD_ADDRESS_16BIT 1
#endif
/* maximum write cycle time in milliseconds - see datasheet */
#ifndef EEPROM_WRITE_CYCLE
#define EEPROM_WRITE_CYCLE 5
#endif
/* The lower 3 bits of TWSR are reserved on the ATmega163 */
#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3))
/* start condition transmitted */
#define TW_START 0x08
/* repeated start condition transmitted */
#define TW_REP_START 0x10
/* ***Master Transmitter*** */
/* SLA+W transmitted, ACK received */
#define TW_MT_SLA_ACK 0x18
/* SLA+W transmitted, NACK received */
#define TW_MT_SLA_NACK 0x20
/* data transmitted, ACK received */
#define TW_MT_DATA_ACK 0x28
/* data transmitted, NACK received */
#define TW_MT_DATA_NACK 0x30
/* arbitration lost in SLA+W or data */
#define TW_MT_ARB_LOST 0x38
/* ***Master Receiver*** */
/* arbitration lost in SLA+R or NACK */
#define TW_MR_ARB_LOST 0x38
/* SLA+R transmitted, ACK received */
#define TW_MR_SLA_ACK 0x40
/* SLA+R transmitted, NACK received */
#define TW_MR_SLA_NACK 0x48
/* data received, ACK returned */
#define TW_MR_DATA_ACK 0x50
/* data received, NACK returned */
#define TW_MR_DATA_NACK 0x58
/* SLA+R address */
#define TW_READ 1
/* SLA+W address */
#define TW_WRITE 0
/* Number of iterations is the max amount to wait for write cycle
to complete a full page write */
/* .005s/.000025=200 */
#define MAX_ITER (((SEEPROM_I2C_CLOCK/1000)/10)*SEEPROM_WRITE_CYCLE)
/*************************************************************************
* DESCRIPTION: Return bytes from SEEPROM memory at address
* RETURN: number of bytes read, or -1 on error
* NOTES: none
**************************************************************************/
int seeprom_bytes_read(
uint16_t eeaddr, /* SEEPROM starting memory address */
uint8_t * buf, /* data to store */
int len)
{ /* number of bytes of data to read */
uint8_t sla, twcr, n = 0;
int rv = 0;
uint8_t twst; /* status - only valid while TWINT is set. */
uint16_t timeout = 0xFFFF;
#if SEEPROM_WORD_ADDRESS_16BIT
/* 16bit address devices need only TWI Device Address */
sla = SEEPROM_I2C_ADDRESS;
#else
/* patch high bits of EEPROM address into SLA */
sla = SEEPROM_I2C_ADDRESS | (((eeaddr >> 8) & 0x07) << 1);
#endif
/* First cycle: master transmitter mode */
restart:
if (n++ >= MAX_ITER) {
return -1;
}
begin:
/* send start condition */
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0) {
timeout--;
if (timeout == 0) {
return -1;
}
}
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_REP_START:
/* OK, but should not happen */
case TW_START:
break;
case TW_MT_ARB_LOST:
/* Since the TWI bus is multi-master capable,
there is potential for a bus contention when
one master starts to access the bus. */
goto begin;
default:
/* error: not in start condition */
/* NB: do /not/ send stop condition */
return -1;
}
/* Next, the device slave is going to be reselected using a repeated
start condition which is meant to guarantee that the bus arbitration
will remain at the current master. This uses the same slave address
(SLA), but this time with read intent (R/~W bit set to 1) in order
to request the device slave to start transfering data from the slave
to the master in the next packet. */
/* send SLA+W */
TWDR = sla | TW_WRITE;
/* clear interrupt to start transmission */
TWCR = _BV(TWINT) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MT_SLA_ACK:
break;
case TW_MT_SLA_NACK:
/* nack during select: device busy writing */
/* If the EEPROM device is still busy writing one or more cells
after a previous write request, it will simply leave its bus
interface drivers at high impedance, and does not respond to
a selection in any way at all. */
goto restart;
case TW_MT_ARB_LOST:
/* re-arbitrate */
goto begin;
default:
/* must send stop condition */
goto error;
}
#if SEEPROM_WORD_ADDRESS_16BIT
/* 16 bit word address device, send high 8 bits of addr */
TWDR = (eeaddr >> 8);
/* clear interrupt to start transmission */
TWCR = _BV(TWINT) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MT_DATA_ACK:
break;
case TW_MT_DATA_NACK:
goto quit;
case TW_MT_ARB_LOST:
goto begin;
default:
/* must send stop condition */
goto error;
}
#endif
/* low 8 bits of addr */
TWDR = eeaddr;
/* clear interrupt to start transmission */
TWCR = _BV(TWINT) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MT_DATA_ACK:
break;
case TW_MT_DATA_NACK:
goto quit;
case TW_MT_ARB_LOST:
goto begin;
default:
/* must send stop condition */
goto error;
}
/* This is called master receiver mode: the bus master still supplies
the SCL clock, but the device slave drives the SDA line with the
appropriate data. After 8 data bits, the master responds with an ACK
bit (SDA driven low) in order to request another data transfer from
the slave, or it can leave the SDA line high (NACK), indicating to
the slave that it is going to stop the transfer now.
Assertion of ACK is handled by setting the TWEA bit in TWCR when
starting the current transfer. */
/* Next cycle(s): master receiver mode */
/* send repeated start condition */
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_START:
/* OK, but should not happen */
case TW_REP_START:
break;
case TW_MT_ARB_LOST:
goto begin;
default:
goto error;
}
/* send SLA+R */
TWDR = sla | TW_READ;
/* clear interrupt to start transmission */
TWCR = _BV(TWINT) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MR_SLA_ACK:
break;
case TW_MR_SLA_NACK:
goto quit;
case TW_MR_ARB_LOST:
goto begin;
default:
goto error;
}
/* The control word sent out in order to initiate the transfer of the
next data packet is initially set up to assert the TWEA bit.
During the last loop iteration, TWEA is de-asserted so the client
will get informed that no further transfer is desired. */
twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
for (; len > 0; len--) {
if (len == 1) {
/* send NAK this time */
twcr = _BV(TWINT) | _BV(TWEN);
}
/* clear int to start transmission */
TWCR = twcr;
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MR_DATA_NACK:
/* force end of loop */
len = 0;
/* FALLTHROUGH */
case TW_MR_DATA_ACK:
*buf = TWDR;
buf++;
rv++;
break;
default:
goto error;
}
}
quit:
/* Except in the case of lost arbitration, all bus transactions
must properly be terminated by the master initiating a
stop condition. */
/* send stop condition */
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
return rv;
error:
rv = -1;
goto quit;
}
/*************************************************************************
* DESCRIPTION: Write some data and wait until it is sent
* RETURN: number of bytes written, or -1 on error
* NOTES: only writes from offset to end of page.
**************************************************************************/
static int seeprom_bytes_write_page(
uint16_t eeaddr, /* SEEPROM starting memory address */
uint8_t * buf, /* data to send */
int len)
{ /* number of bytes of data */
uint8_t sla, n = 0;
int rv = 0;
uint16_t endaddr;
uint8_t twst; /* status - only valid while TWINT is set. */
uint16_t page_end_addr;
uint16_t timeout = 0xFFFF;
/* limit the length to end of the EEPROM page */
page_end_addr = eeaddr | (SEEPROM_PAGE_SIZE - 1);
if ((eeaddr + len) > page_end_addr) {
endaddr = page_end_addr + 1;
len = endaddr - eeaddr;
}
#if SEEPROM_WORD_ADDRESS_16BIT
/* 16bit address devices need only TWI Device Address */
sla = SEEPROM_I2C_ADDRESS;
#else
/* patch high bits of EEPROM address into SLA */
sla = SEEPROM_I2C_ADDRESS | (((eeaddr >> 8) & 0x07) << 1);
#endif
restart:
if (n++ >= MAX_ITER) {
return -1;
}
begin:
/* Writing to the EEPROM device is simpler than reading,
since only a master transmitter mode transfer is needed.
Note that the first packet after the SLA+W selection is
always considered to be the EEPROM address for the next operation.
This packet is exactly the same as the one above sent before
starting to read the device.
In case a master transmitter mode transfer is going to send
more than one data packet, all following packets will be considered
data bytes to write at the indicated address.
The internal address pointer will be incremented after each
write operation. */
/* send start condition */
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0) {
timeout--;
if (timeout == 0) {
return -1;
}
}
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_REP_START:
/* OK, but should not happen */
case TW_START:
break;
case TW_MT_ARB_LOST:
goto begin;
default:
/* error: not in start condition */
/* NB: do /not/ send stop condition */
return -1;
}
/* send SLA+W */
TWDR = sla | TW_WRITE;
/* clear interrupt to start transmission */
TWCR = _BV(TWINT) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MT_SLA_ACK:
break;
case TW_MT_SLA_NACK:
/* nack during select: device busy writing */
goto restart;
case TW_MT_ARB_LOST:
/* re-arbitrate */
goto begin;
default:
/* must send stop condition */
goto error;
}
#if SEEPROM_WORD_ADDRESS_16BIT
/* 16 bit word address device, send high 8 bits of addr */
TWDR = (eeaddr >> 8);
/* clear interrupt to start transmission */
TWCR = _BV(TWINT) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MT_DATA_ACK:
break;
case TW_MT_DATA_NACK:
goto quit;
case TW_MT_ARB_LOST:
goto begin;
default:
/* must send stop condition */
goto error;
}
#endif
/* low 8 bits of addr */
TWDR = eeaddr;
/* clear interrupt to start transmission */
TWCR = _BV(TWINT) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0) {
};
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MT_DATA_ACK:
break;
case TW_MT_DATA_NACK:
goto quit;
case TW_MT_ARB_LOST:
goto begin;
default:
/* must send stop condition */
goto error;
}
for (; len > 0; len--) {
TWDR = *buf;
/* start transmission */
TWCR = _BV(TWINT) | _BV(TWEN);
/* wait for transmission */
while ((TWCR & _BV(TWINT)) == 0);
twst = TWSR & TW_STATUS_MASK;
switch (twst) {
case TW_MT_DATA_NACK:
/* device write protected -- Note [16] */
goto error;
case TW_MT_DATA_ACK:
buf++;
rv++;
break;
default:
goto error;
}
}
quit:
/* send stop condition */
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
return rv;
error:
rv = -1;
goto quit;
}
/*************************************************************************
* DESCRIPTION: Write some data and wait until it is sent
* RETURN: number of bytes written, or -1 on error
* NOTES:
* When the word address, internally generated,
* reaches the page boundary, the following
* byte is placed at the beginning of the same
* page. If more than 64 data words are
* transmitted to the EEPROM, the data word
* address will "roll over" and previous data will be
* overwritten. The address "roll over" during write
* is from the last byte of the current page to the
* first byte of the same page.
**************************************************************************/
int seeprom_bytes_write(
uint16_t off, /* SEEPROM starting memory address */
uint8_t * buf, /* data to send */
int len)
{ /* number of bytes of data */
int status = 0;
int rv = 0;
while (len) {
status = seeprom_bytes_write_page(off, buf, len);
if (status <= 0) {
if (rv == 0) {
rv = status;
}
break;
}
buf += status;
off += status;
len -= status;
rv += status;
}
return rv;
}
/*************************************************************************
* Description: Initialize the SEEPROM TWI connection
* Returns: none
* Notes: none
**************************************************************************/
void seeprom_init(
void)
{
/* bit rate prescaler */
TWSR = 0;
TWCR = _BV(TWEN) | _BV(TWEA);
/* bit rate */
/* SCL freq = F_CPU/(16+2*TWBR*4^TWPS) */
/* since TWPS in TWSR is set to zero, 4^TWPS resolves to 1 */
TWBR = (F_CPU / SEEPROM_I2C_CLOCK - 16) / 2;
/* my address */
TWAR = 0;
}
+48
View File
@@ -0,0 +1,48 @@
/**************************************************************************
*
* Copyright (C) 2009 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 SEEPROM_H
#define SEEPROM_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int seeprom_bytes_read(
uint16_t ee_address, /* SEEPROM starting memory address */
uint8_t * buffer, /* data to store */
int nbytes); /* number of bytes of data to read */
int seeprom_bytes_write(
uint16_t ee_address, /* SEEPROM starting memory address */
uint8_t * buffer, /* data to send */
int nbytes); /* number of bytes of data */
void seeprom_init(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+192
View File
@@ -0,0 +1,192 @@
/**************************************************************************
*
* Copyright (C) 2009 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 <stdlib.h>
#include "hardware.h"
#include "fifo.h"
#include "serial.h"
/* baud rate */
static uint32_t Baud_Rate = 9600;
/* buffer for storing received bytes - size must be power of two */
static uint8_t Receive_Buffer_Data[128];
static FIFO_BUFFER Receive_Buffer;
static void serial_receiver_enable(
void)
{
UCSR1B = _BV(TXEN1) | _BV(RXEN1) | _BV(RXCIE1);
}
ISR(USART1_RX_vect)
{
uint8_t data_byte;
if (BIT_CHECK(UCSR1A, RXC1)) {
/* data is available */
data_byte = UDR1;
(void) FIFO_Put(&Receive_Buffer, data_byte);
}
}
bool serial_byte_get(
uint8_t * data_register)
{
bool data_available = false; /* return value */
if (!FIFO_Empty(&Receive_Buffer)) {
*data_register = FIFO_Get(&Receive_Buffer);
data_available = true;
}
return data_available;
}
bool serial_byte_peek(
uint8_t * data_register)
{
bool data_available = false; /* return value */
if (!FIFO_Empty(&Receive_Buffer)) {
*data_register = FIFO_Peek(&Receive_Buffer);
data_available = true;
}
return data_available;
}
void serial_bytes_send(
uint8_t * buffer, /* data to send */
uint16_t nbytes)
{ /* number of bytes of data */
while (!BIT_CHECK(UCSR1A, UDRE1)) {
/* do nothing - wait until Tx buffer is empty */
}
while (nbytes) {
/* Send the data byte */
UDR1 = *buffer;
while (!BIT_CHECK(UCSR1A, UDRE1)) {
/* do nothing - wait until Tx buffer is empty */
}
buffer++;
nbytes--;
}
/* was the frame sent? */
while (!BIT_CHECK(UCSR1A, TXC1)) {
/* do nothing - wait until the entire frame in the
Transmit Shift Register has been shifted out */
}
/* Clear the Transmit Complete flag by writing a one to it. */
BIT_SET(UCSR1A, TXC1);
return;
}
void serial_byte_send(
uint8_t ch)
{
while (!BIT_CHECK(UCSR1A, UDRE1)) {
/* do nothing - wait until Tx buffer is empty */
}
/* Send the data byte */
UDR1 = ch;
return;
}
void serial_byte_transmit_complete(
void)
{
/* was the frame sent? */
while (!BIT_CHECK(UCSR1A, TXC1)) {
/* do nothing - wait until the entire frame in the
Transmit Shift Register has been shifted out */
}
/* Clear the Transmit Complete flag by writing a one to it. */
BIT_SET(UCSR1A, TXC1);
}
uint32_t serial_baud_rate(
void)
{
return Baud_Rate;
}
bool serial_baud_rate_set(
uint32_t baud)
{
bool valid = true;
switch (baud) {
case 9600:
case 19200:
case 38400:
case 57600:
case 76800:
case 115200:
Baud_Rate = baud;
/* 2x speed mode */
BIT_SET(UCSR1A, U2X1);
/* configure baud rate */
UBRR1 = (F_CPU / (8UL * Baud_Rate)) - 1;
/* FIXME: store the baud rate */
break;
default:
valid = false;
break;
}
return valid;
}
static void serial_usart_init(
void)
{
/* enable the internal pullup on RXD1 */
BIT_CLEAR(DDRD, DDD2);
BIT_SET(PORTD, PD2);
/* enable Transmit and Receive */
UCSR1B = _BV(TXEN1) | _BV(RXEN1);
/* Set USART Control and Status Register n C */
/* Asynchronous USART 8-bit data, No parity, 1 stop */
/* Set USART Mode Select: UMSELn1 UMSELn0 = 00 for Asynchronous USART */
/* Set Parity Mode: UPMn1 UPMn0 = 00 for Parity Disabled */
/* Set Stop Bit Select: USBSn = 0 for 1 stop bit */
/* Set Character Size: UCSZn2 UCSZn1 UCSZn0 = 011 for 8-bit */
/* Clock Polarity: UCPOLn = 0 when asynchronous mode is used. */
UCSR1C = _BV(UCSZ11) | _BV(UCSZ10);
power_usart1_enable();
}
void serial_init(
void)
{
FIFO_Init(&Receive_Buffer, &Receive_Buffer_Data[0],
(unsigned) sizeof(Receive_Buffer_Data));
serial_usart_init();
serial_baud_rate_set(Baud_Rate);
serial_receiver_enable();
}
+59
View File
@@ -0,0 +1,59 @@
/**************************************************************************
*
* Copyright (C) 2009 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 SERIAL_H
#define SERIAL_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
bool serial_byte_get(
uint8_t * data_register);
bool serial_byte_peek(
uint8_t * data_register);
void serial_bytes_send(
uint8_t * buffer, /* data to send */
uint16_t nbytes); /* number of bytes of data */
/* byte transmit */
void serial_byte_send(
uint8_t ch);
void serial_byte_transmit_complete(
void);
uint32_t serial_baud_rate(
void);
bool serial_baud_rate_set(
uint32_t baud);
void serial_init(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+108
View File
@@ -0,0 +1,108 @@
/**************************************************************************
*
* Copyright (C) 2009 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 "hardware.h"
/* me */
#include "stack.h"
#if defined(__GNUC__)
/* stack checking */
extern uint8_t _end;
extern uint8_t __stack;
#define STACK_CANARY (0xC5)
void stack_init(
void) __attribute__ ((naked)) __attribute__ ((section(".init1")));
void stack_init(
void)
{
#if 0
uint8_t *p = &_end;
while (p <= &__stack) {
*p = STACK_CANARY;
p++;
}
#else
__asm volatile (
" ldi r30,lo8(_end)\n" " ldi r31,hi8(_end)\n" " ldi r24,lo8(0xc5)\n" /* STACK_CANARY = 0xc5 */
" ldi r25,hi8(__stack)\n" " rjmp .cmp\n" ".loop:\n"
" st Z+,r24\n" ".cmp:\n" " cpi r30,lo8(__stack)\n"
" cpc r31,r25\n" " brlo .loop\n" " breq .loop"::);
#endif
}
unsigned stack_size(
void)
{
return (&__stack) - (&_end);
}
uint8_t stack_byte(
unsigned offset)
{
return *(&_end + offset);
}
unsigned stack_unused(
void)
{
uint8_t *p = &_end;
unsigned count = 0;
while (p <= &__stack) {
if ((*p) != STACK_CANARY) {
count = p - (&_end);
break;
}
p++;
}
return count;
}
#else
void stack_init(
void)
{
}
unsigned stack_size(
void)
{
return 0;
}
uint8_t stack_byte(
unsigned offset)
{
return 0;
}
unsigned stack_unused(
void)
{
return 0;
}
#endif
+51
View File
@@ -0,0 +1,51 @@
/**************************************************************************
*
* Copyright (C) 2009 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 STACK_H
#define STACK_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* C stack checking */
void stack_init(
void);
unsigned stack_size(
void);
uint8_t stack_byte(
unsigned offset);
unsigned stack_unused(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+235
View File
@@ -0,0 +1,235 @@
/**************************************************************************
*
* Copyright (C) 2010 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 <stdbool.h>
#include <string.h>
#include "hardware.h"
#include "timer.h"
#include "serial.h"
#include "input.h"
#include "bo.h"
#include "rs485.h"
#include "dlmstp.h"
#include "seeprom.h"
#include "nvdata.h"
/* me */
#include "test.h"
#ifndef BDK_VERSION
#define BDK_VERSION 4
#endif
#define BINARY_STRING_MAX 3
const char * const binary_string[BINARY_STRING_MAX] = {
"INACTIVE", "ACTIVE", "RELINQUISH"
};
/* timer for test task */
static struct itimer Test_Timer;
/* MAC Address of MS/TP */
static uint8_t MSTP_MAC_Address;
void test_init(
void)
{
#ifdef MSTP_MONITOR
serial_baud_rate_set(115200);
#else
serial_baud_rate_set(9600);
#endif
timer_interval_start_seconds(&Test_Timer, 1);
/* configure a port pin as output */
#if (BDK_VERSION==4)
BIT_SET(DDRD, DDB5);
#else
BIT_SET(DDRB, DDB0);
#endif
}
/**
* @brief send a string of text to the RS-232 port
* @param text - C string of text (null terminated)
*/
static void test_write_string(const char * text)
{
size_t len = 0;
if (text) {
len = strlen(text);
serial_bytes_send((uint8_t *)text, len);
}
}
/*************************************************************************
* Description: Turn on a pin
* Returns: none
* Notes: none
*************************************************************************/
static inline void test_pin_on(
void)
{
#if (BDK_VERSION==4)
BIT_SET(PORTD, PD5);
#else
BIT_SET(PORTB, PB0);
#endif
}
/*************************************************************************
* Description: Turn off a pin
* Returns: none
* Notes: none
*************************************************************************/
static inline void test_pin_off(
void)
{
#if (BDK_VERSION==4)
BIT_CLEAR(PORTD, PD5);
#else
BIT_CLEAR(PORTB, PB0);
#endif
}
/*************************************************************************
* Description: Get the state of the test pin
* Returns: true if on, false if off.
* Notes: none
*************************************************************************/
static inline bool test_pin_state(
void)
{
#if (BDK_VERSION==4)
return (BIT_CHECK(PIND, PD5));
#else
return (BIT_CHECK(PINB, PB0));
#endif
}
/*************************************************************************
* Description: Toggle the test pin
* Returns: none
* Notes: none
*************************************************************************/
static inline void test_pin_toggle(
void)
{
if (test_pin_state()) {
test_pin_off();
} else {
test_pin_on();
}
}
#ifdef MSTP_MONITOR
void test_task(
void)
{
if (timer_interval_expired(&Test_Timer)) {
timer_interval_reset(&Test_Timer);
MSTP_MAC_Address = MSTP_MAC_Address;
}
}
#else
char Send_Buffer[32];
void test_task(
void)
{
uint8_t data_register = 0;
uint16_t id = 0;
if (timer_interval_expired(&Test_Timer)) {
timer_interval_reset(&Test_Timer);
sprintf(Send_Buffer, "BACnet: 0000000\r\n");
MSTP_MAC_Address = input_address();
Send_Buffer[8] = (MSTP_MAC_Address & BIT0) ? '1' : '0';
Send_Buffer[9] = (MSTP_MAC_Address & BIT1) ? '1' : '0';
Send_Buffer[10] = (MSTP_MAC_Address & BIT2) ? '1' : '0';
Send_Buffer[11] = (MSTP_MAC_Address & BIT3) ? '1' : '0';
Send_Buffer[12] = (MSTP_MAC_Address & BIT4) ? '1' : '0';
Send_Buffer[13] = (MSTP_MAC_Address & BIT5) ? '1' : '0';
Send_Buffer[14] = (MSTP_MAC_Address & BIT6) ? '1' : '0';
serial_bytes_send((uint8_t *) Send_Buffer, 17);
}
if (serial_byte_get(&data_register)) {
/* echo the character */
serial_byte_send(data_register);
switch (data_register) {
case '0':
Binary_Output_Present_Value_Set(0, BINARY_INACTIVE, 0);
Binary_Output_Present_Value_Set(1, BINARY_INACTIVE, 0);
test_write_string(binary_string[0]);
break;
case '1':
Binary_Output_Present_Value_Set(0, BINARY_ACTIVE, 0);
Binary_Output_Present_Value_Set(1, BINARY_ACTIVE, 0);
test_write_string(binary_string[1]);
break;
case '2':
Binary_Output_Present_Value_Set(0, BINARY_NULL, 0);
Binary_Output_Present_Value_Set(1, BINARY_NULL, 0);
test_write_string(binary_string[2]);
break;
case '3':
rs485_baud_rate_set(38400);
break;
case '5':
rs485_baud_rate_set(57600);
break;
case '7':
rs485_baud_rate_set(76800);
break;
case '9':
rs485_baud_rate_set(9600);
break;
case 'e':
seeprom_bytes_read(NV_SEEPROM_TYPE_0, (uint8_t *) & id, 2);
sprintf(Send_Buffer, "\r\n%04X", id);
serial_bytes_send((uint8_t *) Send_Buffer,
strlen(Send_Buffer));
break;
case 'b':
sprintf(Send_Buffer, "\r\n%lubps",
(unsigned long) rs485_baud_rate());
serial_bytes_send((uint8_t *) Send_Buffer,
strlen(Send_Buffer));
break;
case 'm':
sprintf(Send_Buffer, "\r\nMax:%u",
(unsigned) dlmstp_max_master());
serial_bytes_send((uint8_t *) Send_Buffer,
strlen(Send_Buffer));
break;
default:
break;
}
serial_byte_send('\r');
serial_byte_send('\n');
serial_byte_transmit_complete();
}
test_pin_toggle();
}
#endif
+41
View File
@@ -0,0 +1,41 @@
/**************************************************************************
*
* Copyright (C) 2010 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 TEST_H
#define TEST_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void test_init(
void);
void test_task(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+431
View File
@@ -0,0 +1,431 @@
/**************************************************************************
*
* Copyright (C) 2009 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 "timer.h"
/* generic elapsed timer handling */
/* interval not to exceed 49.7 days */
/* interval of 1ms may be 0 to 1ms */
/*************************************************************************
* Description: Sets the start time for an elapsed timer
* Returns: the value of the start timer
* Notes: none
*************************************************************************/
void timer_elapsed_start(
struct etimer *t)
{
uint32_t now = timer_milliseconds();
if (t) {
t->start = now;
}
}
/*************************************************************************
* Description: Gets the amount of elapsed time in milliseconds
* Returns: elapsed time in milliseconds
* Notes: none
*************************************************************************/
uint32_t timer_elapsed_time(
struct etimer *t)
{
uint32_t now = timer_milliseconds();
uint32_t delta = 0;
if (t) {
delta = now - t->start;
}
return delta;
}
/*************************************************************************
* Description: Sets the start time with an offset
* Returns: elapsed time in milliseconds
* Notes: none
*************************************************************************/
void timer_elapsed_start_offset(
struct etimer *t,
uint32_t offset)
{
uint32_t now = timer_milliseconds();
if (t) {
t->start = now + offset;
}
}
/*************************************************************************
* Description: Tests to see if time has elapsed
* Returns: true if time has elapsed
* Notes: none
*************************************************************************/
bool timer_elapsed_milliseconds(
struct etimer *t,
uint32_t milliseconds)
{
return (timer_elapsed_time(t) >= milliseconds);
}
/*************************************************************************
* Description: Tests to see if time has elapsed
* Returns: true if time has elapsed
* Notes: none
*************************************************************************/
bool timer_elapsed_seconds(
struct etimer * t,
uint32_t seconds)
{
uint32_t milliseconds = seconds;
milliseconds *= 1000L;
return timer_elapsed_milliseconds(t, milliseconds);
}
/*************************************************************************
* Description: Tests to see if time has elapsed
* Returns: true if time has elapsed
* Notes: none
*************************************************************************/
bool timer_elapsed_minutes(
struct etimer * t,
uint32_t minutes)
{
uint32_t milliseconds = minutes;
milliseconds *= 1000L;
milliseconds *= 60L;
return timer_elapsed_milliseconds(t, milliseconds);
}
/*************************************************************************
* Description: Tests to see if time has elapsed
* Returns: true if time has elapsed
* Notes: none
*************************************************************************/
bool timer_elapsed_milliseconds_short(
struct etimer * t,
uint16_t value)
{
uint32_t milliseconds;
milliseconds = value;
return (timer_elapsed_time(t) >= milliseconds);
}
/*************************************************************************
* Description: Tests to see if time has elapsed
* Returns: true if time has elapsed
* Notes: none
*************************************************************************/
bool timer_elapsed_seconds_short(
struct etimer * t,
uint16_t value)
{
return timer_elapsed_seconds(t, value);
}
/*************************************************************************
* Description: Tests to see if time has elapsed
* Returns: true if time has elapsed
* Notes: none
*************************************************************************/
bool timer_elapsed_minutes_short(
struct etimer * t,
uint16_t value)
{
return timer_elapsed_minutes(t, value);
}
/*************************************************************************
* Description: Starts an interval timer
* Returns: nothing
* Notes: none
*************************************************************************/
void timer_interval_start(
struct itimer *t,
uint32_t interval)
{
if (t) {
t->start = timer_milliseconds();
t->interval = interval;
}
}
/*************************************************************************
* Description: Starts an interval timer
* Returns: nothing
* Notes: none
*************************************************************************/
void timer_interval_start_seconds(
struct itimer *t,
uint32_t seconds)
{
uint32_t interval = seconds;
interval *= 1000L;
timer_interval_start(t, interval);
}
/*************************************************************************
* Description: Starts an interval timer
* Returns: nothing
* Notes: none
*************************************************************************/
void timer_interval_start_minutes(
struct itimer *t,
uint32_t minutes)
{
uint32_t interval = minutes;
interval *= 1000L;
interval *= 60L;
timer_interval_start(t, interval);
}
/*************************************************************************
* Description: Determines the amount of time that has elapsed
* Returns: elapsed milliseconds
* Notes: none
*************************************************************************/
uint32_t timer_interval_elapsed(
struct itimer *t)
{
uint32_t now = timer_milliseconds();
uint32_t delta = 0;
if (t) {
delta = now - t->start;
}
return delta;
}
/*************************************************************************
* Description: Determines the amount of time that has elapsed
* Returns: elapsed milliseconds
* Notes: none
*************************************************************************/
uint32_t timer_interval(
struct itimer * t)
{
uint32_t interval = 0;
if (t) {
interval = t->interval;
}
return interval;
}
/*************************************************************************
* Description: Tests to see if time has elapsed
* Returns: true if time has elapsed
* Notes: none
*************************************************************************/
bool timer_interval_expired(
struct itimer * t)
{
bool expired = false;
if (t) {
if (t->interval) {
expired = timer_interval_elapsed(t) >= t->interval;
}
}
return expired;
}
/*************************************************************************
* Description: Sets the interval value to zero so it never expires
* Returns: nothing
* Notes: none
*************************************************************************/
void timer_interval_no_expire(
struct itimer *t)
{
if (t) {
t->interval = 0;
}
}
/*************************************************************************
* Description: Adds another interval to the start time. Used for cyclic
* timers that won't lose ticks.
* Returns: nothing
* Notes: none
*************************************************************************/
void timer_interval_reset(
struct itimer *t)
{
if (t) {
t->start += t->interval;
}
}
/*************************************************************************
* Description: Restarts the timer with the same interval
* Returns: nothing
* Notes: none
*************************************************************************/
void timer_interval_restart(
struct itimer *t)
{
if (t) {
t->start = timer_milliseconds();
}
}
/*************************************************************************
* Description: Return the elapsed time
* Returns: number of milliseconds elapsed
* Notes: only up to 255ms elapsed
**************************************************************************/
uint8_t timer_milliseconds_delta(
uint8_t start)
{
return (timer_milliseconds_byte() - start);
}
/*************************************************************************
* Description: Mark the start of a delta timer
* Returns: mark timer starting tick
* Notes: only up to 255ms elapsed
**************************************************************************/
uint8_t timer_milliseconds_mark(
void)
{
return timer_milliseconds_byte();
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
static uint32_t Milliseconds;
uint32_t timer_milliseconds(
void)
{
return Milliseconds;
}
uint32_t timer_milliseconds_set(
uint32_t value)
{
uint32_t old_value = Milliseconds;
Milliseconds = value;
return old_value;
}
void testElapsedTimer(
Test * pTest)
{
struct etimer t;
uint32_t test_time = 0;
timer_milliseconds_set(test_time);
timer_elapsed_start(&t);
ct_test(pTest, timer_elapsed_time(&t) == test_time);
test_time = 0xffff;
timer_milliseconds_set(test_time);
ct_test(pTest, timer_elapsed_time(&t) == test_time);
test_time = 0xffffffff;
timer_milliseconds_set(test_time);
ct_test(pTest, timer_elapsed_time(&t) == test_time);
}
void testIntervalTimer(
Test * pTest)
{
struct itimer t;
uint32_t interval = 0;
uint32_t test_time = 0;
timer_milliseconds_set(test_time);
timer_interval_start(&t, interval);
test_time = 0xffff;
timer_milliseconds_set(test_time);
ct_test(pTest, timer_interval(&t) == interval);
ct_test(pTest, timer_interval_elapsed(&t) == test_time);
test_time = 0xffffffff;
timer_milliseconds_set(test_time);
ct_test(pTest, timer_interval(&t) == interval);
ct_test(pTest, timer_interval_elapsed(&t) == test_time);
test_time = 0;
timer_milliseconds_set(test_time);
interval = 0xffff;
timer_interval_start(&t, interval);
ct_test(pTest, timer_interval(&t) == interval);
interval = 0xffffffff;
timer_interval_start(&t, interval);
ct_test(pTest, timer_interval(&t) == interval);
interval = 0;
timer_interval_start_seconds(&t, interval);
ct_test(pTest, timer_interval(&t) == interval);
interval = 60L;
timer_interval_start_seconds(&t, interval);
interval *= 1000L;
ct_test(pTest, timer_interval(&t) == interval);
}
#ifdef TEST_TIMER
int main(
void)
{
Test *pTest;
bool rc;
pTest = ct_create("Timer", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testElapsedTimer);
assert(rc);
rc = ct_addTestFunction(pTest, testIntervalTimer);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif
#endif
+115
View File
@@ -0,0 +1,115 @@
/**************************************************************************
*
* Copyright (C) 2009 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 TIMER_H
#define TIMER_H
#include <stdbool.h>
#include <stdint.h>
/* Timer Module */
/* elapsed timer structure */
struct etimer {
uint32_t start;
};
/* interval timer structure */
struct itimer {
uint32_t start;
uint32_t interval;
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* these 3 functions are created in the hardware specific module */
void timer_init(
void);
uint32_t timer_milliseconds(
void);
uint8_t timer_milliseconds_byte(
void);
/* these functions are in the generic timer.c module */
/* elapsed timer */
void timer_elapsed_start(
struct etimer *t);
void timer_elapsed_start_offset(
struct etimer *t,
uint32_t offset);
uint32_t timer_elapsed_time(
struct etimer *t);
bool timer_elapsed_milliseconds(
struct etimer *t,
uint32_t value);
bool timer_elapsed_seconds(
struct etimer *t,
uint32_t value);
bool timer_elapsed_minutes(
struct etimer *t,
uint32_t value);
bool timer_elapsed_milliseconds_short(
struct etimer *t,
uint16_t value);
bool timer_elapsed_seconds_short(
struct etimer *t,
uint16_t value);
bool timer_elapsed_minutes_short(
struct etimer *t,
uint16_t value);
/* interval timer */
void timer_interval_start(
struct itimer *t,
uint32_t interval);
void timer_interval_start_seconds(
struct itimer *t,
uint32_t interval);
void timer_interval_start_minutes(
struct itimer *t,
uint32_t interval);
bool timer_interval_expired(
struct itimer *t);
uint32_t timer_interval(
struct itimer *t);
uint32_t timer_interval_elapsed(
struct itimer *t);
void timer_interval_no_expire(
struct itimer *t);
void timer_interval_reset(
struct itimer *t);
void timer_interval_restart(
struct itimer *t);
/* special for 8-bit microcontrollers - limited to 255ms */
uint8_t timer_milliseconds_delta(
uint8_t start);
uint8_t timer_milliseconds_mark(
void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+165
View File
@@ -0,0 +1,165 @@
/**************************************************************************
*
* Copyright (C) 2009 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 "hardware.h"
#include "timer.h"
#ifndef F_CPU
#error "F_CPU must be defined for Timer configuration."
#endif
/* Timer2 Prescaling: 1, 8, 32, 64, 128, 256, or 1024 */
#define TIMER_MICROSECONDS 1000UL
#define TIMER_TICKS(p) \
(((((F_CPU)/(p))/1000UL) \
*(TIMER_MICROSECONDS))/1000UL)
#define TIMER_TICKS_MAX 255UL
/* adjust the prescaler for the processor clock */
#if (TIMER_TICKS(1) <= TIMER_TICKS_MAX)
#define TIMER2_PRESCALER 1
#elif (TIMER_TICKS(8) <= TIMER_TICKS_MAX)
#define TIMER2_PRESCALER 8
#elif (TIMER_TICKS(32) <= TIMER_TICKS_MAX)
#define TIMER2_PRESCALER 32
#elif (TIMER_TICKS(64) <= TIMER_TICKS_MAX)
#define TIMER2_PRESCALER 64
#elif (TIMER_TICKS(128) <= TIMER_TICKS_MAX)
#define TIMER2_PRESCALER 128
#elif (TIMER_TICKS(256) <= TIMER_TICKS_MAX)
#define TIMER2_PRESCALER 256
#elif (TIMER_TICKS(1024) <= TIMER_TICKS_MAX)
#define TIMER2_PRESCALER 1024
#else
#error "TIMER2: F_CPU too large for timer prescaler."
#endif
#define TIMER2_TICKS TIMER_TICKS(TIMER2_PRESCALER)
/* Timer counts up from count to TIMER_TICKS_MAX and then signals overflow */
#define TIMER2_COUNT (TIMER_TICKS_MAX-TIMER2_TICKS)
/* counter for the the timer which wraps every 49.7 days */
static volatile uint32_t Millisecond_Counter;
static volatile uint8_t Millisecond_Counter_Byte;
/*************************************************************************
* Description: Timer Interrupt Handler
* Returns: nothing
* Notes: none
*************************************************************************/
static inline void timer_interrupt_handler(
void)
{
/* Set the counter for the next interrupt */
TCNT2 = TIMER2_COUNT;
Millisecond_Counter++;
Millisecond_Counter_Byte++;
}
/*************************************************************************
* Description: Timer Interrupt Service Routine - Timer Overflowed!
* Returns: none
* Notes: Global interupts must be enabled
*************************************************************************/
ISR(TIMER2_OVF_vect)
{
timer_interrupt_handler();
}
/*************************************************************************
* Description: returns the current millisecond count
* Returns: none
* Notes: This method only disables the timer overflow interrupt.
*************************************************************************/
uint32_t timer_milliseconds(
void)
{
uint32_t timer_value; /* return value */
/* Disable the overflow interrupt.
Prevents value corruption that would happen if interrupted */
BIT_CLEAR(TIMSK2, TOIE2);
timer_value = Millisecond_Counter;
/* Enable the overflow interrupt */
BIT_SET(TIMSK2, TOIE2);
return timer_value;
}
/*************************************************************************
* Description: returns the current millisecond count
* Returns: none
* Notes: This method only disables the timer overflow interrupt.
*************************************************************************/
uint8_t timer_milliseconds_byte(
void)
{
return Millisecond_Counter;
}
/*************************************************************************
* Description: Initialization for Timer
* Returns: none
* Notes: none
*************************************************************************/
void timer_init(
void)
{
/* Normal Operation */
TCCR2A = 0;
/* Timer2: prescale selections:
CSn2 CSn1 CSn0 Description
---- ---- ---- -----------
0 0 0 No Clock Source
0 0 1 No prescaling
0 1 0 CLKt2s/8
0 1 1 CLKt2s/32
1 0 0 CLKt2s/64
1 0 1 CLKt2s/128
1 1 0 CLKt2s/256
1 1 1 CLKt2s/1024
*/
#if (TIMER2_PRESCALER==1)
TCCR2B = _BV(CS20);
#elif (TIMER2_PRESCALER==8)
TCCR2B = _BV(CS21);
#elif (TIMER2_PRESCALER==32)
TCCR2B = _BV(CS21) | _BV(CS20);
#elif (TIMER2_PRESCALER==64)
TCCR2B = _BV(CS22);
#elif (TIMER2_PRESCALER==128)
TCCR2B = _BV(CS22) | _BV(CS20);
#elif (TIMER2_PRESCALER==256)
TCCR2B = _BV(CS22) | _BV(CS21);
#elif (TIMER2_PRESCALER==1024)
TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
#else
#error Timer2 Prescale: Invalid Value
#endif
/* Clear any TOV Flag set when the timer overflowed - by setting! */
BIT_SET(TIFR2, TOV2);
/* Initial value */
TCNT2 = TIMER2_COUNT;
/* Enable the overflow interrupt */
BIT_SET(TIMSK2, TOIE2);
power_timer2_enable();
}
+103
View File
@@ -0,0 +1,103 @@
/**************************************************************************
*
* Copyright (C) 2009 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 "hardware.h"
#include "watchdog.h"
#if !defined(__GNUC__)
static inline void wdt_enable(
int value)
{
__disable_interrupt();
__watchdog_reset();
/* Start timed equence */
WDTCSR |= (1 << WDCE) | (1 << WDE);
/* Set new prescaler(time-out) value = 64K cycles (~0.5 s) */
WDTCSR = (1 << WDE) | (value);
/* we aren't ready to enable interrupts here
__enable_interrupt(); */
}
static inline void wdt_disable(
void)
{
__disable_interrupt();
__watchdog_reset();
/* Clear WDRF in MCUSR */
MCUSR &= ~(1 << WDRF);
/* Write logical one to WDCE and WDE */
/* Keep old prescaler setting to prevent unintentional time-out */
WDTCSR |= (1 << WDCE) | (1 << WDE);
/* Turn off WDT */
WDTCSR = 0x00;
__enable_interrupt();
}
static inline void wdt_reset(
void)
{
__watchdog_reset();
}
#endif
/*************************************************************************
* Description: Reset the watchdog timer
* Returns: none
* Notes: none
**************************************************************************/
void watchdog_reset(
void)
{
wdt_reset();
}
/*************************************************************************
* Description: Initialize the watchdog timer
* Returns: none
* Notes: none
**************************************************************************/
void watchdog_init(
unsigned milliseconds)
{
unsigned value = WDTO_15MS;
if (milliseconds) {
if (milliseconds <= 15) {
value = WDTO_15MS;
} else if (milliseconds <= 30) {
value = WDTO_30MS;
} else if (milliseconds <= 60) {
value = WDTO_60MS;
} else if (milliseconds <= 120) {
value = WDTO_120MS;
} else if (milliseconds <= 500) {
value = WDTO_500MS;
} else if (milliseconds <= 1000) {
value = WDTO_1S;
} else {
value = WDTO_2S;
}
wdt_enable(value);
} else {
wdt_disable();
}
}
+39
View File
@@ -0,0 +1,39 @@
/**************************************************************************
*
* Copyright (C) 2009 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 WATCHDOG_H
#define WATCHDOG_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void watchdog_reset(
void);
void watchdog_init(
unsigned milliseconds);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif