adjust root folder
This commit is contained in:
@@ -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.
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
|
||||
<workspace>
|
||||
<project>
|
||||
<path>$WS_DIR$\bacnet.ewp</path>
|
||||
</project>
|
||||
<batchBuild/>
|
||||
</workspace>
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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.
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user