adjust root folder
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
# gdb setup for J-Link - start JLinkGDBServer first
|
||||
target remote localhost:2331
|
||||
monitor reset
|
||||
monitor speed 5
|
||||
monitor speed auto
|
||||
monitor long 0xffffff60 0x00320100
|
||||
monitor long 0xfffffd44 0xa0008000
|
||||
monitor long 0xfffffc20 0xa0000601
|
||||
monitor sleep 100
|
||||
monitor long 0xfffffc2c 0x00480a0e
|
||||
monitor sleep 200
|
||||
monitor long 0xfffffc30 0x7
|
||||
monitor sleep 100
|
||||
monitor long 0xfffffd08 0xa5000401
|
||||
monitor sleep 100
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
# Makefile for AT91SAM7S evaluation kit with RS-485 Transceiver on UART0
|
||||
# Written by Steve Karg <skarg@users.sourceforge.net> 06-Aug-2007
|
||||
|
||||
TARGET=bacnet
|
||||
|
||||
# Tools
|
||||
#PREFIX=arm-elf-
|
||||
PREFIX ?= arm-none-eabi-
|
||||
#
|
||||
CC = $(PREFIX)gcc
|
||||
OBJCOPY = $(PREFIX)objcopy
|
||||
OBJDUMP = $(PREFIX)objdump
|
||||
AR = $(PREFIX)ar
|
||||
SIZE = $(PREFIX)size
|
||||
|
||||
LDSCRIPT = at91sam7s256.ld
|
||||
|
||||
BACNET_FLAGS = -DBACDL_MSTP
|
||||
BACNET_FLAGS += -DMAX_TSM_TRANSACTIONS=0
|
||||
BACNET_FLAGS += -DMAX_CHARACTER_STRING_BYTES=64
|
||||
BACNET_FLAGS += -DMAX_OCTET_STRING_BYTES=64
|
||||
BACNET_FLAGS += -DPRINT_ENABLED=0
|
||||
BACNET_FLAGS += -DMAX_APDU=480
|
||||
BACNET_FLAGS += -DCRC_USE_TABLE
|
||||
#BACNET_FLAGS += -DDLMSTP_TEST
|
||||
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_DEMO = ../../demo
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_OBJECT = ../../demo/object
|
||||
BACNET_HANDLER = ../../demo/handler
|
||||
INCLUDES = -I.
|
||||
INCLUDES += -I$(BACNET_INCLUDE)
|
||||
INCLUDES += -I$(BACNET_OBJECT)
|
||||
INCLUDES += -I$(BACNET_HANDLER)
|
||||
#OPTIMIZATION = -O0
|
||||
OPTIMIZATION = -Os
|
||||
CFLAGS = -fno-common $(INCLUDES) $(BACNET_FLAGS) -Wall -g
|
||||
CFLAGS += -mno-thumb-interwork
|
||||
# dead code removal
|
||||
CFLAGS += -fdata-sections -ffunction-sections
|
||||
LIBRARY = lib$(TARGET).a
|
||||
# -Wa,<options> Pass comma-separated <options> on to the assembler
|
||||
AFLAGS = -Wa,-ahls,-mapcs-32,-adhlns=$(<:.s=.lst)
|
||||
# -Wl,<options> Pass comma-separated <options> on to the linker
|
||||
LIBRARIES=-lc,-lgcc,-lm,-L.,-l$(TARGET)
|
||||
LDFLAGS = -nostartfiles
|
||||
LDFLAGS += -Wl,-nostdlib,-Map=$(TARGET).map,$(LIBRARIES),-T$(LDSCRIPT)
|
||||
# dead code removal
|
||||
LDFLAGS += -Wl,--gc-sections,-static
|
||||
CPFLAGS = --output-target=binary
|
||||
ODFLAGS = -x --syms
|
||||
|
||||
ASRC = crt.s
|
||||
|
||||
PORTSRC = main.c \
|
||||
timer.c \
|
||||
isr.c \
|
||||
init.c \
|
||||
blinker.c \
|
||||
rs485.c \
|
||||
dlmstp.c
|
||||
|
||||
DEMOSRC = ai.c \
|
||||
av.c \
|
||||
bi.c \
|
||||
bv.c \
|
||||
device.c \
|
||||
$(BACNET_DEMO)/handler/txbuf.c \
|
||||
$(BACNET_DEMO)/handler/noserv.c \
|
||||
$(BACNET_DEMO)/handler/h_npdu.c \
|
||||
$(BACNET_DEMO)/handler/h_whohas.c \
|
||||
$(BACNET_DEMO)/handler/h_whois.c \
|
||||
$(BACNET_DEMO)/handler/h_rd.c \
|
||||
$(BACNET_DEMO)/handler/h_rp.c \
|
||||
$(BACNET_DEMO)/handler/h_rpm.c \
|
||||
$(BACNET_DEMO)/handler/h_wp.c \
|
||||
$(BACNET_DEMO)/handler/h_dcc.c \
|
||||
$(BACNET_DEMO)/handler/s_iam.c \
|
||||
$(BACNET_DEMO)/handler/s_ihave.c
|
||||
|
||||
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)/datetime.c \
|
||||
$(BACNET_CORE)/dcc.c \
|
||||
$(BACNET_CORE)/iam.c \
|
||||
$(BACNET_CORE)/ihave.c \
|
||||
$(BACNET_CORE)/lighting.c \
|
||||
$(BACNET_CORE)/memcopy.c \
|
||||
$(BACNET_CORE)/npdu.c \
|
||||
$(BACNET_CORE)/proplist.c \
|
||||
$(BACNET_CORE)/rd.c \
|
||||
$(BACNET_CORE)/reject.c \
|
||||
$(BACNET_CORE)/ringbuf.c \
|
||||
$(BACNET_CORE)/rp.c \
|
||||
$(BACNET_CORE)/rpm.c \
|
||||
$(BACNET_CORE)/version.c \
|
||||
$(BACNET_CORE)/whohas.c \
|
||||
$(BACNET_CORE)/whois.c \
|
||||
$(BACNET_CORE)/wp.c
|
||||
|
||||
CSRC = $(PORTSRC) $(DEMOSRC)
|
||||
#CSRC = $(PORTSRC)
|
||||
|
||||
AOBJ = $(ASRC:.s=.o)
|
||||
COBJ = $(CSRC:.c=.o)
|
||||
COREOBJ = $(CORESRC:.c=.o)
|
||||
|
||||
all: $(TARGET).bin $(TARGET).elf
|
||||
$(OBJDUMP) $(ODFLAGS) $(TARGET).elf > $(TARGET).dmp
|
||||
$(SIZE) $(TARGET).elf
|
||||
|
||||
$(TARGET).bin: $(TARGET).elf
|
||||
$(OBJCOPY) $(TARGET).elf $(CPFLAGS) $(TARGET).bin
|
||||
|
||||
$(TARGET).elf: $(COBJ) $(AOBJ) $(LIBRARY) Makefile
|
||||
$(CC) $(CFLAGS) $(AOBJ) $(COBJ) $(LDFLAGS) -o $@
|
||||
|
||||
lib: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(COREOBJ) Makefile
|
||||
$(AR) rcs $@ $(COREOBJ)
|
||||
|
||||
# allow a single file to be unoptimized for debugging purposes
|
||||
#dlmstp.o:
|
||||
# $(CC) -c $(CFLAGS) $*.c -o $@
|
||||
#
|
||||
#main.o:
|
||||
# $(CC) -c $(CFLAGS) $*.c -o $@
|
||||
#
|
||||
#$(BACNET_CORE)/npdu.o:
|
||||
# $(CC) -c $(CFLAGS) $*.c -o $@
|
||||
#
|
||||
#$(BACNET_CORE)/apdu.o:
|
||||
# $(CC) -c $(CFLAGS) $*.c -o $@
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(OPTIMIZATION) $(CFLAGS) $*.c -o $@
|
||||
|
||||
.s.o:
|
||||
$(CC) -c $(AFLAGS) $*.s -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -rf $(COBJ) $(AOBJ) $(COREOBJ)
|
||||
-rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).dmp $(TARGET).map
|
||||
-rm -rf $(LIBRARY)
|
||||
-rm -rf *.lst
|
||||
|
||||
## Other dependencies
|
||||
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)
|
||||
@@ -0,0 +1,221 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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
|
||||
#if (MAX_ANALOG_INPUTS > 9)
|
||||
#error Modify the Analog_Input_Name to handle multiple digits
|
||||
#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[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Analog_Input_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Analog_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Analog_Input_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Analog_Input_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Analog_Input_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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[16] = "AI-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
text_string[3] = '0' + (uint8_t) 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 has already exists */
|
||||
int Analog_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
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], OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0],
|
||||
Analog_Input_Present_Value(rpdata->object_instance));
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = 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;
|
||||
}
|
||||
|
||||
void Analog_Input_Init(
|
||||
void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,156 @@
|
||||
/* ****************************************************************************************************** */
|
||||
/* LINKER SCRIPT */
|
||||
/* */
|
||||
/* */
|
||||
/* The Linker Script defines how the code and data emitted by the GNU C compiler and assembler are */
|
||||
/* to be loaded into memory (code goes into FLASH, variables go into RAM). */
|
||||
/* */
|
||||
/* Any symbols defined in the Linker Script are automatically global and available to the rest of the */
|
||||
/* program. */
|
||||
/* */
|
||||
/* To force the linker to use this LINKER SCRIPT, just add the -T AT91SAM7S256.LD */
|
||||
/* directive to the linker flags in the makefile. For example, */
|
||||
/* */
|
||||
/* LFLAGS = -Map main.map -nostartfiles -T AT91SAM7S256.LD */
|
||||
/* */
|
||||
/* */
|
||||
/* The order that the object files are listed in the makefile determines what .text section is */
|
||||
/* placed first. */
|
||||
/* */
|
||||
/* For example: $(LD) $(LFLAGS) -o main.out crt.o main.o lowlevelinit.o */
|
||||
/* */
|
||||
/* crt.o is first in the list of objects, so it will be placed at address 0x00000000 */
|
||||
/* */
|
||||
/* */
|
||||
/* The top of the stack (_stack_end) is (last_byte_of_ram +1) - 4 */
|
||||
/* */
|
||||
/* Therefore: _stack_end = (0x00020FFFF + 1) - 4 = 0x00210000 - 4 = 0x0020FFFC */
|
||||
/* Therefore: _stack_end = (0x000203FFF + 1) - 4 = 0x00204000 - 4 = 0x00203FFC */
|
||||
/* */
|
||||
/* Note that this symbol (_stack_end) is automatically GLOBAL and will be used by the crt.s */
|
||||
/* startup assembler routine to specify all stacks for the various ARM modes */
|
||||
/* */
|
||||
/* MEMORY MAP */
|
||||
/* | | */
|
||||
/* .-------->|---------------------------------|0x00210000 */
|
||||
/* . | |0x0020FFFC <---------- _stack_end */
|
||||
/* . | UDF Stack 16 bytes | */
|
||||
/* . | | */
|
||||
/* . |---------------------------------|0x0020FFEC */
|
||||
/* . | | */
|
||||
/* . | ABT Stack 16 bytes | */
|
||||
/* . | | */
|
||||
/* . |---------------------------------|0x0020FFDC */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* . | FIQ Stack 128 bytes | */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* RAM |---------------------------------|0x0020FF5C */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* . | IRQ Stack 128 bytes | */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* . |---------------------------------|0x0020FEDC */
|
||||
/* . | | */
|
||||
/* . | SVC Stack 16 bytes | */
|
||||
/* . | | */
|
||||
/* . |---------------------------------|0x0020FECC */
|
||||
/* . | | */
|
||||
/* . | stack area for user program | */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* . | free ram | */
|
||||
/* . | | */
|
||||
/* . |.................................|0x002006D8 <---------- _bss_end */
|
||||
/* . | | */
|
||||
/* . | .bss uninitialized variables | */
|
||||
/* . |.................................|0x002006D0 <---------- _bss_start, _edata */
|
||||
/* . | | */
|
||||
/* . | .data initialized variables | */
|
||||
/* . | | */
|
||||
/* .-------->|_________________________________|0x00200000 */
|
||||
/* */
|
||||
/* */
|
||||
/* .-------->|---------------------------------|0x00100000 */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* . | free flash | */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* . |.................................|0x000006D0 <---------- _bss_start, _edata */
|
||||
/* . | | */
|
||||
/* . | .data initialized variables | */
|
||||
/* . | | */
|
||||
/* . |---------------------------------|0x000006C4 <----------- _etext */
|
||||
/* . | | */
|
||||
/* . | C code | */
|
||||
/* . | | */
|
||||
/* . | | */
|
||||
/* . |---------------------------------|0x00000118 main() */
|
||||
/* . | | */
|
||||
/* . | Startup Code (crt.s) | */
|
||||
/* . | (assembler) | */
|
||||
/* . | | */
|
||||
/* . |---------------------------------|0x00000020 */
|
||||
/* . | | */
|
||||
/* . | Interrupt Vector Table | */
|
||||
/* . | 32 bytes | */
|
||||
/* .-------->|---------------------------------|0x00000000 _vec_reset */
|
||||
/* */
|
||||
/* */
|
||||
/* Author: James P. Lynch May 12, 2007 */
|
||||
/* */
|
||||
/* ****************************************************************************************************** */
|
||||
|
||||
|
||||
/* identify the Entry Point (_vec_reset is defined in file crt.s) */
|
||||
ENTRY(_vec_reset)
|
||||
|
||||
/* specify the AT91SAM7S64 memory areas */
|
||||
MEMORY
|
||||
{
|
||||
flash : ORIGIN = 0, LENGTH = 64K /* FLASH EPROM */
|
||||
ram : ORIGIN = 0x00200000, LENGTH = 16K /* static RAM area */
|
||||
}
|
||||
|
||||
|
||||
/* define a global symbol _stack_end (see analysis in annotation above) */
|
||||
/*_stack_end = 0x20FFFC;*/
|
||||
_stack_end = 0x203FFC;
|
||||
|
||||
/* now define the output sections */
|
||||
SECTIONS
|
||||
{
|
||||
. = 0; /* set location counter to address zero */
|
||||
|
||||
.text : /* collect all sections that should go into FLASH after startup */
|
||||
{
|
||||
*(.text*) /* all .text sections (code) */
|
||||
*(.rodata) /* all .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* all .rodata* sections (constants, strings, etc.) */
|
||||
*(.glue_7) /* all .glue_7 sections (no idea what these are) */
|
||||
*(.glue_7t) /* all .glue_7t sections (no idea what these are) */
|
||||
_etext = .; /* define a global symbol _etext just after the last code byte */
|
||||
} >flash /* put all the above into FLASH */
|
||||
|
||||
.data : /* collect all initialized .data sections that go into RAM */
|
||||
{
|
||||
_data = .; /* create a global symbol marking the start of the .data section */
|
||||
*(.data*) /* all .data sections */
|
||||
_edata = .; /* define a global symbol marking the end of the .data section */
|
||||
} >ram AT >flash /* put all the above into RAM (but load the LMA initializer copy into FLASH) */
|
||||
|
||||
.bss : /* collect all uninitialized .bss sections that go into RAM */
|
||||
{
|
||||
_bss_start = .; /* define a global symbol marking the start of the .bss section */
|
||||
*(.bss*) /* all .bss sections */
|
||||
} >ram /* put all the above in RAM (it will be cleared in the startup code */
|
||||
|
||||
. = ALIGN(4); /* advance location counter to the next 32-bit boundary */
|
||||
_bss_end = . ; /* define a global symbol marking the end of the .bss section */
|
||||
}
|
||||
_end = .; /* define a global symbol marking the end of application RAM */
|
||||
|
||||
@@ -0,0 +1,449 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "av.h"
|
||||
#include "handlers.h"
|
||||
|
||||
#ifndef MAX_ANALOG_VALUES
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
#endif
|
||||
#if (MAX_ANALOG_VALUES > 9)
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
/* we choose to have a NULL level in our system represented by */
|
||||
/* a particular value. When the priorities are not in use, they */
|
||||
/* will be relinquished (i.e. set to the NULL level). */
|
||||
#define ANALOG_LEVEL_NULL 255
|
||||
/* When all the priorities are level null, the present value returns */
|
||||
/* the Relinquish Default value */
|
||||
#define ANALOG_RELINQUISH_DEFAULT 0
|
||||
/* Here is our Present_Value. They are supposed to be Real, but */
|
||||
/* we don't have that kind of memory, so we will use a single byte */
|
||||
/* and load a Real for returning the value when asked. */
|
||||
static uint8_t Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* 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[] = {
|
||||
PROP_DESCRIPTION,
|
||||
#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)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/* initialize all the analog output priority arrays to NULL */
|
||||
for (i = 0; i < MAX_ANALOG_VALUES; i++) {
|
||||
Present_Value[i] = ANALOG_LEVEL_NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
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 = ANALOG_RELINQUISH_DEFAULT;
|
||||
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_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[16] = "AV-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_ANALOG_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t) 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;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
float real_value = (float) 1.414;
|
||||
#if 0
|
||||
int len = 0;
|
||||
unsigned object_index = 0;
|
||||
unsigned i = 0;
|
||||
bool state = false;
|
||||
#endif
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
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], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
real_value = Analog_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_real(&apdu[0], real_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(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(rpdata->object_instance);
|
||||
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
|
||||
/* FIXME: check if we have room before adding it to APDU */
|
||||
if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL)
|
||||
len = encode_application_null(&apdu[apdu_len]);
|
||||
else {
|
||||
real_value = Present_Value[object_index][i];
|
||||
len =
|
||||
encode_application_real(&apdu[apdu_len],
|
||||
real_value);
|
||||
}
|
||||
/* add it if we have room */
|
||||
if ((apdu_len + len) < MAX_APDU)
|
||||
apdu_len += len;
|
||||
else {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
if (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 */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
uint8_t level = ANALOG_LEVEL_NULL;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Real >= 0.0) && (value.type.Real <= 100.0)) {
|
||||
level = (uint8_t) value.type.Real;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#if 0
|
||||
} else if (value.tag == BACNET_APPLICATION_TAG_NULL) {
|
||||
level = ANALOG_LEVEL_NULL;
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
priority = wp_data->priority;
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
|
||||
priority--;
|
||||
Present_Value[object_index][priority] = level;
|
||||
/* Note: you could set the physical output here to the next
|
||||
highest priority, or to the relinquish default if no
|
||||
priorities are set.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. This comment may apply to the
|
||||
main loop (i.e. check out of service before changing output) */
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Analog_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_UNITS:
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_DESCRIPTION:
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
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,233 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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"
|
||||
|
||||
#define MAX_BINARY_INPUTS 8
|
||||
#if (MAX_BINARY_INPUTS > 9)
|
||||
#error Modify the Binary_Input_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Binary_Input_Properties_Required[] = {
|
||||
PROP_OBJECT_IDENTIFIER,
|
||||
PROP_OBJECT_NAME,
|
||||
PROP_OBJECT_TYPE,
|
||||
PROP_PRESENT_VALUE,
|
||||
PROP_STATUS_FLAGS,
|
||||
PROP_EVENT_STATE,
|
||||
PROP_OUT_OF_SERVICE,
|
||||
PROP_POLARITY,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Binary_Input_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Binary_Input_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Binary_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired) {
|
||||
*pRequired = Binary_Input_Properties_Required;
|
||||
}
|
||||
if (pOptional) {
|
||||
*pOptional = Binary_Input_Properties_Optional;
|
||||
}
|
||||
if (pProprietary) {
|
||||
*pProprietary = Binary_Input_Properties_Proprietary;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[16] = "BI-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_BINARY_INPUTS) {
|
||||
text_string[3] = '0' + (uint8_t) 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;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_INPUT,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
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], OBJECT_BINARY_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
value = Binary_Input_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = 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,42 @@
|
||||
/*****************************************************************************
|
||||
blinker.c
|
||||
|
||||
Endless loop blinks a code for crash analysis
|
||||
|
||||
Inputs: Code - blink code to display
|
||||
1 = undefined instruction (one blinks ........ long pause)
|
||||
2 = prefetch abort (two blinks ........ long pause)
|
||||
3 = data abort (three blinks ...... long pause)
|
||||
|
||||
Author: James P Lynch May 12, 2007
|
||||
*****************************************************************************/
|
||||
#include "board.h"
|
||||
|
||||
/* global variables */
|
||||
unsigned long blinkcount;
|
||||
|
||||
void blinker(
|
||||
unsigned char code)
|
||||
{
|
||||
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA; /* pointer to PIO register structure */
|
||||
volatile unsigned int j, k; /* loop counters */
|
||||
|
||||
/* endless loop */
|
||||
while (1) {
|
||||
/* count out the proper number of blinks */
|
||||
for (j = code; j != 0; j--) {
|
||||
/* turn LED1 (DS1) on */
|
||||
pPIO->PIO_CODR = LED1;
|
||||
/* wait 250 msec */
|
||||
for (k = 600000; k != 0; k--);
|
||||
/* turn LED1 (DS1) off */
|
||||
pPIO->PIO_SODR = LED1;
|
||||
/* wait 250 msec */
|
||||
for (k = 600000; k != 0; k--);
|
||||
}
|
||||
/* wait 2 seconds */
|
||||
for (k = 5000000; (code != 0) && (k != 0); k--);
|
||||
blinkcount++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*---------------------------------------------------------------------------------------------------- */
|
||||
/* ATMEL Microcontroller Software Support - ROUSSET - */
|
||||
/*---------------------------------------------------------------------------------------------------- */
|
||||
/* The software is delivered "AS IS" without warranty or condition of any */
|
||||
/* kind, either express, implied or statutory. This includes without */
|
||||
/* limitation any warranty or condition with respect to merchantability or */
|
||||
/* fitness for any particular purpose, or against the infringements of */
|
||||
/* intellectual property rights of others. */
|
||||
/*---------------------------------------------------------------------------------------------------- */
|
||||
/* File Name: Board.h */
|
||||
/* Object: AT91SAM7S Evaluation Board Features Definition File. */
|
||||
/* */
|
||||
/* Creation: JPP 16/June/2004 */
|
||||
/*---------------------------------------------------------------------------------------------------- */
|
||||
#ifndef Board_h
|
||||
#define Board_h
|
||||
|
||||
#include "at91sam7s256.h"
|
||||
#include "isr.h"
|
||||
#define __inline inline
|
||||
|
||||
/*----------------------------------------------- */
|
||||
/* SAM7Board Memories Definition */
|
||||
/*----------------------------------------------- */
|
||||
/* The AT91SAM7S2564 embeds a 64-Kbyte SRAM bank, and 256 K-Byte Flash */
|
||||
|
||||
#define INT_SRAM 0x00200000
|
||||
#define INT_SRAM_REMAP 0x00000000
|
||||
|
||||
#define INT_FLASH 0x00000000
|
||||
#define INT_FLASH_REMAP 0x01000000
|
||||
|
||||
#define FLASH_PAGE_NB 512
|
||||
#define FLASH_PAGE_SIZE 128
|
||||
|
||||
/*------------------------ */
|
||||
/* Leds Definition */
|
||||
/*------------------------ */
|
||||
#define LED1 (1<<0) /* PA0 */
|
||||
#define LED2 (1<<1) /* PA1 */
|
||||
#define LED3 (1<<2) /* PA2 */
|
||||
#define LED4 (1<<3) /* PA3 */
|
||||
#define NB_LEB 4
|
||||
#define LED_MASK (LED1|LED2|LED3|LED4)
|
||||
|
||||
|
||||
/*---------------------------------- */
|
||||
/* Push Buttons Definition */
|
||||
/*----------------------------------- */
|
||||
#define SW1_MASK (1<<19) /* PA19 */
|
||||
#define SW2_MASK (1<<20) /* PA20 */
|
||||
#define SW3_MASK (1<<15) /* PA15 */
|
||||
#define SW4_MASK (1<<14) /* PA14 */
|
||||
#define SW_MASK (SW1_MASK|SW2_MASK|SW3_MASK|SW4_MASK)
|
||||
|
||||
#define SW1 (1<<19) /* PA19 */
|
||||
#define SW2 (1<<20) /* PA20 */
|
||||
#define SW3 (1<<15) /* PA15 */
|
||||
#define SW4 (1<<14) /* PA14 */
|
||||
|
||||
/*------------------------- */
|
||||
/* USART Definition */
|
||||
/*------------------------- */
|
||||
/* SUB-D 9 points J3 DBGU */
|
||||
#define DBGU_RXD AT91C_PA9_DRXD /* JP11 must be close */
|
||||
#define DBGU_TXD AT91C_PA10_DTXD /* JP12 must be close */
|
||||
#define AT91C_DBGU_BAUD 115200 /* Baud rate */
|
||||
#define US_RXD_PIN AT91C_PA5_RXD0 /* JP9 must be close */
|
||||
#define US_TXD_PIN AT91C_PA6_TXD0 /* JP7 must be close */
|
||||
#define US_RTS_PIN AT91C_PA7_RTS0 /* JP8 must be close */
|
||||
#define US_CTS_PIN AT91C_PA8_CTS0 /* JP6 must be close */
|
||||
|
||||
/*-------------- */
|
||||
/* Master Clock */
|
||||
/*-------------- */
|
||||
#define EXT_OC 18432000 /* Exetrnal ocilator MAINCK */
|
||||
#define MCK 47923200 /* MCK (PLLRC div by 2) */
|
||||
#define MCKKHz (MCK/1000) /* */
|
||||
|
||||
#endif /* Board_h */
|
||||
@@ -0,0 +1,337 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "bv.h"
|
||||
#include "handlers.h"
|
||||
|
||||
#ifndef MAX_BINARY_VALUES
|
||||
#define MAX_BINARY_VALUES 8
|
||||
#endif
|
||||
#if (MAX_BINARY_VALUES > 9)
|
||||
#error Modify the Binary_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
/* These three arrays are used by the ReadPropertyMultiple handler */
|
||||
static const int Binary_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,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Binary_Value_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Binary_Value_Properties_Proprietary[] = {
|
||||
-1
|
||||
};
|
||||
|
||||
void Binary_Value_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (pRequired)
|
||||
*pRequired = Binary_Value_Properties_Required;
|
||||
if (pOptional)
|
||||
*pOptional = Binary_Value_Properties_Optional;
|
||||
if (pProprietary)
|
||||
*pProprietary = Binary_Value_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Binary_Value_Init(
|
||||
void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < MAX_BINARY_VALUES; i++) {
|
||||
Present_Value[i] = BINARY_INACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_BINARY_VALUES;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Binary_Value_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Binary_Value_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
unsigned index = MAX_BINARY_VALUES;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES)
|
||||
index = object_instance;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
BACNET_BINARY_PV Binary_Value_Present_Value(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
BACNET_BINARY_PV value = BINARY_INACTIVE;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
value = Present_Value[object_instance];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
bool Binary_Value_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
static char text_string[16] = "BV-0"; /* okay for single thread */
|
||||
bool status = false;
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
status = characterstring_init_ansi(object_name, text_string);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
|
||||
uint8_t *apdu = NULL;
|
||||
|
||||
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
|
||||
(rpdata->application_data_len == 0)) {
|
||||
return 0;
|
||||
}
|
||||
apdu = rpdata->application_data;
|
||||
switch (rpdata->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
rpdata->object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
Binary_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], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value =
|
||||
Binary_Value_Present_Value(rpdata->object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_POLARITY:
|
||||
/* FIXME: figure out the polarity */
|
||||
apdu_len = encode_application_enumerated(&apdu[0], polarity);
|
||||
break;
|
||||
default:
|
||||
rpdata->error_class = ERROR_CLASS_PROPERTY;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = 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;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
unsigned int priority = 0;
|
||||
BACNET_BINARY_PV level = BINARY_NULL;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
wp_data->error_class = ERROR_CLASS_OBJECT;
|
||||
wp_data->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
return false;
|
||||
}
|
||||
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
|
||||
(wp_data->array_index != BACNET_ARRAY_ALL)) {
|
||||
/* only array properties can have array options */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
priority = wp_data->priority;
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
if (priority && (priority <= BACNET_MAX_PRIORITY) &&
|
||||
(priority != 6 /* reserved */ ) &&
|
||||
(value.type.Enumerated >= MIN_BINARY_PV) &&
|
||||
(value.type.Enumerated <= MAX_BINARY_PV)) {
|
||||
level = value.type.Enumerated;
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
priority--;
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] = level;
|
||||
/* Note: you could set the physical output here if we
|
||||
are the highest priority.
|
||||
However, if Out of Service is TRUE, then don't set the
|
||||
physical output. */
|
||||
status = true;
|
||||
} else if (priority == 6) {
|
||||
/* Command priority 6 is reserved for use by Minimum On/Off
|
||||
algorithm and may not be used for other purposes in any
|
||||
object. */
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
#if 0
|
||||
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->object_instance);
|
||||
Binary_Value_Out_Of_Service[object_index] = value.type.Boolean;
|
||||
status = true;
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
case PROP_RELINQUISH_DEFAULT:
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
/* ****************************************************************************************************** */
|
||||
/* crt.s */
|
||||
/* */
|
||||
/* Assembly Language Startup Code for Atmel AT91SAM7S256 */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* Author: James P Lynch May 12, 2007 */
|
||||
/* ****************************************************************************************************** */
|
||||
|
||||
/* Stack Sizes */
|
||||
.set UND_STACK_SIZE, 0x00000010 /* stack for "undefined instruction" interrupts is 16 bytes */
|
||||
.set ABT_STACK_SIZE, 0x00000010 /* stack for "abort" interrupts is 16 bytes */
|
||||
.set FIQ_STACK_SIZE, 0x00000080 /* stack for "FIQ" interrupts is 128 bytes */
|
||||
.set IRQ_STACK_SIZE, 0X00000080 /* stack for "IRQ" normal interrupts is 128 bytes */
|
||||
.set SVC_STACK_SIZE, 0x00000080 /* stack for "SVC" supervisor mode is 128 bytes */
|
||||
|
||||
/* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs (program status registers) */
|
||||
.set ARM_MODE_USR, 0x10 /* Normal User Mode */
|
||||
.set ARM_MODE_FIQ, 0x11 /* FIQ Processing Fast Interrupts Mode */
|
||||
.set ARM_MODE_IRQ, 0x12 /* IRQ Processing Standard Interrupts Mode */
|
||||
.set ARM_MODE_SVC, 0x13 /* Supervisor Processing Software Interrupts Mode */
|
||||
.set ARM_MODE_ABT, 0x17 /* Abort Processing memory Faults Mode */
|
||||
.set ARM_MODE_UND, 0x1B /* Undefined Processing Undefined Instructions Mode */
|
||||
.set ARM_MODE_SYS, 0x1F /* System Running Priviledged Operating System Tasks Mode */
|
||||
.set I_BIT, 0x80 /* when I bit is set, IRQ is disabled (program status registers) */
|
||||
.set F_BIT, 0x40 /* when F bit is set, FIQ is disabled (program status registers) */
|
||||
|
||||
/* Addresses and offsets of AIC and PIO */
|
||||
.set AT91C_BASE_AIC, 0xFFFFF000 /* (AIC) Base Address */
|
||||
.set AT91C_PIOA_CODR, 0xFFFFF434 /* (PIO) Clear Output Data Register */
|
||||
.set AT91C_AIC_IVR, 0xFFFFF100 /* (AIC) IRQ Interrupt Vector Register */
|
||||
.set AT91C_AIC_FVR, 0xFFFFF104 /* (AIC) FIQ Interrupt Vector Register */
|
||||
.set AIC_IVR, 256 /* IRQ Vector Register offset from base above */
|
||||
.set AIC_FVR, 260 /* FIQ Vector Register offset from base above */
|
||||
.set AIC_EOICR, 304 /* End of Interrupt Command Register */
|
||||
|
||||
/* identify all GLOBAL symbols */
|
||||
.global _vec_reset
|
||||
.global _vec_undef
|
||||
.global _vec_swi
|
||||
.global _vec_pabt
|
||||
.global _vec_dabt
|
||||
.global _vec_rsv
|
||||
.global _vec_irq
|
||||
.global _vec_fiq
|
||||
.global AT91F_Irq_Handler
|
||||
.global AT91F_Fiq_Handler
|
||||
.global AT91F_Default_FIQ_handler
|
||||
.global AT91F_Default_IRQ_handler
|
||||
.global AT91F_Spurious_handler
|
||||
.global AT91F_Dabt_Handler
|
||||
.global AT91F_Pabt_Handler
|
||||
.global AT91F_Undef_Handler
|
||||
|
||||
|
||||
/* GNU assembler controls */
|
||||
.text /* all assembler code that follows will go into .text section */
|
||||
.arm /* compile for 32-bit ARM instruction set */
|
||||
.align /* align section on 32-bit boundary */
|
||||
|
||||
/* ============================================================ */
|
||||
/* VECTOR TABLE */
|
||||
/* */
|
||||
/* Must be located in FLASH at address 0x00000000 */
|
||||
/* */
|
||||
/* Easy to do if this file crt.s is first in the list */
|
||||
/* for the linker step in the makefile, e.g. */
|
||||
/* */
|
||||
/* $(LD) $(LFLAGS) -o main.out crt.o main.o */
|
||||
/* */
|
||||
/* ============================================================ */
|
||||
|
||||
_vec_reset: b _init_reset /* RESET vector - must be at 0x00000000 */
|
||||
_vec_undef: b AT91F_Undef_Handler /* Undefined Instruction vector */
|
||||
_vec_swi: b _vec_swi /* Software Interrupt vector */
|
||||
_vec_pabt: b AT91F_Pabt_Handler /* Prefetch abort vector */
|
||||
_vec_dabt: b AT91F_Dabt_Handler /* Data abort vector */
|
||||
_vec_rsv: nop /* Reserved vector */
|
||||
_vec_irq: b AT91F_Irq_Handler /* Interrupt Request (IRQ) vector */
|
||||
_vec_fiq: /* Fast interrupt request (FIQ) vector */
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Function: AT91F_Fiq_Handler */
|
||||
/* */
|
||||
/* The FIQ interrupt asserts when switch SW1 is pressed. */
|
||||
/* */
|
||||
/* This simple FIQ handler turns on LED3 (Port PA2). The LED3 will be */
|
||||
/* turned off by the background loop in main() thus giving a visual */
|
||||
/* indication that the interrupt has occurred. */
|
||||
/* */
|
||||
/* This FIQ_Handler supports non-nested FIQ interrupts (a FIQ interrupt */
|
||||
/* cannot itself be interrupted). */
|
||||
/* */
|
||||
/* The Fast Interrupt Vector Register (AIC_FVR) is read to clear the */
|
||||
/* interrupt. */
|
||||
/* */
|
||||
/* A global variable FiqCount is also incremented. */
|
||||
/* */
|
||||
/* Remember that switch SW1 is not debounced, so the FIQ interrupt may */
|
||||
/* occur more than once for a single button push. */
|
||||
/* */
|
||||
/* Programmer: James P Lynch */
|
||||
/* ======================================================================== */
|
||||
AT91F_Fiq_Handler:
|
||||
|
||||
/* Adjust LR_irq */
|
||||
sub lr, lr, #4
|
||||
|
||||
/* Read the AIC Fast Interrupt Vector register to clear the interrupt */
|
||||
ldr r12, =AT91C_AIC_FVR
|
||||
ldr r11, [r12]
|
||||
|
||||
/* Return from Fiq interrupt */
|
||||
movs pc, lr
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* _init_reset Handler */
|
||||
/* */
|
||||
/* RESET vector 0x00000000 branches to here. */
|
||||
/* */
|
||||
/* ARM microprocessor begins execution after RESET at address 0x00000000 */
|
||||
/* in Supervisor mode with interrupts disabled! */
|
||||
/* */
|
||||
/* _init_reset handler: creates a stack for each ARM mode. */
|
||||
/* sets up a stack pointer for each ARM mode. */
|
||||
/* turns off interrupts in each mode. */
|
||||
/* leaves CPU in SYS (System) mode. */
|
||||
/* */
|
||||
/* block copies the initializers to .data section */
|
||||
/* clears the .bss section to zero */
|
||||
/* */
|
||||
/* branches to main( ) */
|
||||
/* ======================================================================== */
|
||||
.text /* all assembler code that follows will go into .text section */
|
||||
.align /* align section on 32-bit boundary */
|
||||
_init_reset:
|
||||
/* Setup a stack for each mode with interrupts initially disabled. */
|
||||
ldr r0, =_stack_end /* r0 = top-of-stack */
|
||||
|
||||
msr CPSR_c, #ARM_MODE_UND|I_BIT|F_BIT /* switch to Undefined Instruction Mode */
|
||||
mov sp, r0 /* set stack pointer for UND mode */
|
||||
sub r0, r0, #UND_STACK_SIZE /* adjust r0 past UND stack */
|
||||
|
||||
msr CPSR_c, #ARM_MODE_ABT|I_BIT|F_BIT /* switch to Abort Mode */
|
||||
mov sp, r0 /* set stack pointer for ABT mode */
|
||||
sub r0, r0, #ABT_STACK_SIZE /* adjust r0 past ABT stack */
|
||||
|
||||
msr CPSR_c, #ARM_MODE_FIQ|I_BIT|F_BIT /* switch to FIQ Mode */
|
||||
mov sp, r0 /* set stack pointer for FIQ mode */
|
||||
sub r0, r0, #FIQ_STACK_SIZE /* adjust r0 past FIQ stack */
|
||||
|
||||
msr CPSR_c, #ARM_MODE_IRQ|I_BIT|F_BIT /* switch to IRQ Mode */
|
||||
mov sp, r0 /* set stack pointer for IRQ mode */
|
||||
sub r0, r0, #IRQ_STACK_SIZE /* adjust r0 past IRQ stack */
|
||||
|
||||
msr CPSR_c, #ARM_MODE_SVC|I_BIT|F_BIT /* switch to Supervisor Mode */
|
||||
mov sp, r0 /* set stack pointer for SVC mode */
|
||||
sub r0, r0, #SVC_STACK_SIZE /* adjust r0 past SVC stack */
|
||||
|
||||
msr CPSR_c, #ARM_MODE_SYS|I_BIT|F_BIT /* switch to System Mode */
|
||||
mov sp, r0 /* set stack pointer for SYS mode */
|
||||
/* we now start execution in SYSTEM mode */
|
||||
/* This is exactly like USER mode (same stack) */
|
||||
/* but SYSTEM mode has more privileges */
|
||||
|
||||
/* copy initialized variables .data section (Copy from ROM to RAM) */
|
||||
ldr R1, =_etext
|
||||
ldr R2, =_data
|
||||
ldr R3, =_edata
|
||||
1: cmp R2, R3
|
||||
ldrlo R0, [R1], #4
|
||||
strlo R0, [R2], #4
|
||||
blo 1b
|
||||
|
||||
/* Clear uninitialized variables .bss section (Zero init) */
|
||||
mov R0, #0
|
||||
ldr R1, =_bss_start
|
||||
ldr R2, =_bss_end
|
||||
2: cmp R1, R2
|
||||
strlo R0, [R1], #4
|
||||
blo 2b
|
||||
|
||||
/* Enter the C code */
|
||||
b main
|
||||
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Function: AT91F_Irq_Handler */
|
||||
/* */
|
||||
/* This IRQ_Handler supports nested interrupts (an IRQ interrupt can itself */
|
||||
/* be interrupted). */
|
||||
/* */
|
||||
/* This handler re-enables interrupts and switches to "Supervisor" mode to */
|
||||
/* prevent any corruption to the link and IP registers. */
|
||||
/* */
|
||||
/* The Interrupt Vector Register (AIC_IVR) is read to determine the address */
|
||||
/* of the required interrupt service routine. The ISR routine can be a */
|
||||
/* standard C function since this handler minds all the save/restore */
|
||||
/* protocols. */
|
||||
/* */
|
||||
/* */
|
||||
/* Programmers: */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* ATMEL Microcontroller Software Support - ROUSSET - */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS */
|
||||
/* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
|
||||
/* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
|
||||
/* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR */
|
||||
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR */
|
||||
/* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT */
|
||||
/* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */
|
||||
/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */
|
||||
/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE */
|
||||
/* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
|
||||
/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
||||
/* File source : Cstartup.s79 */
|
||||
/* Object : Generic CStartup to AT91SAM7S256 */
|
||||
/* 1.0 09/May/06 JPP : Creation */
|
||||
/* */
|
||||
/* */
|
||||
/* Note: taken from Atmel web site (www.at91.com) */
|
||||
/* Keil example project: AT91SAM7S-Interrupt_SAM7S */
|
||||
/* ======================================================================== */
|
||||
AT91F_Irq_Handler:
|
||||
|
||||
/* Manage Exception Entry */
|
||||
/* Adjust and save LR_irq in IRQ stack */
|
||||
sub lr, lr, #4
|
||||
stmfd sp!, {lr}
|
||||
|
||||
/* Save r0 and SPSR (need to be saved for nested interrupt) */
|
||||
mrs r14, SPSR
|
||||
stmfd sp!, {r0,r14}
|
||||
|
||||
/* Write in the IVR to support Protect Mode */
|
||||
/* No effect in Normal Mode */
|
||||
/* De-assert the NIRQ and clear the source in Protect Mode */
|
||||
ldr r14, =AT91C_BASE_AIC
|
||||
ldr r0 , [r14, #AIC_IVR]
|
||||
str r14, [r14, #AIC_IVR]
|
||||
|
||||
/* Enable Interrupt and Switch in Supervisor Mode */
|
||||
msr CPSR_c, #ARM_MODE_SVC
|
||||
|
||||
/* Save scratch/used registers and LR in User Stack */
|
||||
stmfd sp!, { r1-r3, r12, r14}
|
||||
|
||||
/* Branch to the routine pointed by the AIC_IVR */
|
||||
mov r14, pc
|
||||
bx r0
|
||||
|
||||
/* Manage Exception Exit */
|
||||
/* Restore scratch/used registers and LR from User Stack */
|
||||
ldmia sp!, { r1-r3, r12, r14}
|
||||
|
||||
/* Disable Interrupt and switch back in IRQ mode */
|
||||
msr CPSR_c, #I_BIT | ARM_MODE_IRQ
|
||||
|
||||
/* Mark the End of Interrupt on the AIC */
|
||||
ldr r14, =AT91C_BASE_AIC
|
||||
str r14, [r14, #AIC_EOICR]
|
||||
|
||||
/* Restore SPSR_irq and r0 from IRQ stack */
|
||||
ldmia sp!, {r0,r14}
|
||||
msr SPSR_cxsf, r14
|
||||
|
||||
/* Restore adjusted LR_irq from IRQ stack directly in the PC */
|
||||
ldmia sp!, {pc}^
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Function: AT91F_Dabt_Handler */
|
||||
/* */
|
||||
/* Entered on Data Abort exception. */
|
||||
/* Enters blink routine (3 blinks followed by a pause) */
|
||||
/* processor hangs in the blink loop forever */
|
||||
/* */
|
||||
/* ======================================================================== */
|
||||
AT91F_Dabt_Handler: mov R0, #3
|
||||
b blinker
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Function: AT91F_Pabt_Handler */
|
||||
/* */
|
||||
/* Entered on Prefetch Abort exception. */
|
||||
/* Enters blink routine (2 blinks followed by a pause) */
|
||||
/* processor hangs in the blink loop forever */
|
||||
/* */
|
||||
/* ======================================================================== */
|
||||
AT91F_Pabt_Handler: mov R0, #2
|
||||
b blinker
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* Function: AT91F_Undef_Handler */
|
||||
/* */
|
||||
/* Entered on Undefined Instruction exception. */
|
||||
/* Enters blink routine (1 blinks followed by a pause) */
|
||||
/* processor hangs in the blink loop forever */
|
||||
/* */
|
||||
/* ======================================================================== */
|
||||
AT91F_Undef_Handler: mov R0, #1
|
||||
b blinker
|
||||
|
||||
|
||||
AT91F_Default_FIQ_handler: b AT91F_Default_FIQ_handler
|
||||
|
||||
AT91F_Default_IRQ_handler: b AT91F_Default_IRQ_handler
|
||||
|
||||
AT91F_Spurious_handler: b AT91F_Spurious_handler
|
||||
.end
|
||||
@@ -0,0 +1,995 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 "handlers.h"
|
||||
/* objects */
|
||||
#include "device.h"
|
||||
#include "ai.h"
|
||||
#include "av.h"
|
||||
#include "bi.h"
|
||||
#include "bv.h"
|
||||
#include "wp.h"
|
||||
#include "dcc.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_VALUE, Binary_Value_Init, Binary_Value_Count,
|
||||
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance,
|
||||
Binary_Value_Object_Name, Binary_Value_Read_Property,
|
||||
Binary_Value_Write_Property, Binary_Value_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 BACNET_CHARACTER_STRING My_Object_Name;
|
||||
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_MAX_MASTER,
|
||||
PROP_MAX_INFO_FRAMES,
|
||||
PROP_DEVICE_ADDRESS_BINDING,
|
||||
PROP_DATABASE_REVISION,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Device_Properties_Optional[] = {
|
||||
PROP_DESCRIPTION,
|
||||
PROP_LOCATION,
|
||||
-1
|
||||
};
|
||||
|
||||
static const int Device_Properties_Proprietary[] = {
|
||||
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);
|
||||
}
|
||||
|
||||
static int Read_Property_Common(
|
||||
struct my_object_functions *pObject,
|
||||
BACNET_READ_PROPERTY_DATA * rpdata)
|
||||
{
|
||||
int apdu_len = BACNET_STATUS_ERROR;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
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:
|
||||
/* only array properties can have array options */
|
||||
if (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;
|
||||
} else {
|
||||
/* Device Object exception: requested instance
|
||||
may not match our instance if a wildcard */
|
||||
if (rpdata->object_type == OBJECT_DEVICE) {
|
||||
rpdata->object_instance = Object_Instance_Number;
|
||||
}
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], rpdata->object_type,
|
||||
rpdata->object_instance);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
/* only array properties can have array options */
|
||||
if (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;
|
||||
} else {
|
||||
characterstring_init_ansi(&char_string, "");
|
||||
if (pObject->Object_Name) {
|
||||
(void) pObject->Object_Name(rpdata->object_instance,
|
||||
&char_string);
|
||||
}
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0],
|
||||
&char_string);
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
/* only array properties can have array options */
|
||||
if (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;
|
||||
} else {
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0],
|
||||
rpdata->object_type);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (pObject->Object_Read_Property) {
|
||||
apdu_len = pObject->Object_Read_Property(rpdata);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
pObject = Device_Objects_Find_Functions(rpdata->object_type);
|
||||
if (pObject) {
|
||||
if (pObject->Object_Valid_Instance &&
|
||||
pObject->Object_Valid_Instance(rpdata->object_instance)) {
|
||||
apdu_len = Read_Property_Common(pObject, rpdata);
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
}
|
||||
} else {
|
||||
rpdata->error_class = ERROR_CLASS_OBJECT;
|
||||
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 : property_list_count(pPropertyList->Required.pList);
|
||||
|
||||
pPropertyList->Optional.count =
|
||||
pPropertyList->Optional.pList ==
|
||||
NULL ? 0 : property_list_count(pPropertyList->Optional.pList);
|
||||
|
||||
pPropertyList->Proprietary.count =
|
||||
pPropertyList->Proprietary.pList ==
|
||||
NULL ? 0 : 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;
|
||||
}
|
||||
|
||||
bool Device_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (object_instance == Object_Instance_Number) {
|
||||
status = characterstring_copy(object_name, &My_Object_Name);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Name(
|
||||
BACNET_CHARACTER_STRING * object_name)
|
||||
{
|
||||
bool status = false; /*return value */
|
||||
|
||||
if (!characterstring_same(&My_Object_Name, object_name)) {
|
||||
/* Make the change and update the database revision */
|
||||
status = characterstring_copy(&My_Object_Name, object_name);
|
||||
Device_Inc_Database_Revision();
|
||||
}
|
||||
|
||||
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);
|
||||
Object_Instance_Number = 12345;
|
||||
characterstring_init_ansi(&My_Object_Name, "ARM7 Demo Device");
|
||||
}
|
||||
|
||||
/* methods to manipulate the data */
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void)
|
||||
{
|
||||
return Object_Instance_Number;
|
||||
}
|
||||
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
bool status = true; /* return value */
|
||||
|
||||
if (object_id <= BACNET_MAX_INSTANCE) {
|
||||
Object_Instance_Number = object_id;
|
||||
} 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;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
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_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string, "BACnet Demo");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_LOCATION:
|
||||
characterstring_init_ansi(&char_string, "USA");
|
||||
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, "GNU Demo");
|
||||
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 9600:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0], RS485_Get_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;
|
||||
uint8_t encoding = 0;
|
||||
size_t length = 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_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))) {
|
||||
/* 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)) {
|
||||
dlmstp_set_max_master(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_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
length = characterstring_length(&value.type.Character_String);
|
||||
if (length < 1) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
} else if (length < characterstring_capacity(&My_Object_Name)) {
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
if (encoding < MAX_CHARACTER_STRING_ENCODING) {
|
||||
/* All the object names in a device must be unique. */
|
||||
if (Device_Valid_Object_Name(&value.type.
|
||||
Character_String, NULL, NULL)) {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code = ERROR_CODE_DUPLICATE_NAME;
|
||||
} else {
|
||||
Device_Set_Object_Name(&value.type.
|
||||
Character_String);
|
||||
status = true;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code =
|
||||
ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
wp_data->error_class = ERROR_CLASS_PROPERTY;
|
||||
wp_data->error_code =
|
||||
ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
} 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_Set_Baud_Rate(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_NUMBER_OF_APDU_RETRIES:
|
||||
case PROP_APDU_TIMEOUT:
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
case PROP_SYSTEM_STATUS:
|
||||
case PROP_LOCATION:
|
||||
case PROP_DESCRIPTION:
|
||||
case PROP_MODEL_NAME:
|
||||
case PROP_VENDOR_NAME:
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
case PROP_APPLICATION_SOFTWARE_VERSION:
|
||||
case PROP_LOCAL_TIME:
|
||||
case PROP_UTC_OFFSET:
|
||||
case PROP_LOCAL_DATE:
|
||||
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 PROP_ACTIVE_COV_SUBSCRIPTIONS:
|
||||
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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* ATMEL Microcontroller Software Support - ROUSSET - */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* The software is delivered "AS IS" without warranty or condition of any */
|
||||
/* kind, either express, implied or statutory. This includes without */
|
||||
/* limitation any warranty or condition with respect to merchantability or */
|
||||
/* fitness for any particular purpose, or against the infringements of */
|
||||
/* intellectual property rights of others. */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* File Name : Cstartup_SAM7.c */
|
||||
/* Object : Low level initializations written in C for IAR tools */
|
||||
/* 1.0 08/Sep/04 JPP : Creation */
|
||||
/* 1.10 10/Sep/04 JPP : Update AT91C_CKGR_PLLCOUNT filed */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
/* Include the board file description */
|
||||
#include "board.h"
|
||||
|
||||
/* The following functions must be write in ARM mode this function called directly */
|
||||
/* by exception vector */
|
||||
extern void AT91F_Spurious_handler(
|
||||
void);
|
||||
extern void AT91F_Default_IRQ_handler(
|
||||
void);
|
||||
extern void AT91F_Default_FIQ_handler(
|
||||
void);
|
||||
|
||||
/**---------------------------------------------------------------------------- */
|
||||
/** \fn AT91F_LowLevelInit */
|
||||
/** \brief This function performs very low level HW initialization */
|
||||
/** this function can be use a Stack, depending the compilation */
|
||||
/** optimization mode */
|
||||
/**---------------------------------------------------------------------------- */
|
||||
void LowLevelInit(
|
||||
void)
|
||||
{
|
||||
int i;
|
||||
AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
|
||||
/** Set Flash Wait sate */
|
||||
/* Single Cycle Access at Up to 30 MHz, or 40 */
|
||||
/* if MCK = 48054841 I have 50 Cycle for 1 usecond ( flied MC_FMR->FMCN */
|
||||
/* result: AT91C_MC_FMR = 0x00320100 (MC Flash Mode Register) */
|
||||
AT91C_BASE_MC->MC_FMR =
|
||||
(((AT91C_MC_FMCN) & (50 << 16)) | AT91C_MC_FWS_1FWS);
|
||||
|
||||
/** Watchdog Disable */
|
||||
/* result: AT91C_WDTC_WDMR = 0x00008000 (Watchdog Mode Register) */
|
||||
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
|
||||
|
||||
/** Set MCK at 48 054 841 */
|
||||
/* 1 Enabling the Main Oscillator: */
|
||||
/* SCK = 1/32768 = 30.51 uSecond */
|
||||
/* Start up time = 8 * 6 / SCK = 56 * 30.51 = 1,46484375 ms */
|
||||
/* result: AT91C_CKGR_MOR = 0x00000601 (Main Oscillator Register) */
|
||||
pPMC->PMC_MOR = ((AT91C_CKGR_OSCOUNT & (0x06 << 8)) | AT91C_CKGR_MOSCEN);
|
||||
|
||||
/* Wait the startup time */
|
||||
while (!(pPMC->PMC_SR & AT91C_PMC_MOSCS));
|
||||
|
||||
/* PMC Clock Generator PLL Register setup */
|
||||
/* */
|
||||
/* The following settings are used: DIV = 14 */
|
||||
/* MUL = 72 */
|
||||
/* PLLCOUNT = 10 */
|
||||
/* */
|
||||
/* Main Clock (MAINCK from crystal oscillator) = 18432000 hz (see AT91SAM7-EK schematic) */
|
||||
/* MAINCK / DIV = 18432000/14 = 1316571 hz */
|
||||
/* PLLCK = 1316571 * (MUL + 1) = 1316571 * (72 + 1) = 1316571 * 73 = 96109683 hz */
|
||||
/* */
|
||||
/* PLLCOUNT = number of slow clock cycles before the LOCK bit is set */
|
||||
/* in PMC_SR after CKGR_PLLR is written. */
|
||||
/* */
|
||||
/* PLLCOUNT = 10 */
|
||||
/* */
|
||||
/* OUT = 0 (not used) */
|
||||
/* result: AT91C_CKGR_PLLR = 0x00000000480A0E (PLL Register) */
|
||||
pPMC->PMC_PLLR =
|
||||
((AT91C_CKGR_DIV & 14) | (AT91C_CKGR_PLLCOUNT & (10 << 8)) |
|
||||
(AT91C_CKGR_MUL & (72 << 16)));
|
||||
|
||||
/* Wait the startup time (until PMC Status register LOCK bit is set) */
|
||||
while (!(pPMC->PMC_SR & AT91C_PMC_LOCK));
|
||||
|
||||
/* PMC Master Clock (MCK) Register setup */
|
||||
/* */
|
||||
/* CSS = 3 (PLLCK clock selected) */
|
||||
/* */
|
||||
/* PRES = 1 (MCK = PLLCK / 2) = 96109683/2 = 48054841 hz */
|
||||
/* */
|
||||
/* Note: Master Clock MCK = 48054841 hz (this is the CPU clock speed) */
|
||||
/* result: AT91C_PMC_MCKR = 0x00000007 (Master Clock Register) */
|
||||
pPMC->PMC_MCKR = AT91C_PMC_CSS_PLL_CLK | AT91C_PMC_PRES_CLK_2;
|
||||
|
||||
/* Set up the default interrupts handler vectors */
|
||||
AT91C_BASE_AIC->AIC_SVR[0] = (int) AT91F_Default_FIQ_handler;
|
||||
for (i = 1; i < 31; i++) {
|
||||
AT91C_BASE_AIC->AIC_SVR[i] = (int) AT91F_Default_IRQ_handler;
|
||||
}
|
||||
AT91C_BASE_AIC->AIC_SPU = (int) AT91F_Spurious_handler;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/* The following functions must be written in ARM mode */
|
||||
/* these functions are called directly by an exception vector */
|
||||
|
||||
/*------------------------------------------------------------------------------ */
|
||||
/* Internal functions */
|
||||
/*------------------------------------------------------------------------------ */
|
||||
/*------------------------------------------------------------------------------ */
|
||||
/* Default spurious interrupt handler. Infinite loop. */
|
||||
/*------------------------------------------------------------------------------ */
|
||||
void AT91F_Spurious_handler(
|
||||
void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------ */
|
||||
/* Default handler for fast interrupt requests. Infinite loop. */
|
||||
/*------------------------------------------------------------------------------ */
|
||||
void AT91F_Default_FIQ_handler(
|
||||
void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------ */
|
||||
/* Default handler for standard interrupt requests. Infinite loop. */
|
||||
/*------------------------------------------------------------------------------ */
|
||||
void AT91F_Default_IRQ_handler(
|
||||
void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/* ********************************************************************************************** */
|
||||
/* */
|
||||
/* File Name : isr.c */
|
||||
/* Title : interrupt enable/disable functions */
|
||||
/* */
|
||||
/* */
|
||||
/* This module provides the interface routines for setting up and */
|
||||
/* controlling the various interrupt modes present on the ARM processor. */
|
||||
/* Copyright 2004, R O SoftWare */
|
||||
/* No guarantees, warrantees, or promises, implied or otherwise. */
|
||||
/* May be used for hobby or commercial purposes provided copyright */
|
||||
/* notice remains intact. */
|
||||
/* */
|
||||
/* Note from Jim Lynch: */
|
||||
/* This module was developed by Bill Knight, RO Software and used with his permission. */
|
||||
/* Taken from the Yahoo LPC2000 User's Group - Files Section 'UT050418A.ZIP' */
|
||||
/* Specifically, the module armVIC.c with the include file references removed */
|
||||
/* ********************************************************************************************** */
|
||||
#include "isr.h"
|
||||
|
||||
#define IRQ_MASK 0x00000080
|
||||
#define FIQ_MASK 0x00000040
|
||||
#define INT_MASK (IRQ_MASK | FIQ_MASK)
|
||||
|
||||
static inline unsigned __get_cpsr(
|
||||
void)
|
||||
{
|
||||
unsigned long retval;
|
||||
asm volatile (" mrs %0, cpsr" : "=r" (retval) : /* no inputs */ );
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline void __set_cpsr(
|
||||
unsigned val)
|
||||
{
|
||||
asm volatile (
|
||||
" msr cpsr, %0": /* no outputs */ :"r" (val));
|
||||
}
|
||||
|
||||
unsigned disableIRQ(
|
||||
void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr(_cpsr | IRQ_MASK);
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned restoreIRQ(
|
||||
unsigned oldCPSR)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr((_cpsr & ~IRQ_MASK) | (oldCPSR & IRQ_MASK));
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned enableIRQ(
|
||||
void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr(_cpsr & ~IRQ_MASK);
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned disableFIQ(
|
||||
void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr(_cpsr | FIQ_MASK);
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned restoreFIQ(
|
||||
unsigned oldCPSR)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr((_cpsr & ~FIQ_MASK) | (oldCPSR & FIQ_MASK));
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned enableFIQ(
|
||||
void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr(_cpsr & ~FIQ_MASK);
|
||||
return _cpsr;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__ICCARM__)
|
||||
#include <intrinsics.h>
|
||||
#define isr_enable() __enable_interrupt()
|
||||
#define isr_disable() __disable_interrupt()
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#define isr_enable() enableIRQ();enableFIQ();
|
||||
#define isr_disable() disableFIQ();disableIRQ();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
unsigned disableIRQ(
|
||||
void);
|
||||
|
||||
unsigned restoreIRQ(
|
||||
unsigned oldCPSR);
|
||||
|
||||
unsigned enableIRQ(
|
||||
void);
|
||||
|
||||
unsigned disableFIQ(
|
||||
void);
|
||||
|
||||
unsigned restoreFIQ(
|
||||
unsigned oldCPSR);
|
||||
|
||||
unsigned enableFIQ(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,257 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
* Portions of the AT91SAM7S startup code were developed by James P Lynch.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
/* hardware specific */
|
||||
#include "board.h"
|
||||
#include "timer.h"
|
||||
/* standard libraries */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
/* BACnet */
|
||||
#include "rs485.h"
|
||||
#include "datalink.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "dcc.h"
|
||||
#include "iam.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "device.h"
|
||||
#include "dcc.h"
|
||||
#include "iam.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
/* ******************************************************* */
|
||||
/* FIXME: use header files? External References */
|
||||
/* ******************************************************* */
|
||||
extern void LowLevelInit(
|
||||
void);
|
||||
extern unsigned enableIRQ(
|
||||
void);
|
||||
extern unsigned enableFIQ(
|
||||
void);
|
||||
|
||||
/* used by crt.s file */
|
||||
unsigned FiqCount = 0;
|
||||
|
||||
static unsigned long LED_Timer_1 = 0;
|
||||
static unsigned long LED_Timer_2 = 0;
|
||||
static unsigned long LED_Timer_3 = 0;
|
||||
static unsigned long LED_Timer_4 = 1000;
|
||||
static unsigned long DCC_Timer = 1000;
|
||||
|
||||
static inline void millisecond_timer(
|
||||
void)
|
||||
{
|
||||
while (Timer_Milliseconds) {
|
||||
Timer_Milliseconds--;
|
||||
if (LED_Timer_1) {
|
||||
LED_Timer_1--;
|
||||
}
|
||||
if (LED_Timer_2) {
|
||||
LED_Timer_2--;
|
||||
}
|
||||
if (LED_Timer_3) {
|
||||
LED_Timer_3--;
|
||||
}
|
||||
if (LED_Timer_4) {
|
||||
LED_Timer_4--;
|
||||
}
|
||||
if (DCC_Timer) {
|
||||
DCC_Timer--;
|
||||
}
|
||||
}
|
||||
/* note: MS/TP silence timer is updated in ISR */
|
||||
}
|
||||
|
||||
static inline void init(
|
||||
void)
|
||||
{
|
||||
unsigned int pcsr;
|
||||
|
||||
/* Initialize the Parallel I/O Controller A Peripheral Clock */
|
||||
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
|
||||
pcsr = pPMC->PMC_PCSR;
|
||||
pPMC->PMC_PCER = pcsr | (1 << AT91C_ID_PIOA);
|
||||
|
||||
/* Set up the LEDs (PA0 - PA3) */
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
/* PIO Enable Register */
|
||||
/* allow PIO to control pins P0 - P3 and pin 19 */
|
||||
pPIO->PIO_PER = LED_MASK | SW1_MASK;
|
||||
/* PIO Output Enable Register */
|
||||
/* sets pins P0 - P3 to outputs */
|
||||
pPIO->PIO_OER = LED_MASK;
|
||||
/* PIO Set Output Data Register */
|
||||
/* turns off the four LEDs */
|
||||
pPIO->PIO_SODR = LED_MASK;
|
||||
|
||||
/* Select PA19 (pushbutton) to be FIQ function (Peripheral B) */
|
||||
pPIO->PIO_BSR = SW1_MASK;
|
||||
|
||||
/* Set up the AIC registers for FIQ (pushbutton SW1) */
|
||||
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC;
|
||||
/* Disable FIQ interrupt in */
|
||||
/* AIC Interrupt Disable Command Register */
|
||||
pAIC->AIC_IDCR = (1 << AT91C_ID_FIQ);
|
||||
/* Set the interrupt source type in */
|
||||
/* AIC Source Mode Register[0] */
|
||||
pAIC->AIC_SMR[AT91C_ID_FIQ] = (AT91C_AIC_SRCTYPE_INT_EDGE_TRIGGERED);
|
||||
/* Clear the FIQ interrupt in */
|
||||
/* AIC Interrupt Clear Command Register */
|
||||
pAIC->AIC_ICCR = (1 << AT91C_ID_FIQ);
|
||||
/* Remove disable FIQ interrupt in */
|
||||
/* AIC Interrupt Disable Command Register */
|
||||
pAIC->AIC_IDCR = (0 << AT91C_ID_FIQ);
|
||||
/* Enable the FIQ interrupt in */
|
||||
/* AIC Interrupt Enable Command Register */
|
||||
pAIC->AIC_IECR = (1 << AT91C_ID_FIQ);
|
||||
}
|
||||
|
||||
static inline void bacnet_init(
|
||||
void)
|
||||
{
|
||||
#if defined(BACDL_MSTP)
|
||||
uint8_t MAC_Address = 0x55;
|
||||
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
dlmstp_set_mac_address(MAC_Address);
|
||||
dlmstp_set_max_master(127);
|
||||
dlmstp_set_max_info_frames(1);
|
||||
dlmstp_init(NULL);
|
||||
#endif
|
||||
Device_Set_Object_Instance_Number(22222);
|
||||
/* initialize objects */
|
||||
Device_Init(NULL);
|
||||
/* set up our confirmed service unrecognized service handler - required! */
|
||||
apdu_set_unrecognized_service_handler_handler
|
||||
(handler_unrecognized_service);
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_HAS, handler_who_has);
|
||||
/* we need to handle who-is to support dynamic device binding */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||
/* Set the handlers for any confirmed services that we support. */
|
||||
/* We must implement read property - it's required! */
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
handler_read_property);
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROP_MULTIPLE,
|
||||
handler_read_property_multiple);
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
|
||||
handler_reinitialize_device);
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
handler_write_property);
|
||||
/* handle communication so we can shutup when asked */
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||
handler_device_communication_control);
|
||||
}
|
||||
|
||||
static uint8_t Receive_PDU[MAX_MPDU]; /* PDU data */
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
unsigned long IdleCount = 0; /* idle loop blink counter */
|
||||
bool LED1_Off_Enabled = true;
|
||||
bool LED2_Off_Enabled = true;
|
||||
bool LED3_Off_Enabled = true;
|
||||
uint16_t pdu_len = 0;
|
||||
BACNET_ADDRESS src; /* source address */
|
||||
/* Set up the LEDs (PA0 - PA3) */
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
|
||||
/* Initialize the Atmel AT91SAM7S256 */
|
||||
/* (watchdog, PLL clock, default interrupts, etc.) */
|
||||
LowLevelInit();
|
||||
TimerInit();
|
||||
init();
|
||||
bacnet_init();
|
||||
/* enable interrupts */
|
||||
isr_enable();
|
||||
/* broadcast an I-Am on startup */
|
||||
Send_I_Am(&Handler_Transmit_Buffer[0]);
|
||||
/* endless blink loop */
|
||||
while (1) {
|
||||
millisecond_timer();
|
||||
if (!DCC_Timer) {
|
||||
dcc_timer_seconds(1);
|
||||
DCC_Timer = 1000;
|
||||
}
|
||||
/* USART Tx turns the LED on, we turn it off */
|
||||
if (((pPIO->PIO_ODSR & LED1) == LED1) && (LED1_Off_Enabled)) {
|
||||
LED1_Off_Enabled = false;
|
||||
/* wait */
|
||||
LED_Timer_1 = 20;
|
||||
}
|
||||
if (!LED_Timer_1) {
|
||||
/* turn off */
|
||||
pPIO->PIO_SODR = LED1;
|
||||
LED1_Off_Enabled = true;
|
||||
}
|
||||
/* USART Rx turns the LED on, we turn it off */
|
||||
if (((pPIO->PIO_ODSR & LED2) == LED2) && (LED2_Off_Enabled)) {
|
||||
LED2_Off_Enabled = false;
|
||||
/* wait */
|
||||
LED_Timer_2 = 20;
|
||||
}
|
||||
if (!LED_Timer_2) {
|
||||
/* turn off */
|
||||
pPIO->PIO_SODR = LED2;
|
||||
LED2_Off_Enabled = true;
|
||||
}
|
||||
/* switch or NPDU turns on the LED, we turn it off */
|
||||
if (((pPIO->PIO_ODSR & LED3) == LED3) && (LED3_Off_Enabled)) {
|
||||
LED3_Off_Enabled = false;
|
||||
/* wait */
|
||||
LED_Timer_3 = 500;
|
||||
}
|
||||
if (!LED_Timer_3) {
|
||||
/* turn LED3 (DS3) off */
|
||||
pPIO->PIO_SODR = LED3;
|
||||
LED3_Off_Enabled = true;
|
||||
}
|
||||
/* Blink LED every second */
|
||||
if (!LED_Timer_4) {
|
||||
if ((pPIO->PIO_ODSR & LED4) == LED4) {
|
||||
/* turn on */
|
||||
pPIO->PIO_CODR = LED4;
|
||||
} else {
|
||||
/* turn off */
|
||||
pPIO->PIO_SODR = LED4;
|
||||
}
|
||||
/* wait */
|
||||
LED_Timer_4 = 1000;
|
||||
}
|
||||
/* count # of times through the idle loop */
|
||||
IdleCount++;
|
||||
/* BACnet handling */
|
||||
pdu_len =
|
||||
datalink_receive(&src, &Receive_PDU[0], sizeof(Receive_PDU), 0);
|
||||
if (pdu_len) {
|
||||
pPIO->PIO_CODR = LED3;
|
||||
npdu_handler(&src, &Receive_PDU[0], pdu_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
This port was done with a AT91SAM7S-EK which contained a
|
||||
AT91SAM7S64 processor. The compiler was the GNU ARM compiler
|
||||
and tools from Yagarto project.
|
||||
|
||||
The hardware was modified by severing the I-PA5 (RXD0),
|
||||
I-PA6 (TXD0), I-PA7 (RTS0) pads and rerouting those
|
||||
signals to a DS75176 RS-485 transceiver.
|
||||
PIN SIGNAL AT91SAM7S
|
||||
--- ------ ---------
|
||||
1 RO RXD0
|
||||
2 /RE RTS
|
||||
3 DE RTS
|
||||
4 DI TXD0
|
||||
5 GND GND
|
||||
6 DO n/c
|
||||
7 DO n/c
|
||||
8 +5V From EXT_VCC via 5V Regulator
|
||||
|
||||
The makefile allows you to build just the dlmstp or a simple
|
||||
server, both for programming into the flash memory of the processor.
|
||||
The dlmstp is the datalink layer for MS/TP over RS-485.
|
||||
|
||||
I used the makefile from the command line on Windows, and
|
||||
then used the SAM-BA to send the resulting .bin file to the
|
||||
board using a J-Link. To debug the code from flash, run the
|
||||
J-Link GDB Server and then:
|
||||
> arm-elf-gdb bacnet.elf
|
||||
|
||||
I got the crt.s, at91sam7s256.ld, blinker.c, init.c, isr.c, and
|
||||
timer.c from James P Lynch. I created the rs485.c based on the
|
||||
initialization sequence from serial.c by Keil Electronik. I
|
||||
got the at91sam7s256.h file from Atmel via the Keil website.
|
||||
I started with the makefile from James P Lynch, but it didn't work
|
||||
for me. I then used some ideas from FreeRTOS makefile, and
|
||||
created my own makefile from scratch.
|
||||
|
||||
Hopefully you find it useful!
|
||||
|
||||
Steve Karg
|
||||
@@ -0,0 +1,290 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
* RS-485 initialization on AT91SAM7S inspired by Keil Eletronik serial.c
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* The module handles sending data out the RS-485 port */
|
||||
/* and handles receiving data from the RS-485 port. */
|
||||
/* Customize this file for your specific hardware */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "timer.h"
|
||||
|
||||
/* This file has been customized for use with UART0
|
||||
on the AT91SAM7S-EK */
|
||||
#include "board.h"
|
||||
|
||||
/* UART */
|
||||
static volatile AT91S_USART *RS485_Interface = AT91C_BASE_US0;
|
||||
/* baud rate */
|
||||
static int RS485_Baud = 38400;
|
||||
|
||||
/* The minimum time after the end of the stop bit of the final octet of a */
|
||||
/* received frame before a node may enable its EIA-485 driver: 40 bit times. */
|
||||
/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */
|
||||
/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */
|
||||
/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */
|
||||
/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */
|
||||
/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */
|
||||
/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */
|
||||
/* 40 bits is 4 octets including a start and stop bit with each octet */
|
||||
#define Tturnaround (40UL)
|
||||
/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in
|
||||
* receive mode.
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
unsigned int pcsr;
|
||||
/* Enable the USART0 clock in the Power Management Controller */
|
||||
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
|
||||
pcsr = pPMC->PMC_PCSR;
|
||||
pPMC->PMC_PCER = pcsr | (1 << AT91C_ID_US0);
|
||||
|
||||
/* Disable and clear USART0 interrupt
|
||||
in AIC Interrupt Disable Command Register */
|
||||
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC;
|
||||
pAIC->AIC_IDCR = (1 << AT91C_ID_US0);
|
||||
pAIC->AIC_ICCR = (1 << AT91C_ID_US0);
|
||||
|
||||
/* enable the peripheral by disabling the pin in the PIO controller */
|
||||
*AT91C_PIOA_PDR = AT91C_PA5_RXD0 | AT91C_PA6_TXD0 | AT91C_PA7_RTS0;
|
||||
|
||||
RS485_Interface->US_CR = AT91C_US_RSTRX | /* Reset Receiver */
|
||||
AT91C_US_RSTTX | /* Reset Transmitter */
|
||||
AT91C_US_RSTSTA | /* Clear status register */
|
||||
AT91C_US_RXDIS | /* Receiver Disable */
|
||||
AT91C_US_TXDIS; /* Transmitter Disable */
|
||||
|
||||
RS485_Interface->US_MR = AT91C_US_USMODE_RS485 | /* RS-485 Mode - RTS auto assert */
|
||||
AT91C_US_CLKS_CLOCK | /* Clock = MCK */
|
||||
AT91C_US_CHRL_8_BITS | /* 8-bit Data */
|
||||
AT91C_US_PAR_NONE | /* No Parity */
|
||||
AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */
|
||||
|
||||
/* set the Time Guard to release RTS after x bit times */
|
||||
RS485_Interface->US_TTGR = 1;
|
||||
|
||||
/* Receiver Time-out disabled */
|
||||
RS485_Interface->US_RTOR = 0;
|
||||
|
||||
/* baud rate */
|
||||
RS485_Interface->US_BRGR = MCK / 16 / RS485_Baud;
|
||||
|
||||
RS485_Interface->US_CR = AT91C_US_RXEN | /* Receiver Enable */
|
||||
AT91C_US_TXEN; /* Transmitter Enable */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void RS485_Cleanup(
|
||||
void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Returns the baud rate that we are currently running at
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void)
|
||||
{
|
||||
return RS485_Baud;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Sets the baud rate for the chip USART
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud)
|
||||
{
|
||||
bool valid = true;
|
||||
|
||||
switch (baud) {
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 76800:
|
||||
case 115200:
|
||||
RS485_Baud = baud;
|
||||
RS485_Interface->US_BRGR = MCK / 16 / baud;
|
||||
/* FIXME: store the baud rate */
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Waits on the SilenceTimer for 40 bits.
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Turnaround_Delay(
|
||||
void)
|
||||
{
|
||||
uint16_t turnaround_time;
|
||||
|
||||
/* delay after reception before trasmitting - per MS/TP spec */
|
||||
/* wait a minimum 40 bit times since reception */
|
||||
/* at least 1 ms for errors: rounding, clock tick */
|
||||
turnaround_time = 2 + ((Tturnaround * 1000UL) / RS485_Baud);
|
||||
while (Timer_Silence() < turnaround_time) {
|
||||
/* do nothing - wait for timer to increment */
|
||||
};
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Enable or disable the transmitter
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: The Atmel ARM7 has an automatic enable/disable in RS485 mode.
|
||||
*****************************************************************************/
|
||||
void RS485_Transmitter_Enable(
|
||||
bool enable)
|
||||
{
|
||||
(void) enable;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Send some data and wait until it is sent
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Send_Data(
|
||||
uint8_t * buffer, /* data to send */
|
||||
uint16_t nbytes)
|
||||
{ /* number of bytes of data */
|
||||
/* LED on send */
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
/* LED ON */
|
||||
pPIO->PIO_CODR = LED1;
|
||||
/* send all the bytes */
|
||||
while (nbytes) {
|
||||
while (!(RS485_Interface->US_CSR & AT91C_US_TXRDY)) {
|
||||
/* do nothing - wait until Tx buffer is empty */
|
||||
}
|
||||
RS485_Interface->US_THR = *buffer;
|
||||
buffer++;
|
||||
nbytes--;
|
||||
}
|
||||
while (!(RS485_Interface->US_CSR & AT91C_US_TXRDY)) {
|
||||
/* do nothing - wait until Tx buffer is empty */
|
||||
}
|
||||
/* per MSTP spec */
|
||||
Timer_Silence_Reset();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Return true if a framing or overrun error is present
|
||||
* RETURN: true if error
|
||||
* ALGORITHM: none
|
||||
* NOTES: Clears any error flags.
|
||||
*****************************************************************************/
|
||||
bool RS485_ReceiveError(
|
||||
void)
|
||||
{
|
||||
bool ReceiveError = false;
|
||||
/* LED on send */
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
|
||||
/* check for data or error */
|
||||
if (RS485_Interface->US_CSR & (AT91C_US_OVRE | AT91C_US_FRAME)) {
|
||||
/* clear the error flag */
|
||||
RS485_Interface->US_CR = AT91C_US_RSTSTA;
|
||||
ReceiveError = true;
|
||||
/* LED ON */
|
||||
pPIO->PIO_CODR = LED2;
|
||||
}
|
||||
|
||||
return ReceiveError;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Return true if data is available
|
||||
* RETURN: true if data is available, with the data in the parameter set
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
bool RS485_DataAvailable(
|
||||
uint8_t * DataRegister)
|
||||
{
|
||||
bool DataAvailable = false;
|
||||
/* LED on send */
|
||||
volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
|
||||
if (RS485_Interface->US_CSR & AT91C_US_RXRDY) {
|
||||
/* data is available */
|
||||
if (DataRegister) {
|
||||
*DataRegister = RS485_Interface->US_RHR;
|
||||
}
|
||||
DataAvailable = true;
|
||||
/* LED ON */
|
||||
pPIO->PIO_CODR = LED2;
|
||||
}
|
||||
|
||||
return DataAvailable;
|
||||
}
|
||||
|
||||
#ifdef TEST_RS485
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
unsigned i = 0;
|
||||
uint8_t DataRegister;
|
||||
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
RS485_Initialize();
|
||||
/* receive task */
|
||||
for (;;) {
|
||||
if (RS485_ReceiveError()) {
|
||||
fprintf(stderr, "ERROR ");
|
||||
} else if (RS485_DataAvailable(&DataRegister)) {
|
||||
fprintf(stderr, "%02X ", DataRegister);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 RS485_H
|
||||
#define RS485_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
void RS485_Transmitter_Enable(
|
||||
bool enable);
|
||||
|
||||
void RS485_Send_Data(
|
||||
uint8_t * buffer, /* data to send */
|
||||
uint16_t nbytes); /* number of bytes of data */
|
||||
|
||||
bool RS485_ReceiveError(
|
||||
void);
|
||||
bool RS485_DataAvailable(
|
||||
uint8_t * data);
|
||||
|
||||
void RS485_Turnaround_Delay(
|
||||
void);
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,369 @@
|
||||
/* ***************************************************************************** */
|
||||
/* */
|
||||
/* Purpose: Set up the 16-bit Timer/Counter */
|
||||
/* */
|
||||
/* We will use Timer Channel 0 to develop a 1 msec interrupt. */
|
||||
/* */
|
||||
/* The AT91SAM7S-EK board has a 18,432,000 hz crystal oscillator. */
|
||||
/* */
|
||||
/* MAINCK = 18432000 hz */
|
||||
/* PLLCK = (MAINCK / DIV) * (MUL + 1) = 18432000/14 * (72 + 1) */
|
||||
/* PLLCLK = 1316571 * 73 = 96109683 hz */
|
||||
/* */
|
||||
/* MCK = PLLCLK / 2 = 96109683 / 2 = 48054841 hz */
|
||||
/* */
|
||||
/* TIMER_CLOCK5 = MCK / 1024 = 48054841 / 1024 = 46928 hz */
|
||||
/* */
|
||||
/* TIMER_CLOCK5 Period = 1 / 46928 = 21.309239686 microseconds */
|
||||
/* */
|
||||
/* A little algebra: .001 sec = count * 21.3092396896*10**-6 */
|
||||
/* count = .001 / 21.3092396896*10**-6 */
|
||||
/* count = 46.928 */
|
||||
/* */
|
||||
/* */
|
||||
/* Therefore: set Timer Channel 0 register RC to 46*milliseconds */
|
||||
/* turn on capture mode WAVE = 0 */
|
||||
/* enable the clock CLKEN = 1 */
|
||||
/* select TIMER_CLOCK5 TCCLKS = 100 */
|
||||
/* clock is NOT inverted CLKI = 0 */
|
||||
/* enable RC compare CPCTRG = 1 */
|
||||
/* enable RC compare interrupt CPCS = 1 */
|
||||
/* disable all the other timer 0 interrupts */
|
||||
/* */
|
||||
/* Author: James P Lynch May 12, 2007 */
|
||||
/* Modified by Steve Karg */
|
||||
/* Changed timer to 1ms. */
|
||||
/* Encapsulated the intialization */
|
||||
/* ***************************************************************************** */
|
||||
|
||||
|
||||
/**********************************************************
|
||||
Header files
|
||||
**********************************************************/
|
||||
#include <stdint.h>
|
||||
#include "board.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
/* global variable counts interrupts */
|
||||
volatile unsigned long Timer_Milliseconds;
|
||||
/* MS/TP Silence Timer */
|
||||
static volatile int SilenceTime;
|
||||
|
||||
static void Timer0_Setup(
|
||||
int milliseconds)
|
||||
{
|
||||
/* TC Block Control Register TC_BCR (read/write) */
|
||||
/* */
|
||||
/* |------------------------------------------------------------------|------| */
|
||||
/* | SYNC | */
|
||||
/* |------------------------------------------------------------------|------| */
|
||||
/* 31 1 0 */
|
||||
/* */
|
||||
/* SYNC = 0 (no effect) <===== take default */
|
||||
/* SYNC = 1 (generate software trigger for all 3 timer channels simultaneously) */
|
||||
/* */
|
||||
/* create a pointer to TC Global Register structure */
|
||||
AT91PS_TCB pTCB = AT91C_BASE_TCB;
|
||||
/* SYNC trigger not used */
|
||||
pTCB->TCB_BCR = 0;
|
||||
|
||||
/* TC Block Mode Register TC_BMR (read/write) */
|
||||
/* */
|
||||
/* |-------------------------------------|-----------|-----------|-----------| */
|
||||
/* | TC2XC2S TCXC1S TC0XC0S | */
|
||||
/* |-------------------------------------|-----------|-----------|-----------| */
|
||||
/* 31 5 4 3 2 1 0 */
|
||||
/* */
|
||||
/* TC0XC0S Select = 00 TCLK0 (PA4) */
|
||||
/* = 01 none <===== we select this one */
|
||||
/* = 10 TIOA1 (PA15) */
|
||||
/* = 11 TIOA2 (PA26) */
|
||||
/* */
|
||||
/* TCXC1S Select = 00 TCLK1 (PA28) */
|
||||
/* = 01 none <===== we select this one */
|
||||
/* = 10 TIOA0 (PA15) */
|
||||
/* = 11 TIOA2 (PA26) */
|
||||
/* */
|
||||
/* TC2XC2S Select = 00 TCLK2 (PA29) */
|
||||
/* = 01 none <===== we select this one */
|
||||
/* = 10 TIOA0 (PA00) */
|
||||
/* = 11 TIOA1 (PA26) */
|
||||
/* */
|
||||
/* external clocks not used */
|
||||
pTCB->TCB_BMR = 0x15;
|
||||
|
||||
|
||||
/* TC Channel Control Register TC_CCR (read/write) */
|
||||
/* */
|
||||
/* |----------------------------------|--------------|------------|-----------| */
|
||||
/* | SWTRG CLKDIS CLKENS | */
|
||||
/* |----------------------------------|--------------|------------|-----------| */
|
||||
/* 31 2 1 0 */
|
||||
/* */
|
||||
/* CLKEN = 0 no effect */
|
||||
/* CLKEN = 1 enables the clock <===== we select this one */
|
||||
/* */
|
||||
/* CLKDIS = 0 no effect <===== take default */
|
||||
/* CLKDIS = 1 disables the clock */
|
||||
/* */
|
||||
/* SWTRG = 0 no effect */
|
||||
/* SWTRG = 1 software trigger aserted counter reset and clock starts <===== we select this one */
|
||||
/* */
|
||||
/* create a pointer to channel 0 Register structure */
|
||||
AT91PS_TC pTC = AT91C_BASE_TC0;
|
||||
/* enable the clock and start it */
|
||||
pTC->TC_CCR = 0x5;
|
||||
|
||||
/* TC Channel Mode Register TC_CMR (read/write) */
|
||||
/* */
|
||||
/* |-----------------------------------|------------|---------------| */
|
||||
/* | LDRB LDRA | */
|
||||
/* |-----------------------------------|------------|---------------| */
|
||||
/* 31 19 18 17 16 */
|
||||
/* */
|
||||
/* |----------|---------|--------------|------------|---------------| */
|
||||
/* |WAVE = 0 CPCTRG ABETRG ETRGEDG | */
|
||||
/* |----------|---------|--------------|------------|---------------| */
|
||||
/* 15 14 13 11 10 9 8 */
|
||||
/* */
|
||||
/* |----------|---------|--------------|------------|---------------| */
|
||||
/* | LDBDIS LDBSTOP BURST CLKI TCCLKS | */
|
||||
/* |----------|---------|--------------|------------|---------------| */
|
||||
/* 7 6 5 4 3 2 0 */
|
||||
/* */
|
||||
/* CLOCK SELECTION */
|
||||
/* TCCLKS = 000 TIMER_CLOCK1 (MCK/2 = 24027420 hz) */
|
||||
/* 001 TIMER_CLOCK2 (MCK/8 = 6006855 hz) */
|
||||
/* 010 TIMER_CLOCK3 (MCK/32 = 1501713 hz) */
|
||||
/* 011 TIMER_CLOCK4 (MCK/128 = 375428 hz) */
|
||||
/* 100 TIMER_CLOCK5 (MCK/1024 = 46928 hz) <===== we select this one */
|
||||
/* 101 XC0 */
|
||||
/* 101 XC1 */
|
||||
/* 101 XC2 */
|
||||
/* */
|
||||
/* CLOCK INVERT */
|
||||
/* CLKI = 0 counter incremented on rising clock edge <===== we select this one */
|
||||
/* CLKI = 1 counter incremented on falling clock edge */
|
||||
/* */
|
||||
/* BURST SIGNAL SELECTION */
|
||||
/* BURST = 00 clock is not gated by any external system <===== take default */
|
||||
/* 01 XC0 is anded with the clock */
|
||||
/* 10 XC1 is anded with the clock */
|
||||
/* 11 XC2 is anded with the clock */
|
||||
/* */
|
||||
/* COUNTER CLOCK STOPPED WITH RB LOADING */
|
||||
/* LDBSTOP = 0 counter clock is not stopped when RB loading occurs <===== take default */
|
||||
/* = 1 counter clock is stopped when RB loading occur */
|
||||
/* */
|
||||
/* COUNTER CLOCK DISABLE WITH RB LOADING */
|
||||
/* LDBDIS = 0 counter clock is not disabled when RB loading occurs <===== take default */
|
||||
/* = 1 counter clock is disabled when RB loading occurs */
|
||||
/* */
|
||||
/* EXTERNAL TRIGGER EDGE SELECTION */
|
||||
/* ETRGEDG = 00 (none) <===== take default */
|
||||
/* 01 (rising edge) */
|
||||
/* 10 (falling edge) */
|
||||
/* 11 (each edge) */
|
||||
/* */
|
||||
/* TIOA OR TIOB EXTERNAL TRIGGER SELECTION */
|
||||
/* ABETRG = 0 (TIOA is used) <===== take default */
|
||||
/* 1 (TIOB is used) */
|
||||
/* */
|
||||
/* RC COMPARE TRIGGER ENABLE */
|
||||
/* CPCTRG = 0 (RC Compare has no effect on the counter and its clock) */
|
||||
/* 1 (RC Compare resets the counter and starts the clock) <===== we select this one */
|
||||
/* */
|
||||
/* WAVE */
|
||||
/* WAVE = 0 Capture Mode is enabled <===== we select this one */
|
||||
/* 1 Waveform Mode is enabled */
|
||||
/* */
|
||||
/* RA LOADING SELECTION */
|
||||
/* LDRA = 00 none) <===== take default */
|
||||
/* 01 (rising edge of TIOA) */
|
||||
/* 10 (falling edge of TIOA) */
|
||||
/* 11 (each edge of TIOA) */
|
||||
/* */
|
||||
/* RB LOADING SELECTION */
|
||||
/* LDRB = 00 (none) <===== take default */
|
||||
/* 01 (rising edge of TIOA) */
|
||||
/* 10 (falling edge of TIOA) */
|
||||
/* 11 (each edge of TIOA) */
|
||||
/* */
|
||||
/* TCCLKS = 1 (TIMER_CLOCK5) */
|
||||
/* CPCTRG = 1 (RC Compare resets the counter and restarts the clock) */
|
||||
/* WAVE = 0 (Capture mode enabled) */
|
||||
pTC->TC_CMR = 0x4004;
|
||||
|
||||
/* TC Register C TC_RC (read/write) Compare Register 16-bits */
|
||||
/* */
|
||||
/* |----------------------------------|----------------------------------------| */
|
||||
/* | not used RC | */
|
||||
/* |----------------------------------|----------------------------------------| */
|
||||
/* 31 16 15 0 */
|
||||
/* */
|
||||
/* Timer Calculation: What count gives 1 msec time-out? */
|
||||
/* */
|
||||
/* TIMER_CLOCK5 = MCK / 1024 = 48054841 / 1024 = 46928 hz */
|
||||
/* */
|
||||
/* TIMER_CLOCK5 Period = 1 / 46928 = 21.309239686 microseconds */
|
||||
/* */
|
||||
/* A little algebra: .001 sec = count * 21.3092396896*10**-6 */
|
||||
/* count = .001 / 21.3092396896*10**-6 */
|
||||
/* count = 46.928 */
|
||||
/* */
|
||||
/* STK: Even Simpler, let the compiler do the work: */
|
||||
/* */
|
||||
/* TIMER_CLOCK5 = (MCK / 1024) / 1000 */
|
||||
/* = 48054841 / 1024 / 1000 = 46.928 */
|
||||
pTC->TC_RC = ((MCK / 1024 / 1000) + 1) * milliseconds;
|
||||
|
||||
/* TC Interrupt Enable Register TC_IER (write-only) */
|
||||
/* */
|
||||
/* */
|
||||
/* |------------|-------|-------|-------|-------|--------|--------|--------|--------| */
|
||||
/* | ETRGS LDRBS LDRAS CPCS CPBS CPAS LOVRS COVFS | */
|
||||
/* |------------|-------|-------|-------|-------|--------|--------|--------|--------| */
|
||||
/* 31 8 7 6 5 4 3 2 1 0 */
|
||||
/* */
|
||||
/* COVFS = 0 no effect <===== take default */
|
||||
/* 1 enable counter overflow interrupt */
|
||||
/* */
|
||||
/* LOVRS = 0 no effect <===== take default */
|
||||
/* 1 enable load overrun interrupt */
|
||||
/* */
|
||||
/* CPAS = 0 no effect <===== take default */
|
||||
/* 1 enable RA compare interrupt */
|
||||
/* */
|
||||
/* CPBS = 0 no effect <===== take default */
|
||||
/* 1 enable RB compare interrupt */
|
||||
/* */
|
||||
/* CPCS = 0 no effect */
|
||||
/* 1 enable RC compare interrupt <===== we select this one */
|
||||
/* */
|
||||
/* LDRAS = 0 no effect <===== take default */
|
||||
/* 1 enable RA load interrupt */
|
||||
/* */
|
||||
/* LDRBS = 0 no effect <===== take default */
|
||||
/* 1 enable RB load interrupt */
|
||||
/* */
|
||||
/* ETRGS = 0 no effect <===== take default */
|
||||
/* 1 enable External Trigger interrupt */
|
||||
/* */
|
||||
/* enable RC compare interrupt */
|
||||
pTC->TC_IER = 0x10;
|
||||
|
||||
/* TC Interrupt Disable Register TC_IDR (write-only) */
|
||||
/* */
|
||||
/* */
|
||||
/* |------------|-------|-------|-------|-------|--------|--------|--------|--------| */
|
||||
/* | ETRGS LDRBS LDRAS CPCS CPBS CPAS LOVRS COVFS | */
|
||||
/* |------------|-------|-------|-------|-------|--------|--------|--------|--------| */
|
||||
/* 31 8 7 6 5 4 3 2 1 0 */
|
||||
/* */
|
||||
/* COVFS = 0 no effect */
|
||||
/* 1 disable counter overflow interrupt <===== we select this one */
|
||||
/* */
|
||||
/* LOVRS = 0 no effect */
|
||||
/* 1 disable load overrun interrupt <===== we select this one */
|
||||
/* */
|
||||
/* CPAS = 0 no effect */
|
||||
/* 1 disable RA compare interrupt <===== we select this one */
|
||||
/* */
|
||||
/* CPBS = 0 no effect */
|
||||
/* 1 disable RB compare interrupt <===== we select this one */
|
||||
/* */
|
||||
/* CPCS = 0 no effect <===== take default */
|
||||
/* 1 disable RC compare interrupt */
|
||||
/* */
|
||||
/* LDRAS = 0 no effect */
|
||||
/* 1 disable RA load interrupt <===== we select this one */
|
||||
/* */
|
||||
/* LDRBS = 0 no effect */
|
||||
/* 1 disable RB load interrupt <===== we select this one */
|
||||
/* */
|
||||
/* ETRGS = 0 no effect */
|
||||
/* 1 disable External Trigger interrupt <===== we select this one */
|
||||
/* */
|
||||
/* disable all except RC compare interrupt */
|
||||
pTC->TC_IDR = 0xEF;
|
||||
}
|
||||
|
||||
/* ***************************************************************************** */
|
||||
/* */
|
||||
/* Timer 0 Interrupt Service Routine */
|
||||
/* */
|
||||
/* Entered when Timer0 RC compare interrupt asserts */
|
||||
/* */
|
||||
/* Author: James P Lynch May 12, 2007 */
|
||||
/* Modified by Steve Karg */
|
||||
/* simplified and changed to a millisecond count-up timer */
|
||||
/* ***************************************************************************** */
|
||||
static void Timer0IrqHandler(
|
||||
void)
|
||||
{
|
||||
|
||||
volatile AT91PS_TC pTC = AT91C_BASE_TC0; /* pointer to timer channel 0 register structure */
|
||||
volatile unsigned int dummy; /* temporary */
|
||||
|
||||
/* read TC0 Status Register to clear interrupt */
|
||||
dummy = pTC->TC_SR;
|
||||
/* increment the tick count */
|
||||
Timer_Milliseconds++;
|
||||
if (SilenceTime < 60000)
|
||||
SilenceTime++;
|
||||
}
|
||||
|
||||
int Timer_Silence(
|
||||
void)
|
||||
{
|
||||
return SilenceTime;
|
||||
}
|
||||
|
||||
void Timer_Silence_Reset(
|
||||
void)
|
||||
{
|
||||
SilenceTime = 0;
|
||||
}
|
||||
|
||||
/* ***************************************************************************** */
|
||||
/* */
|
||||
/* Timer 0 Initialization */
|
||||
/* */
|
||||
/* From James P Lynch main.c example code */
|
||||
/* Modified by Steve Karg */
|
||||
/* Moved timer startup code from main */
|
||||
/* modified the peripheral clock init */
|
||||
/* ***************************************************************************** */
|
||||
void TimerInit(
|
||||
void)
|
||||
{
|
||||
unsigned int pcsr;
|
||||
/* enable the Timer0 peripheral clock */
|
||||
volatile AT91PS_PMC pPMC = AT91C_BASE_PMC;
|
||||
|
||||
pcsr = pPMC->PMC_PCSR;
|
||||
pPMC->PMC_PCER = pcsr | (1 << AT91C_ID_TC0);
|
||||
/* Set up the AIC registers for Timer 0 */
|
||||
volatile AT91PS_AIC pAIC = AT91C_BASE_AIC;
|
||||
/* Disable timer 0 interrupt */
|
||||
/* in AIC Interrupt Disable Command Register */
|
||||
pAIC->AIC_IDCR = (1 << AT91C_ID_TC0);
|
||||
/* Set the TC0 IRQ handler address in */
|
||||
/* AIC Source Vector Register[12] */
|
||||
pAIC->AIC_SVR[AT91C_ID_TC0] = (unsigned int) Timer0IrqHandler;
|
||||
/* Set the interrupt source type and priority */
|
||||
/* in AIC Source Mode Register[12] */
|
||||
pAIC->AIC_SMR[AT91C_ID_TC0] =
|
||||
(AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | 0x4);
|
||||
/* Clear the TC0 interrupt */
|
||||
/* in AIC Interrupt Clear Command Register */
|
||||
pAIC->AIC_ICCR = (1 << AT91C_ID_TC0);
|
||||
/* Remove disable timer 0 interrupt */
|
||||
/* in AIC Interrupt Disable Command Reg */
|
||||
pAIC->AIC_IDCR = (0 << AT91C_ID_TC0);
|
||||
/* Enable the TC0 interrupt */
|
||||
/* in AIC Interrupt Enable Command Register */
|
||||
pAIC->AIC_IECR = (1 << AT91C_ID_TC0);
|
||||
/* Setup timer0 to generate a 1 msec periodic interrupt */
|
||||
Timer0_Setup(1);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern volatile unsigned long Timer_Milliseconds;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void TimerInit(
|
||||
void);
|
||||
int Timer_Silence(
|
||||
void);
|
||||
void Timer_Silence_Reset(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Reference in New Issue
Block a user