adjust root folder
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
###############################################################################
|
||||
# Makefile for BACnet
|
||||
###############################################################################
|
||||
|
||||
## General Flags
|
||||
MCU = atmega328p
|
||||
AVRDUDE_MCU = m328
|
||||
TARGET = bacnet
|
||||
## Tools
|
||||
CC = avr-gcc
|
||||
AR = avr-ar
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
LINT = splint
|
||||
|
||||
# programmer id--check the avrdude for complete list
|
||||
# # of available opts. These should include stk500,
|
||||
# # avr910, avrisp, bsd, pony and more. Set this to
|
||||
# # one of the valid "-c PROGRAMMER-ID" values
|
||||
# # described in the avrdude info page.
|
||||
# #
|
||||
AVRDUDE_PROGRAMMERID = avrispmkII
|
||||
#
|
||||
# # port--serial or parallel port to which your
|
||||
# # hardware programmer is attached
|
||||
# #
|
||||
AVRDUDE_PORT = /dev/ttyUSB0
|
||||
|
||||
# Source locations
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_HANDLER = ../../demo/handler
|
||||
BACNET_OBJECT = ../../demo/object
|
||||
BACNET_DEMO = ../../demo
|
||||
ARDUINO_CORE = external/Arduino/core
|
||||
ARDUINO_ETHERNET = external/Arduino/Ethernet
|
||||
|
||||
# local files for this project
|
||||
CSRC = main.c \
|
||||
uart.c \
|
||||
apdu.c \
|
||||
h_rp.c \
|
||||
device.c \
|
||||
av.c \
|
||||
bv.c \
|
||||
h_whois.c \
|
||||
h_wp.c \
|
||||
bip.c \
|
||||
bip-init.c \
|
||||
bvlc-arduino.c
|
||||
|
||||
# common demo files needed
|
||||
DEMOSRC = $(BACNET_DEMO)/handler/txbuf.c \
|
||||
$(BACNET_DEMO)/handler/h_npdu.c \
|
||||
$(BACNET_DEMO)/handler/s_iam.c \
|
||||
$(BACNET_DEMO)/handler/noserv.c
|
||||
|
||||
# core BACnet stack files
|
||||
CORESRC = \
|
||||
$(BACNET_CORE)/crc.c \
|
||||
$(BACNET_CORE)/npdu.c \
|
||||
$(BACNET_CORE)/bacdcode.c \
|
||||
$(BACNET_CORE)/bacint.c \
|
||||
$(BACNET_CORE)/bacreal.c \
|
||||
$(BACNET_CORE)/bacstr.c \
|
||||
$(BACNET_CORE)/iam.c \
|
||||
$(BACNET_CORE)/rp.c \
|
||||
$(BACNET_CORE)/wp.c \
|
||||
$(BACNET_CORE)/whois.c \
|
||||
$(BACNET_CORE)/bacaddr.c \
|
||||
$(BACNET_CORE)/abort.c \
|
||||
$(BACNET_CORE)/reject.c \
|
||||
$(BACNET_CORE)/bacerror.c \
|
||||
$(BACNET_CORE)/bacapp.c \
|
||||
# $(BACNET_CORE)/ethernet.c
|
||||
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE)
|
||||
INCLUDES += -I$(BACNET_OBJECT)
|
||||
INCLUDES += -I$(BACNET_HANDLER)
|
||||
INCLUDES += -I$(ARDUINO_CORE)/include
|
||||
INCLUDES += -I$(ARDUINO_ETHERNET)/include
|
||||
|
||||
# Source to Object conversion
|
||||
COBJ = $(CSRC:.c=.o)
|
||||
DEMOOBJ = $(DEMOSRC:.c=.o)
|
||||
COREOBJ = $(CORESRC:.c=.o)
|
||||
|
||||
|
||||
LIBRARY = lib$(TARGET).a
|
||||
|
||||
## Options common to compile, link and assembly rules
|
||||
COMMON = -mmcu=$(MCU) -DF_CPU=16000000UL
|
||||
|
||||
#OPTIMIZE_FLAGS = -mcall-prologues
|
||||
#OPTIMIZE_FLAGS += -finline-functions-called-once -ffunction-sections -fdata-sections
|
||||
#OPTIMIZATION = -Os $(OPTIMIZE_FLAGS)
|
||||
OPTIMIZATION = -Os
|
||||
|
||||
#OPTIMIZATION = -O3 $(OPTIMIZE_FLAGS)
|
||||
|
||||
## Compile options common for all C compilation units.
|
||||
# BFLAGS = -DBACDL_MSTP
|
||||
#BFLAGS = -DBACDL_ETHERNET=1
|
||||
BFLAGS = -DBACDL_BIP=1
|
||||
BFLAGS += -DMAX_APDU=100
|
||||
BFLAGS += -DBIG_ENDIAN=0
|
||||
BFLAGS += -DMAX_TSM_TRANSACTIONS=0
|
||||
#BFLAGS += -DCRC_USE_TABLE
|
||||
BFLAGS += -DBACAPP_REAL
|
||||
BFLAGS += -DBACAPP_OBJECT_ID
|
||||
BFLAGS += -DBACAPP_UNSIGNED
|
||||
BFLAGS += -DBACAPP_ENUMERATED
|
||||
BFLAGS += -DBACAPP_CHARACTER_STRING
|
||||
BFLAGS += -DWRITE_PROPERTY
|
||||
BFLAGS += -DMAX_ANALOG_VALUES=4
|
||||
BFLAGS += -DMAX_BINARY_VALUES=4
|
||||
#BFLAGS += -DDEBUG
|
||||
CFLAGS = $(COMMON)
|
||||
# dead code removal
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
CFLAGS += -Wall -g2 -gstabs -std=gnu99 $(BFLAGS) $(OPTIMIZATION)
|
||||
CFLAGS += -MMD -MP -MT $(*F).o -MF dep/$(@F).d
|
||||
#CFLAGS += -Wall -gdwarf-2 $(BFLAGS) $(OPTIMIZATION) -fsigned-char
|
||||
#CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d
|
||||
|
||||
## Assembly specific flags
|
||||
ASMFLAGS = $(COMMON)
|
||||
ASMFLAGS += $(CFLAGS)
|
||||
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2
|
||||
|
||||
## Linker flags
|
||||
LDFLAGS = $(COMMON)
|
||||
#dead code removal
|
||||
LDFLAGS += -Wl,--gc-sections,-static
|
||||
LDFLAGS += -Wl,-Map=$(TARGET).map,-L.,-l$(TARGET)
|
||||
LDFLAGS += -Wl,-L$(ARDUINO_ETHERNET)/lib,-lArduinoEthernet
|
||||
LDFLAGS += -Wl,-L$(ARDUINO_CORE)/lib,-lArduinoUnoCore,-lm
|
||||
|
||||
## Intel Hex file production flags
|
||||
HEX_FLASH_FLAGS = -R .eeprom
|
||||
HEX_EEPROM_FLAGS = -j .eeprom
|
||||
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
|
||||
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings
|
||||
|
||||
## Objects that must be built in order to link
|
||||
OBJECTS = $(COBJ) $(DEMOOBJ)
|
||||
#OBJECTS = $(COBJ)
|
||||
|
||||
## Build
|
||||
TARGET_ELF=$(TARGET).elf
|
||||
|
||||
all: EthernetLib $(LIBRARY) $(TARGET_ELF) $(TARGET).hex $(TARGET).eep $(TARGET).lst \
|
||||
size Makefile
|
||||
|
||||
EthernetLib:
|
||||
$(MAKE) -s -C external/Arduino/Ethernet all
|
||||
|
||||
##Link
|
||||
$(TARGET_ELF): $(OBJECTS) $(LIBRARY)
|
||||
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||
|
||||
%.hex: $(TARGET_ELF)
|
||||
$(OBJCOPY) -O ihex $(HEX_FLASH_FLAGS) $< $@
|
||||
|
||||
%.eep: $(TARGET_ELF)
|
||||
-$(OBJCOPY) $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0
|
||||
|
||||
%.lst: $(TARGET_ELF)
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
lib: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(COREOBJ) Makefile
|
||||
$(AR) rcs $@ $(COREOBJ)
|
||||
$(OBJDUMP) --syms $@ > $(LIBRARY:.a=.lst)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@
|
||||
|
||||
.cpp.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.cpp -o $@
|
||||
|
||||
size: ${TARGET_ELF}
|
||||
@echo
|
||||
@${SIZE} -C --mcu=${MCU} ${TARGET_ELF}
|
||||
|
||||
lint:
|
||||
$(LINT) $(BFLAGS) $(CSRC)
|
||||
|
||||
install: $(TARGET_ELF)
|
||||
$(AVRDUDE) -c $(AVRDUDE_PROGRAMMERID) \
|
||||
-p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -e \
|
||||
-U flash:w:$(TARGET).hex
|
||||
|
||||
## Clean target
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -rf $(OBJECTS) $(TARGET_ELF) dep/*
|
||||
-rm -rf $(LIBRARY) $(COREOBJ)
|
||||
# -rm -rf $(LIBRARY) $(COREOBJ) $(LIBRARY:.a=.lst)
|
||||
-rm -rf $(TARGET).hex $(TARGET).eep $(TARGET).lst $(TARGET).map
|
||||
cd external/Arduino/Ethernet; make clean
|
||||
|
||||
## Other dependencies
|
||||
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)
|
||||
@@ -0,0 +1,144 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "apdu.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "handlers.h"
|
||||
|
||||
bool apdu_service_supported(BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (service_supported == SERVICE_SUPPORTED_READ_PROPERTY) {
|
||||
status = true;
|
||||
}
|
||||
if (service_supported == SERVICE_SUPPORTED_WHO_IS) {
|
||||
status = true;
|
||||
}
|
||||
#ifdef WRITE_PROPERTY
|
||||
if (service_supported == SERVICE_SUPPORTED_WRITE_PROPERTY) {
|
||||
status = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(uint8_t * apdu, /* APDU data */
|
||||
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request, service_request_len,
|
||||
src, &service_data);
|
||||
}
|
||||
#ifdef WRITE_PROPERTY
|
||||
else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 "wp.h"
|
||||
#include "av.h"
|
||||
|
||||
#if (MAX_ANALOG_VALUES > 10)
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
float AV_Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return object_instance;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "AV-"; /* okay for single thread */
|
||||
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
|
||||
return text_string;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index;
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0],
|
||||
AV_Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
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;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_REAL) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
AV_Present_Value[object_index] = value.type.Real;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalog_Value(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_VALUE;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
len =
|
||||
Analog_Value_Encode_Property_APDU(&apdu[0], instance,
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len =
|
||||
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_ANALOG_VALUE);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Analog Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAnalog_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
@@ -0,0 +1,75 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef AV_H
|
||||
#define AV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifndef MAX_ANALOG_VALUES
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
void Analog_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Analog_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Analog_Value_Count(void);
|
||||
uint32_t Analog_Value_Index_To_Instance(unsigned index);
|
||||
char *Analog_Value_Name(uint32_t object_instance);
|
||||
|
||||
int Analog_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Analog_Value_Present_Value_Set(uint32_t object_instance,
|
||||
float value,
|
||||
uint8_t priority);
|
||||
float Analog_Value_Present_Value(uint32_t object_instance);
|
||||
|
||||
void Analog_Value_Init(void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAnalog_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,166 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <stdio.h>
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
//#include "net.h"
|
||||
|
||||
/** @file linux/bip-init.c Initializes BACnet/IP interface (Linux). */
|
||||
|
||||
bool BIP_Debug = false;
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
a name that is a domain name
|
||||
returns 0 if not found, or
|
||||
an IP address in network byte order */
|
||||
long bip_getaddrbyname(const char *host_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* Eg, for Linux, ifname is eth0, ath0, arc0, and others.
|
||||
*/
|
||||
void bip_set_interface(char *ifname)
|
||||
{
|
||||
|
||||
uint8_t local_address[] = { 0, 0, 0, 0 };
|
||||
uint8_t broadcast_address[] = { 0, 0, 0, 0 };
|
||||
uint8_t netmask[] = { 0, 0, 0, 0 };
|
||||
uint8_t invertedNetmask[] = { 0, 0, 0, 0 };
|
||||
|
||||
getIPAddress_func(CW5100Class_new(), local_address);
|
||||
bip_set_addr(local_address);
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "Interface: %s\n", ifname);
|
||||
fprintf(stderr, "IP Address: %d.%d.%d.%d\n", local_address[0],
|
||||
local_address[1], local_address[2], local_address[3]);
|
||||
}
|
||||
|
||||
/* setup local broadcast address */
|
||||
getSubnetMask_func(CW5100Class_new(), netmask);
|
||||
for (int i = 0; i < 4; i++) { //FIXME: IPv4 ?
|
||||
invertedNetmask[i] = ~netmask[i];
|
||||
broadcast_address[i] = (local_address[i] | invertedNetmask[i]);
|
||||
}
|
||||
|
||||
bip_set_broadcast_addr(broadcast_address);
|
||||
if (BIP_Debug) {
|
||||
fprintf(stderr, "IP Broadcast Address: %d.%d.%d.%d\n",
|
||||
broadcast_address[0], broadcast_address[1], broadcast_address[2],
|
||||
broadcast_address[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize the BACnet/IP services at the given interface.
|
||||
* @ingroup DLBIP
|
||||
* -# Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IP data structures.
|
||||
* -# Opens a UDP socket
|
||||
* -# Configures the socket for sending and receiving
|
||||
* -# Configures the socket so it can send broadcasts
|
||||
* -# Binds the socket to the local IP address at the specified port for
|
||||
* BACnet/IP (by default, 0xBAC0 = 47808).
|
||||
*
|
||||
* @note For Linux, ifname is eth0, ath0, arc0, and others.
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* If NULL, the "eth0" interface is assigned.
|
||||
* @return True if the socket is successfully opened for BACnet/IP,
|
||||
* else False if the socket functions fail.
|
||||
*/
|
||||
bool bip_init(char *ifname)
|
||||
{
|
||||
uint8_t sock_fd = 0;
|
||||
bool isOpen = false;
|
||||
|
||||
if (ifname)
|
||||
bip_set_interface(ifname);
|
||||
else
|
||||
bip_set_interface("eth0");
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
for (sock_fd = 0; sock_fd < MAX_SOCK_NUM; sock_fd++) {
|
||||
if (readSnSR_func(CW5100Class_new(), sock_fd) == SnSR_CLOSED()) {
|
||||
socket_func(sock_fd, SnMR_UDP(), (uint16_t) 47808, 0);
|
||||
listen_func(sock_fd);
|
||||
isOpen = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOpen) {
|
||||
bip_set_socket(MAX_SOCK_NUM);
|
||||
return false;
|
||||
} else {
|
||||
bip_set_socket(sock_fd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Cleanup and close out the BACnet/IP services by closing the socket.
|
||||
* @ingroup DLBIP
|
||||
*/
|
||||
void bip_cleanup(void)
|
||||
{
|
||||
int sock_fd = 0;
|
||||
|
||||
if (bip_valid()) {
|
||||
sock_fd = bip_socket();
|
||||
close_func(sock_fd);
|
||||
}
|
||||
bip_set_socket(MAX_SOCK_NUM);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Get the netmask of the BACnet/IP's interface via an ioctl() call.
|
||||
* @param netmask [out] The netmask, in host order.
|
||||
* @return 0 on success, else the error from the ioctl() call.
|
||||
*/
|
||||
int bip_get_local_netmask(uint8_t * netmask)
|
||||
{
|
||||
getSubnetMask_func(CW5100Class_new(), netmask);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,413 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include <string.h>
|
||||
#include "bacdcode.h"
|
||||
#include "bacint.h"
|
||||
#include "bip.h"
|
||||
#include "bvlc-arduino.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
|
||||
|
||||
#if PRINT_ENABLED | DEBUG
|
||||
#include <stdio.h> /* for standard i/o, like printing */
|
||||
#endif
|
||||
|
||||
/** @file bip.c Configuration and Operations for BACnet/IP */
|
||||
|
||||
static uint8_t BIP_Socket = MAX_SOCK_NUM;
|
||||
/* port to use - stored in network byte order */
|
||||
static uint16_t BIP_Port = 0; /* this will force initialization in demos */
|
||||
/* IP Address - stored in network byte order */
|
||||
//static struct in_addr BIP_Address;
|
||||
static uint8_t BIP_Address[4] = { 0, 0, 0, 0 };
|
||||
/* Broadcast Address - stored in network byte order */
|
||||
//static struct in_addr BIP_Broadcast_Address;
|
||||
static uint8_t BIP_Broadcast_Address[4] = { 0, 0, 0, 0 };
|
||||
|
||||
/** Converter from uint8_t[4] type address to uint32_t
|
||||
*
|
||||
*/
|
||||
uint32_t convertBIP_Address2uint32(uint8_t * bip_address)
|
||||
{
|
||||
return (uint32_t) ((bip_address[0] * 2 ^ 24) + (bip_address[1] * 2 ^ 16) +
|
||||
(bip_address[2] * 2 ^ 8) + bip_address[3]);
|
||||
}
|
||||
|
||||
/** Convert from uint32_t IPv4 address to uint8_t[4] address
|
||||
*
|
||||
*/
|
||||
void convertUint32Address_2_uint8Address(uint32_t ip,
|
||||
uint8_t * address)
|
||||
{
|
||||
address[0] = (uint8_t) (ip >> 24);
|
||||
address[1] = (uint8_t) (ip >> 16);
|
||||
address[2] = (uint8_t) (ip >> 8);
|
||||
address[3] = (uint8_t) (ip >> 0);
|
||||
}
|
||||
|
||||
/** Setter for the BACnet/IP socket handle.
|
||||
*
|
||||
* @param sock_fd [in] Handle for the BACnet/IP socket.
|
||||
*/
|
||||
void bip_set_socket(uint8_t sock_fd)
|
||||
{
|
||||
BIP_Socket = sock_fd;
|
||||
}
|
||||
|
||||
/** Getter for the BACnet/IP socket handle.
|
||||
*
|
||||
* @return The handle to the BACnet/IP socket.
|
||||
*/
|
||||
uint8_t bip_socket(void)
|
||||
{
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
bool bip_valid(void)
|
||||
{
|
||||
return (BIP_Socket < MAX_SOCK_NUM);
|
||||
}
|
||||
|
||||
void bip_set_addr(uint8_t * net_address)
|
||||
{ /* in network byte order */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
BIP_Address[i] = net_address[i];
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint8_t *bip_get_addr(void)
|
||||
{
|
||||
return BIP_Address;
|
||||
}
|
||||
|
||||
void bip_set_broadcast_addr(uint8_t * net_address)
|
||||
{ /* in network byte order */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
BIP_Broadcast_Address[i] = net_address[i];
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint8_t *bip_get_broadcast_addr(void)
|
||||
{
|
||||
return BIP_Broadcast_Address;
|
||||
}
|
||||
|
||||
|
||||
void bip_set_port(uint16_t port)
|
||||
{ /* in network byte order */
|
||||
BIP_Port = port;
|
||||
}
|
||||
|
||||
/* returns network byte order */
|
||||
uint16_t bip_get_port(void)
|
||||
{
|
||||
return BIP_Port;
|
||||
}
|
||||
|
||||
static int bip_decode_bip_address(BACNET_ADDRESS * bac_addr,
|
||||
uint8_t * address, /* in network format */
|
||||
|
||||
uint16_t * port)
|
||||
{ /* in network format */
|
||||
int len = 0;
|
||||
|
||||
if (bac_addr) {
|
||||
memcpy(address, &bac_addr->mac[0], 4);
|
||||
memcpy(port, &bac_addr->mac[4], 2);
|
||||
len = 6;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Function to send a packet out the BACnet/IP socket (Annex J).
|
||||
* @ingroup DLBIP
|
||||
*
|
||||
* @param dest [in] Destination address (may encode an IP address and port #).
|
||||
* @param npdu_data [in] The NPDU header (Network) information (not used).
|
||||
* @param pdu [in] Buffer of data to be sent - may be null (why?).
|
||||
* @param pdu_len [in] Number of bytes in the pdu buffer.
|
||||
* @return Number of bytes sent on success, negative number on failure.
|
||||
*/
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
/* addr and port in host format */
|
||||
uint8_t address[] = { 0, 0, 0, 0 };
|
||||
uint16_t port = 0;
|
||||
|
||||
(void) npdu_data;
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (BIP_Socket < 0) {
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
if ((dest->net == BACNET_BROADCAST_NETWORK) || ((dest->net > 0) &&
|
||||
(dest->len == 0)) || (dest->mac_len == 0)) {
|
||||
/* broadcast */
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
address[i] = BIP_Broadcast_Address[i];
|
||||
port = BIP_Port;
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Send Broadcast NPDU to %d.%d.%d.%d:%d\n", address[0],
|
||||
address[1]
|
||||
, address[2], address[3], port);
|
||||
#endif
|
||||
} else if (dest->mac_len == 6) {
|
||||
bip_decode_bip_address(dest, address, &port);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Send Unicast NPDU to %d.%d.%d.%d:%d\n", address[0],
|
||||
address[1]
|
||||
, address[2], address[3], port);
|
||||
#endif
|
||||
} else {
|
||||
/* invalid address */
|
||||
return -1;
|
||||
}
|
||||
|
||||
mtu_len = 2;
|
||||
mtu_len +=
|
||||
encode_unsigned16(&mtu[mtu_len],
|
||||
(uint16_t) (pdu_len + 4 /*inclusive */ ));
|
||||
memcpy(&mtu[mtu_len], pdu, pdu_len);
|
||||
mtu_len += pdu_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "MTU size %d\n", mtu_len);
|
||||
#endif
|
||||
|
||||
/* Send the packet */
|
||||
bytes_sent =
|
||||
sendto_func(BIP_Socket, mtu, (uint16_t) mtu_len, address, port);
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/** Implementation of the receive() function for BACnet/IP; receives one
|
||||
* packet, verifies its BVLC header, and removes the BVLC header from
|
||||
* the PDU data before returning.
|
||||
*
|
||||
* @param src [out] Source of the packet - who should receive any response.
|
||||
* @param pdu [out] A buffer to hold the PDU portion of the received packet,
|
||||
* after the BVLC portion has been stripped off.
|
||||
* @param max_pdu [in] Size of the pdu[] buffer.
|
||||
* @param timeout [in] The number of milliseconds to wait for a packet.
|
||||
* @return The number of octets (remaining) in the PDU, or zero on failure.
|
||||
*/
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, /* source address */
|
||||
|
||||
uint8_t * pdu, /* PDU data */
|
||||
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
|
||||
unsigned timeout)
|
||||
{
|
||||
int received_bytes = 0;
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t src_addr[] = { 0, 0, 0, 0 };
|
||||
uint16_t src_port = 0;
|
||||
uint16_t i = 0;
|
||||
int function = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (BIP_Socket < 0)
|
||||
return 0;
|
||||
|
||||
if (getRXReceivedSize_func(CW5100Class_new(), BIP_Socket)) {
|
||||
memcpy(&src_addr, &src->mac[0], 4);
|
||||
memcpy(&src_port, &src->mac[4], 2);
|
||||
received_bytes =
|
||||
(int) recvfrom_func(BIP_Socket, &pdu[0], max_pdu, src_addr,
|
||||
&src_port);
|
||||
}
|
||||
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no problem, just no bytes */
|
||||
if (received_bytes == 0)
|
||||
return 0;
|
||||
|
||||
/* the signature of a BACnet/IP packet */
|
||||
if (pdu[0] != BVLL_TYPE_BACNET_IP)
|
||||
return 0;
|
||||
|
||||
if (bvlc_for_non_bbmd(src_addr, &src_port, pdu, received_bytes) > 0) {
|
||||
/* Handled, usually with a NACK. */
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "BIP: BVLC discarded!\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
function = bvlc_get_function_code(); /* aka, pdu[1] */
|
||||
if ((function == BVLC_ORIGINAL_UNICAST_NPDU) ||
|
||||
(function == BVLC_ORIGINAL_BROADCAST_NPDU)) {
|
||||
/* ignore messages from me */
|
||||
if ((convertBIP_Address2uint32(src_addr) ==
|
||||
convertBIP_Address2uint32(BIP_Address)) &&
|
||||
(src_port == BIP_Port)) {
|
||||
pdu_len = 0;
|
||||
#if 0
|
||||
fprintf(stderr, "BIP: src is me. Discarded!\n");
|
||||
#endif
|
||||
} else {
|
||||
/* data in src->mac[] is in network format */
|
||||
src->mac_len = 6;
|
||||
memcpy(&src->mac[0], &src_addr, 4);
|
||||
memcpy(&src->mac[4], &src_port, 2);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "BIP receive from %d.%d.%d.%d\n", src->mac[0],
|
||||
src->mac[1], src->mac[2], src->mac[3]);
|
||||
#endif
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void) decode_unsigned16(&pdu[2], &pdu_len);
|
||||
/* subtract off the BVLC header */
|
||||
pdu_len -= 4;
|
||||
if (pdu_len < max_pdu) {
|
||||
#if 0
|
||||
fprintf(stderr, "BIP: NPDU[%hu]:", pdu_len);
|
||||
#endif
|
||||
/* shift the buffer to return a valid PDU */
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
pdu[i] = pdu[4 + i];
|
||||
#if 0
|
||||
fprintf(stderr, "%02X ", pdu[i]);
|
||||
#endif
|
||||
}
|
||||
#if 0
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
}
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
else {
|
||||
pdu_len = 0;
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "BIP: PDU too large. Discarded!.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else if (function == BVLC_FORWARDED_NPDU) {
|
||||
memcpy(&src_addr, &pdu[4], 4);
|
||||
memcpy(&src_port, &pdu[8], 2);
|
||||
if ((convertBIP_Address2uint32(src_addr) ==
|
||||
convertBIP_Address2uint32(BIP_Address)) &&
|
||||
(src_port == BIP_Port)) {
|
||||
/* ignore messages from me */
|
||||
pdu_len = 0;
|
||||
} else {
|
||||
/* data in src->mac[] is in network format */
|
||||
src->mac_len = 6;
|
||||
memcpy(&src->mac[0], &src_addr, 4);
|
||||
memcpy(&src->mac[4], &src_port, 2);
|
||||
/* FIXME: check destination address */
|
||||
/* see if it is broadcast or for us */
|
||||
/* decode the length of the PDU - length is inclusive of BVLC */
|
||||
(void) decode_unsigned16(&pdu[2], &pdu_len);
|
||||
/* subtract off the BVLC header */
|
||||
pdu_len -= 10;
|
||||
if (pdu_len < max_pdu) {
|
||||
/* shift the buffer to return a valid PDU */
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
pdu[i] = pdu[4 + 6 + i];
|
||||
}
|
||||
} else {
|
||||
/* ignore packets that are too large */
|
||||
/* clients should check my max-apdu first */
|
||||
pdu_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (my_address) {
|
||||
my_address->mac_len = 6;
|
||||
memcpy(&my_address->mac[0], &BIP_Address, 4);
|
||||
memcpy(&my_address->mac[4], &BIP_Port, 2);
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
memcpy(&dest->mac[0], &BIP_Broadcast_Address, 4);
|
||||
memcpy(&dest->mac[4], &BIP_Port, 2);
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
#ifndef BIP_H
|
||||
#define BIP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
/* specific defines for BACnet/IP over Ethernet */
|
||||
#define MAX_HEADER (1 + 1 + 2)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
#define BVLL_TYPE_BACNET_IP (0x81)
|
||||
|
||||
extern bool BIP_Debug;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* note: define init, set_interface, and cleanup in your port */
|
||||
/* on Linux, ifname is eth0, ath0, arc0, and others.
|
||||
on Windows, ifname is the dotted ip address of the interface */
|
||||
bool bip_init(char *ifname);
|
||||
void bip_set_interface(char *ifname);
|
||||
void bip_cleanup(void);
|
||||
|
||||
/* Convert uint8_t IPv4 to uint32 */
|
||||
uint32_t convertBIP_Address2uint32(uint8_t * bip_address);
|
||||
void convertUint32Address_2_uint8Address(uint32_t ip,
|
||||
uint8_t * address);
|
||||
/* common BACnet/IP functions */
|
||||
void bip_set_socket(uint8_t sock_fd);
|
||||
uint8_t bip_socket(void);
|
||||
bool bip_valid(void);
|
||||
void bip_get_broadcast_address(BACNET_ADDRESS * dest); /* destination address */
|
||||
void bip_get_my_address(BACNET_ADDRESS * my_address);
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket */
|
||||
/* returns zero on success, non-zero on failure */
|
||||
int bip_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
/* receives a BACnet/IP packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
uint16_t bip_receive(BACNET_ADDRESS * src, /* source address */
|
||||
|
||||
uint8_t * pdu, /* PDU data */
|
||||
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
|
||||
unsigned timeout); /* milliseconds to wait for a packet */
|
||||
|
||||
/* use network byte order for setting */
|
||||
void bip_set_port(uint16_t port);
|
||||
/* returns network byte order */
|
||||
uint16_t bip_get_port(void);
|
||||
|
||||
/* use network byte order for setting */
|
||||
void bip_set_addr(uint8_t * net_address);
|
||||
/* returns network byte order */
|
||||
uint8_t *bip_get_addr(void);
|
||||
|
||||
/* use network byte order for setting */
|
||||
void bip_set_broadcast_addr(uint8_t * net_address);
|
||||
/* returns network byte order */
|
||||
uint8_t *bip_get_broadcast_addr(void);
|
||||
|
||||
/* gets an IP address by name, where name can be a
|
||||
string that is an IP address in dotted form, or
|
||||
a name that is a domain name
|
||||
returns 0 if not found, or
|
||||
an IP address in network byte order */
|
||||
long bip_getaddrbyname(const char *host_name);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/** @defgroup DLBIP BACnet/IP DataLink Network Layer
|
||||
* @ingroup DataLink
|
||||
* Implementation of the Network Layer using BACnet/IP as the transport, as
|
||||
* described in Annex J.
|
||||
* The functions described here fulfill the roles defined generically at the
|
||||
* DataLink level by serving as the implementation of the function templates.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,302 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* Binary Value Objects - customize for your use */
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "bv.h"
|
||||
|
||||
#if (MAX_BINARY_VALUES > 10)
|
||||
#error Modify the Binary_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static 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 */
|
||||
char *Binary_Value_Name(uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "BV-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
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:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value = Binary_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
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:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
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;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_PRESENT_VALUE:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
|
||||
if ((value.type.Enumerated == BINARY_ACTIVE) ||
|
||||
(value.type.Enumerated == BINARY_INACTIVE)) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index(wp_data->
|
||||
object_instance);
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] =
|
||||
(BACNET_BINARY_PV) value.type.Enumerated;
|
||||
/* 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. */
|
||||
if (Present_Value[0] == BINARY_ACTIVE) {
|
||||
// LED_GREEN_ON();
|
||||
} else {
|
||||
// LED_GREEN_OFF();
|
||||
}
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
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 {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBinary_Value(Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_VALUE;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
|
||||
len =
|
||||
Binary_Value_Encode_Property_APDU(&apdu[0], instance,
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len =
|
||||
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_BINARY_VALUE);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_VALUE
|
||||
int main(void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Binary_Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testBinary_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BINARY_VALUE */
|
||||
#endif /* TEST */
|
||||
@@ -0,0 +1,72 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef BV_H
|
||||
#define BV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifndef MAX_BINARY_VALUES
|
||||
#define MAX_BINARY_VALUES 10
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Binary_Value_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Binary_Value_Valid_Instance(uint32_t object_instance);
|
||||
unsigned Binary_Value_Count(void);
|
||||
uint32_t Binary_Value_Index_To_Instance(unsigned index);
|
||||
char *Binary_Value_Name(uint32_t object_instance);
|
||||
|
||||
void Binary_Value_Init(void);
|
||||
|
||||
int Binary_Value_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testBinary_Value(Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet Virtual Link Control for Wiznet on Arduino-Uno
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bvlc-arduino.h"
|
||||
#include "bip.h"
|
||||
#include "bacint.h"
|
||||
#include "socketWrapper.h"
|
||||
#include "w5100Wrapper.h"
|
||||
|
||||
/** result from a client request */
|
||||
BACNET_BVLC_RESULT BVLC_Result_Code = BVLC_RESULT_SUCCESSFUL_COMPLETION;
|
||||
/** The current BVLC Function Code being handled. */
|
||||
BACNET_BVLC_FUNCTION BVLC_Function_Code = BVLC_RESULT; /* A safe default */
|
||||
|
||||
static int bvlc_encode_bvlc_result(uint8_t * pdu,
|
||||
BACNET_BVLC_RESULT result_code)
|
||||
{
|
||||
if (pdu) {
|
||||
pdu[0] = BVLL_TYPE_BACNET_IP;
|
||||
pdu[1] = BVLC_RESULT;
|
||||
/* The 2-octet BVLC Length field is the length, in octets,
|
||||
of the entire BVLL message, including the two octets of the
|
||||
length field itself, most significant octet first. */
|
||||
encode_unsigned16(&pdu[2], 6);
|
||||
encode_unsigned16(&pdu[4], (uint16_t) result_code);
|
||||
}
|
||||
|
||||
return 6;
|
||||
}
|
||||
|
||||
static int bvlc_send_mpdu(uint8_t * dest_addr, /* the destination address */
|
||||
|
||||
uint16_t * dest_port, /* the destination port */
|
||||
|
||||
uint8_t * mtu, /* the data */
|
||||
|
||||
uint16_t mtu_len)
|
||||
{ /* amount of data to send */
|
||||
/* assumes that the driver has already been initialized */
|
||||
if (bip_valid()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sendto_func(bip_socket(), mtu, mtu_len, dest_addr, *dest_port);
|
||||
}
|
||||
|
||||
static void bvlc_send_result(uint8_t * dest_addr,
|
||||
uint16_t * dest_port, /* the destination address */
|
||||
|
||||
BACNET_BVLC_RESULT result_code)
|
||||
{
|
||||
uint8_t mtu[MAX_MPDU] = { 0 };
|
||||
uint16_t mtu_len = 0;
|
||||
|
||||
mtu_len = (uint16_t) bvlc_encode_bvlc_result(&mtu[0], result_code);
|
||||
bvlc_send_mpdu(dest_addr, dest_port, mtu, mtu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t bvlc_for_non_bbmd(uint8_t * addr,
|
||||
uint16_t * port,
|
||||
uint8_t * npdu,
|
||||
uint16_t received_bytes)
|
||||
{
|
||||
|
||||
uint16_t result_code = 0; /* aka, BVLC_RESULT_SUCCESSFUL_COMPLETION */
|
||||
BVLC_Function_Code = npdu[1]; /* The BVLC function */
|
||||
switch (BVLC_Function_Code) {
|
||||
case BVLC_RESULT:
|
||||
if (received_bytes >= 6) {
|
||||
/* This is the result of our foreign device registration */
|
||||
(void) decode_unsigned16(&npdu[4], &result_code);
|
||||
BVLC_Result_Code = (BACNET_BVLC_RESULT) result_code;
|
||||
fprintf(stderr, "BVLC: Result Code=%d\n", BVLC_Result_Code);
|
||||
/* But don't send any response */
|
||||
result_code = 0;
|
||||
}
|
||||
break;
|
||||
case BVLC_WRITE_BROADCAST_DISTRIBUTION_TABLE:
|
||||
result_code = BVLC_RESULT_WRITE_BROADCAST_DISTRIBUTION_TABLE_NAK;
|
||||
break;
|
||||
case BVLC_READ_BROADCAST_DIST_TABLE:
|
||||
result_code = BVLC_RESULT_READ_BROADCAST_DISTRIBUTION_TABLE_NAK;
|
||||
break;
|
||||
/* case BVLC_READ_BROADCAST_DIST_TABLE_ACK: */
|
||||
case BVLC_REGISTER_FOREIGN_DEVICE:
|
||||
result_code = BVLC_RESULT_REGISTER_FOREIGN_DEVICE_NAK;
|
||||
break;
|
||||
case BVLC_READ_FOREIGN_DEVICE_TABLE:
|
||||
result_code = BVLC_RESULT_READ_FOREIGN_DEVICE_TABLE_NAK;
|
||||
break;
|
||||
/* case BVLC_READ_FOREIGN_DEVICE_TABLE_ACK: */
|
||||
case BVLC_DELETE_FOREIGN_DEVICE_TABLE_ENTRY:
|
||||
result_code = BVLC_RESULT_DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK;
|
||||
break;
|
||||
case BVLC_DISTRIBUTE_BROADCAST_TO_NETWORK:
|
||||
result_code = BVLC_RESULT_DISTRIBUTE_BROADCAST_TO_NETWORK_NAK;
|
||||
break;
|
||||
/* case BVLC_FORWARDED_NPDU: */
|
||||
/* case BVLC_ORIGINAL_UNICAST_NPDU: */
|
||||
/* case BVLC_ORIGINAL_BROADCAST_NPDU: */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result_code > 0) {
|
||||
bvlc_send_result(addr, port, result_code);
|
||||
fprintf(stderr, "BVLC: NAK code=%d\n", result_code);
|
||||
}
|
||||
return result_code;
|
||||
}
|
||||
|
||||
BACNET_BVLC_FUNCTION bvlc_get_function_code(void)
|
||||
{
|
||||
return BVLC_Function_Code;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet Virtual Link Control for Wiznet on Arduino-Uno
|
||||
*/
|
||||
#ifndef BVLCARDUINO_H_
|
||||
#define BVLCARDUINO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bacenum.h"
|
||||
#include "bacdef.h"
|
||||
#include "npdu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
uint16_t bvlc_for_non_bbmd(uint8_t * addr,
|
||||
uint16_t * port,
|
||||
uint8_t * npdu,
|
||||
uint16_t received_bytes);
|
||||
|
||||
BACNET_BVLC_FUNCTION bvlc_get_function_code(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* BVLCARDUINO_H_ */
|
||||
@@ -0,0 +1,136 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*********************************************************************/
|
||||
#ifndef DATALINK_H
|
||||
#define DATALINK_H
|
||||
|
||||
#include "config.h"
|
||||
#include "bacdef.h"
|
||||
|
||||
#if defined(BACDL_ETHERNET)
|
||||
#include "ethernet.h"
|
||||
|
||||
#define datalink_init ethernet_init
|
||||
#define datalink_send_pdu ethernet_send_pdu
|
||||
#define datalink_receive ethernet_receive
|
||||
#define datalink_cleanup ethernet_cleanup
|
||||
#define datalink_get_broadcast_address ethernet_get_broadcast_address
|
||||
#define datalink_get_my_address ethernet_get_my_address
|
||||
|
||||
#elif defined(BACDL_ARCNET)
|
||||
#include "arcnet.h"
|
||||
|
||||
#define datalink_init arcnet_init
|
||||
#define datalink_send_pdu arcnet_send_pdu
|
||||
#define datalink_receive arcnet_receive
|
||||
#define datalink_cleanup arcnet_cleanup
|
||||
#define datalink_get_broadcast_address arcnet_get_broadcast_address
|
||||
#define datalink_get_my_address arcnet_get_my_address
|
||||
|
||||
#elif defined(BACDL_MSTP)
|
||||
#include "dlmstp.h"
|
||||
|
||||
#define datalink_init dlmstp_init
|
||||
#define datalink_send_pdu dlmstp_send_pdu
|
||||
#define datalink_receive dlmstp_receive
|
||||
#define datalink_cleanup dlmstp_cleanup
|
||||
#define datalink_get_broadcast_address dlmstp_get_broadcast_address
|
||||
#define datalink_get_my_address dlmstp_get_my_address
|
||||
|
||||
#elif defined(BACDL_BIP)
|
||||
#include "bip.h"
|
||||
#include "bvlc-arduino.h"
|
||||
|
||||
#define datalink_init bip_init
|
||||
//#if defined(BBMD_ENABLED) && BBMD_ENABLED
|
||||
//#define datalink_send_pdu bvlc_send_pdu
|
||||
//#define datalink_receive bvlc_receive
|
||||
//#else
|
||||
#define datalink_send_pdu bip_send_pdu
|
||||
#define datalink_receive bip_receive
|
||||
//#endif
|
||||
#define datalink_cleanup bip_cleanup
|
||||
#define datalink_get_broadcast_address bip_get_broadcast_address
|
||||
#ifdef BAC_ROUTING
|
||||
extern void routed_get_my_address(BACNET_ADDRESS * my_address);
|
||||
#define datalink_get_my_address routed_get_my_address
|
||||
#else
|
||||
#define datalink_get_my_address bip_get_my_address
|
||||
#endif
|
||||
|
||||
#else /* Ie, BACDL_ALL */
|
||||
#include "npdu.h"
|
||||
|
||||
#define MAX_HEADER (8)
|
||||
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
int datalink_send_pdu(BACNET_ADDRESS * dest,
|
||||
BACNET_NPDU_DATA * npdu_data,
|
||||
uint8_t * pdu,
|
||||
unsigned pdu_len);
|
||||
extern uint16_t datalink_receive(BACNET_ADDRESS * src,
|
||||
uint8_t * pdu,
|
||||
uint16_t max_pdu,
|
||||
unsigned timeout);
|
||||
extern void datalink_cleanup(void);
|
||||
extern void datalink_get_broadcast_address(BACNET_ADDRESS * dest);
|
||||
extern void datalink_get_my_address(BACNET_ADDRESS * my_address);
|
||||
extern void datalink_set_interface(char *ifname);
|
||||
extern void datalink_set(char *datalink_string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
/** @defgroup DataLink The BACnet Network (DataLink) Layer
|
||||
* <b>6 THE NETWORK LAYER </b><br>
|
||||
* The purpose of the BACnet network layer is to provide the means by which
|
||||
* messages can be relayed from one BACnet network to another, regardless of
|
||||
* the BACnet data link technology in use on that network. Whereas the data
|
||||
* link layer provides the capability to address messages to a single device
|
||||
* or broadcast them to all devices on the local network, the network layer
|
||||
* allows messages to be directed to a single remote device, broadcast on a
|
||||
* remote network, or broadcast globally to all devices on all networks.
|
||||
* A BACnet Device is uniquely located by a network number and a MAC address.
|
||||
*
|
||||
* Each client or server application must define exactly one of these
|
||||
* DataLink settings, which will control which parts of the code will be built:
|
||||
* - BACDL_ETHERNET -- for Clause 7 ISO 8802-3 ("Ethernet") LAN
|
||||
* - BACDL_ARCNET -- for Clause 8 ARCNET LAN
|
||||
* - BACDL_MSTP -- for Clause 9 MASTER-SLAVE/TOKEN PASSING (MS/TP) LAN
|
||||
* - BACDL_BIP -- for ANNEX J - BACnet/IP
|
||||
* - BACDL_ALL -- Unspecified for the build, so the transport can be
|
||||
* chosen at runtime from among these choices.
|
||||
* - Clause 10 POINT-TO-POINT (PTP) and Clause 11 EIA/CEA-709.1 ("LonTalk") LAN
|
||||
* are not currently supported by this project.
|
||||
*//** @defgroup DLTemplates DataLink Template Functions
|
||||
* @ingroup DataLink
|
||||
* Most of the functions in this group are function templates which are assigned
|
||||
* to a specific DataLink network layer implementation either at compile time or
|
||||
* at runtime.
|
||||
*/
|
||||
#endif
|
||||
@@ -0,0 +1,460 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacstr.h"
|
||||
#include "bacenum.h"
|
||||
#include "apdu.h"
|
||||
#include "dcc.h"
|
||||
#include "dlmstp.h"
|
||||
#include "version.h"
|
||||
|
||||
/* objects */
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "bv.h"
|
||||
#include "wp.h"
|
||||
|
||||
/* note: you really only need to define variables for
|
||||
properties that are writable or that may change.
|
||||
The properties that are constant can be hard coded
|
||||
into the read-property encoding. */
|
||||
static uint32_t Object_Instance_Number = 260001;
|
||||
static char Object_Name[20] = "My Device";
|
||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||
|
||||
void Device_Init(void)
|
||||
{
|
||||
/* Reinitialize_State = BACNET_REINIT_IDLE; */
|
||||
/* dcc_set_status_duration(COMMUNICATION_ENABLE, 0); */
|
||||
/* FIXME: Get the data from the eeprom */
|
||||
/* I2C_Read_Block(EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&Object_Instance_Number,
|
||||
sizeof(Object_Instance_Number),
|
||||
EEPROM_BACNET_ID_ADDR); */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* FIXME: Write the data to the eeprom */
|
||||
/* I2C_Write_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&Object_Instance_Number,
|
||||
sizeof(Object_Instance_Number),
|
||||
EEPROM_BACNET_ID_ADDR); */
|
||||
} else
|
||||
status = false;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id)
|
||||
{
|
||||
/* BACnet allows for a wildcard instance number */
|
||||
return ((Object_Instance_Number == object_id) ||
|
||||
(object_id == BACNET_MAX_INSTANCE));
|
||||
}
|
||||
|
||||
uint16_t Device_Vendor_Identifier(void)
|
||||
{
|
||||
return BACNET_VENDOR_ID;
|
||||
}
|
||||
|
||||
unsigned Device_Object_List_Count(void)
|
||||
{
|
||||
unsigned count = 1; /* at least 1 for device object */
|
||||
|
||||
/* FIXME: add objects as needed */
|
||||
count += Analog_Value_Count();
|
||||
count += Binary_Value_Count();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool Device_Object_List_Identifier(uint32_t array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance)
|
||||
{
|
||||
bool status = false;
|
||||
uint32_t object_index = 0;
|
||||
uint32_t object_count = 0;
|
||||
|
||||
/* device object */
|
||||
if (array_index == 1) {
|
||||
*object_type = OBJECT_DEVICE;
|
||||
*instance = Object_Instance_Number;
|
||||
status = true;
|
||||
}
|
||||
/* normalize the index since
|
||||
we know it is not the previous objects */
|
||||
/* array index starts at 1 */
|
||||
object_index = array_index - 1;
|
||||
/* 1 for the device object */
|
||||
object_count = 1;
|
||||
/* FIXME: add objects as needed */
|
||||
/* analog value objects */
|
||||
if (!status) {
|
||||
/* array index starts at 1, and 1 for the device object */
|
||||
object_index -= object_count;
|
||||
object_count = Analog_Value_Count();
|
||||
if (object_index < object_count) {
|
||||
*object_type = OBJECT_ANALOG_VALUE;
|
||||
*instance = Analog_Value_Index_To_Instance(object_index);
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
/* binary value objects */
|
||||
if (!status) {
|
||||
object_index -= object_count;
|
||||
object_count = Binary_Value_Count();
|
||||
/* is it a valid index for this object? */
|
||||
if (object_index < object_count) {
|
||||
*object_type = OBJECT_BINARY_VALUE;
|
||||
*instance = Binary_Value_Index_To_Instance(object_index);
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return the length of the apdu encoded or -1 for error */
|
||||
int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint32_t i = 0;
|
||||
int object_type = 0;
|
||||
uint32_t instance = 0;
|
||||
uint32_t count = 0;
|
||||
|
||||
//object_instance = object_instance;
|
||||
/* FIXME: change the hardcoded names to suit your application */
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string, Object_Name);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], System_Status);
|
||||
break;
|
||||
case PROP_VENDOR_NAME:
|
||||
characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Vendor_Identifier());
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
characterstring_init_ansi(&char_string, "GNU Demo");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
characterstring_init_ansi(&char_string, BACNET_VERSION_TEXT);
|
||||
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);
|
||||
/* must have the bit string as big as it can be */
|
||||
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);
|
||||
}
|
||||
/* FIXME: indicate the objects that YOU support */
|
||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
/* Array element zero is the number of objects in the list */
|
||||
if (array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. Note that more than likely you will have */
|
||||
/* to return an error if the number of encoded objects exceeds */
|
||||
/* your maximum APDU size. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
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 */
|
||||
*error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Device_Object_List_Identifier(array_index, &object_type,
|
||||
&instance))
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = 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], SEGMENTATION_NONE);
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 60000);
|
||||
break;
|
||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 0);
|
||||
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], 0);
|
||||
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;
|
||||
// case 512:
|
||||
// apdu_len = encode_application_unsigned(&apdu[0], stack_size());
|
||||
// break;
|
||||
// case 513:
|
||||
// apdu_len = encode_application_unsigned(&apdu[0], stack_unused());
|
||||
// break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (property != PROP_OBJECT_LIST) &&
|
||||
(array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
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;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Device_Set_Object_Instance_Number(value.type.Object_Id.
|
||||
instance))) {
|
||||
/* we could send an I-Am broadcast to let the world know */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
// case PROP_MAX_INFO_FRAMES:
|
||||
// if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
// if (value.type.Unsigned_Int <= 255) {
|
||||
// dlmstp_set_max_info_frames(value.type.Unsigned_Int);
|
||||
// status = true;
|
||||
// } else {
|
||||
// *error_class = ERROR_CLASS_PROPERTY;
|
||||
// *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
// }
|
||||
// } else {
|
||||
// *error_class = ERROR_CLASS_PROPERTY;
|
||||
// *error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
// }
|
||||
// break;
|
||||
// case PROP_MAX_MASTER:
|
||||
// if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
// if ((value.type.Unsigned_Int > 0) &&
|
||||
// (value.type.Unsigned_Int <= 127)) {
|
||||
// dlmstp_set_max_master(value.type.Unsigned_Int);
|
||||
// status = true;
|
||||
// } else {
|
||||
// *error_class = ERROR_CLASS_PROPERTY;
|
||||
// *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
// }
|
||||
// } else {
|
||||
// *error_class = ERROR_CLASS_PROPERTY;
|
||||
// *error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
// }
|
||||
// break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (characterstring_ansi_copy(&Object_Name[0],
|
||||
sizeof(Object_Name),
|
||||
&value.type.Character_String)) {
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
// case 9600:
|
||||
// if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
// if (value.type.Unsigned_Int > 115200) {
|
||||
// RS485_Set_Baud_Rate(value.type.Unsigned_Int);
|
||||
// status = true;
|
||||
// } else {
|
||||
// *error_class = ERROR_CLASS_PROPERTY;
|
||||
// *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
// }
|
||||
// } else {
|
||||
// *error_class = ERROR_CLASS_PROPERTY;
|
||||
// *error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
// }
|
||||
// break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DEVICE_H
|
||||
#define DEVICE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacenum.h"
|
||||
#include "wp.h"
|
||||
#include "readrange.h"
|
||||
|
||||
typedef unsigned (*object_count_function) (void);
|
||||
typedef uint32_t(*object_index_to_instance_function)
|
||||
(unsigned index);
|
||||
typedef char *(*object_name_function)
|
||||
(uint32_t object_instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Device_Object_Function_Set(BACNET_OBJECT_TYPE object_type,
|
||||
object_count_function count_function,
|
||||
object_index_to_instance_function index_function,
|
||||
object_name_function name_function);
|
||||
|
||||
void Device_Init(void);
|
||||
|
||||
void Device_Property_Lists(const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
|
||||
uint32_t Device_Object_Instance_Number(void);
|
||||
bool Device_Set_Object_Instance_Number(uint32_t object_id);
|
||||
bool Device_Valid_Object_Instance_Number(uint32_t object_id);
|
||||
unsigned Device_Object_List_Count(void);
|
||||
bool Device_Object_List_Identifier(uint32_t array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance);
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(void);
|
||||
void Device_Set_System_Status(BACNET_DEVICE_STATUS status);
|
||||
|
||||
const char *Device_Vendor_Name(void);
|
||||
|
||||
uint16_t Device_Vendor_Identifier(void);
|
||||
|
||||
const char *Device_Model_Name(void);
|
||||
bool Device_Set_Model_Name(const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Firmware_Revision(void);
|
||||
|
||||
const char *Device_Application_Software_Version(void);
|
||||
bool Device_Set_Application_Software_Version(const char *name,
|
||||
size_t length);
|
||||
|
||||
bool Device_Set_Object_Name(const char *name,
|
||||
size_t length);
|
||||
const char *Device_Object_Name(void);
|
||||
|
||||
const char *Device_Description(void);
|
||||
bool Device_Set_Description(const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Location(void);
|
||||
bool Device_Set_Location(const char *name,
|
||||
size_t length);
|
||||
|
||||
/* some stack-centric constant values - no set methods */
|
||||
uint8_t Device_Protocol_Version(void);
|
||||
uint8_t Device_Protocol_Revision(void);
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(void);
|
||||
|
||||
uint8_t Device_Database_Revision(void);
|
||||
void Device_Set_Database_Revision(uint8_t revision);
|
||||
|
||||
bool Device_Valid_Object_Name(const char *object_name,
|
||||
int *object_type,
|
||||
uint32_t * object_instance);
|
||||
char *Device_Valid_Object_Id(int object_type,
|
||||
uint32_t object_instance);
|
||||
|
||||
int Device_Encode_Property_APDU(uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool DeviceGetRRInfo(uint32_t Object, /* Which particular object - obviously not important for device object */
|
||||
|
||||
BACNET_PROPERTY_ID Property, /* Which property */
|
||||
|
||||
RR_PROP_INFO * pInfo, /* Where to put the information */
|
||||
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,118 @@
|
||||
###############################################################################
|
||||
# Makefile for BACnet
|
||||
###############################################################################
|
||||
|
||||
## General Flags
|
||||
MCU = atmega328p
|
||||
AVRDUDE_MCU = m328
|
||||
TARGET = ArduinoEthernet
|
||||
## Tools
|
||||
CC = avr-gcc
|
||||
AR = avr-ar
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
LINT = splint
|
||||
|
||||
# programmer id--check the avrdude for complete list
|
||||
# # of available opts. These should include stk500,
|
||||
# # avr910, avrisp, bsd, pony and more. Set this to
|
||||
# # one of the valid "-c PROGRAMMER-ID" values
|
||||
# # described in the avrdude info page.
|
||||
# #
|
||||
AVRDUDE_PROGRAMMERID = avrispmkII
|
||||
#
|
||||
# # port--serial or parallel port to which your
|
||||
# # hardware programmer is attached
|
||||
# #
|
||||
AVRDUDE_PORT = /dev/ttyUSB0
|
||||
|
||||
# local files for this project
|
||||
#CSRC = main.c
|
||||
|
||||
ARDUINOSRC = \
|
||||
src/socket.cpp \
|
||||
src/w5100.cpp \
|
||||
src/SPI.cpp \
|
||||
src/w5100Wrapper.cpp \
|
||||
src/socketWrapper.cpp
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -Iinclude
|
||||
INCLUDES += -I../core/include
|
||||
|
||||
LIBRARY = lib$(TARGET).a
|
||||
|
||||
## Options common to compile, link and assembly rules
|
||||
COMMON = -mmcu=$(MCU)
|
||||
|
||||
OPTIMIZE_FLAGS = -mcall-prologues
|
||||
#OPTIMIZE_FLAGS += -finline-functions
|
||||
OPTIMIZE_FLAGS += -finline-functions-called-once
|
||||
#OPTIMIZATION = -O0
|
||||
#OPTIMIZATION = -Os
|
||||
OPTIMIZATION = -Os $(OPTIMIZE_FLAGS)
|
||||
#OPTIMIZATION = -O3 $(OPTIMIZE_FLAGS)
|
||||
|
||||
## Compile options common for all C compilation units.
|
||||
CFLAGS = $(COMMON)
|
||||
# dead code removal
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
CFLAGS += -Wall -gdwarf-2 $(OPTIMIZATION) -fsigned-char
|
||||
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d
|
||||
|
||||
## Assembly specific flags
|
||||
ASMFLAGS = $(COMMON)
|
||||
ASMFLAGS += $(CFLAGS)
|
||||
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2
|
||||
|
||||
## Linker flags
|
||||
LDFLAGS = $(COMMON)
|
||||
#dead code removal
|
||||
#LDFLAGS += -Wl,-nostartfiles,-nostdlib
|
||||
LDFLAGS += -Wl,--gc-sections,-static
|
||||
LDFLAGS += -Wl,-Map=$(TARGET).map,-L.,-l$(TARGET)
|
||||
#LDFLAGS += -Wl,-Map=$(TARGET).map
|
||||
LDFLAGS += -L../core/lib,-lArduinoUnoCore
|
||||
|
||||
## Intel Hex file production flags
|
||||
HEX_FLASH_FLAGS = -R .eeprom
|
||||
HEX_EEPROM_FLAGS = -j .eeprom
|
||||
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
|
||||
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings
|
||||
|
||||
## Objects that must be built in order to link
|
||||
OBJS := ${SRCS:.cpp=.o}
|
||||
|
||||
all: $(LIBRARY) size Makefile
|
||||
|
||||
default: all
|
||||
|
||||
lib: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(OBJS) Makefile
|
||||
$(AR) rcs lib/$@ $(OBJS)
|
||||
$(OBJDUMP) --syms lib/$@ > lib/$(LIBRARY:.a=.lst)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@
|
||||
|
||||
.cpp.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.cpp -o $@
|
||||
|
||||
size: ${TARGET_ELF}
|
||||
@echo
|
||||
@${SIZE} ${TARGET_ELF}
|
||||
|
||||
lint:
|
||||
$(LINT) $(BFLAGS) $(CSRC)
|
||||
|
||||
## Clean target
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -rf $(OBJS) dep/*
|
||||
-rm -rf $(LIBRARY) $(OBJS)
|
||||
|
||||
## Other dependencies
|
||||
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
||||
* SPI Master library for arduino.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _SPI_H_INCLUDED
|
||||
#define _SPI_H_INCLUDED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <Arduino.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define SPI_CLOCK_DIV4 0x00
|
||||
#define SPI_CLOCK_DIV16 0x01
|
||||
#define SPI_CLOCK_DIV64 0x02
|
||||
#define SPI_CLOCK_DIV128 0x03
|
||||
#define SPI_CLOCK_DIV2 0x04
|
||||
#define SPI_CLOCK_DIV8 0x05
|
||||
#define SPI_CLOCK_DIV32 0x06
|
||||
//#define SPI_CLOCK_DIV64 0x07
|
||||
|
||||
#define SPI_MODE0 0x00
|
||||
#define SPI_MODE1 0x04
|
||||
#define SPI_MODE2 0x08
|
||||
#define SPI_MODE3 0x0C
|
||||
|
||||
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
|
||||
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
|
||||
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
|
||||
|
||||
class SPIClass {
|
||||
public:
|
||||
inline static byte transfer(byte _data);
|
||||
|
||||
// SPI Configuration methods
|
||||
|
||||
inline static void attachInterrupt();
|
||||
inline static void detachInterrupt(); // Default
|
||||
|
||||
static void begin(); // Default
|
||||
static void end();
|
||||
|
||||
static void setBitOrder(uint8_t);
|
||||
static void setDataMode(uint8_t);
|
||||
static void setClockDivider(uint8_t);
|
||||
};
|
||||
|
||||
extern SPIClass SPI;
|
||||
|
||||
byte SPIClass::transfer(byte _data)
|
||||
{
|
||||
SPDR = _data;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
return SPDR;
|
||||
}
|
||||
|
||||
void SPIClass::attachInterrupt()
|
||||
{
|
||||
SPCR |= _BV(SPIE);
|
||||
}
|
||||
|
||||
void SPIClass::detachInterrupt()
|
||||
{
|
||||
SPCR &= ~_BV(SPIE);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) )
|
||||
#define ntohs(x) htons(x)
|
||||
|
||||
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
|
||||
((x)<< 8 & 0x00FF0000UL) | \
|
||||
((x)>> 8 & 0x0000FF00UL) | \
|
||||
((x)>>24 & 0x000000FFUL) )
|
||||
#define ntohl(x) htonl(x)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef W5100_H_INCLUDED
|
||||
#define W5100_H_INCLUDED
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define MAX_SOCK_NUM 4
|
||||
|
||||
typedef uint8_t SOCKET;
|
||||
|
||||
#define IDM_OR 0x8000
|
||||
#define IDM_AR0 0x8001
|
||||
#define IDM_AR1 0x8002
|
||||
#define IDM_DR 0x8003
|
||||
/*
|
||||
class MR {
|
||||
public:
|
||||
static const uint8_t RST = 0x80;
|
||||
static const uint8_t PB = 0x10;
|
||||
static const uint8_t PPPOE = 0x08;
|
||||
static const uint8_t LB = 0x04;
|
||||
static const uint8_t AI = 0x02;
|
||||
static const uint8_t IND = 0x01;
|
||||
};
|
||||
*/
|
||||
/*
|
||||
class IR {
|
||||
public:
|
||||
static const uint8_t CONFLICT = 0x80;
|
||||
static const uint8_t UNREACH = 0x40;
|
||||
static const uint8_t PPPoE = 0x20;
|
||||
static const uint8_t SOCK0 = 0x01;
|
||||
static const uint8_t SOCK1 = 0x02;
|
||||
static const uint8_t SOCK2 = 0x04;
|
||||
static const uint8_t SOCK3 = 0x08;
|
||||
static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); };
|
||||
};
|
||||
*/
|
||||
|
||||
class SnMR {
|
||||
public:
|
||||
static const uint8_t CLOSE = 0x00;
|
||||
static const uint8_t TCP = 0x01;
|
||||
static const uint8_t UDP = 0x02;
|
||||
static const uint8_t IPRAW = 0x03;
|
||||
static const uint8_t MACRAW = 0x04;
|
||||
static const uint8_t PPPOE = 0x05;
|
||||
static const uint8_t ND = 0x20;
|
||||
static const uint8_t MULTI = 0x80;
|
||||
};
|
||||
|
||||
enum SockCMD {
|
||||
Sock_OPEN = 0x01,
|
||||
Sock_LISTEN = 0x02,
|
||||
Sock_CONNECT = 0x04,
|
||||
Sock_DISCON = 0x08,
|
||||
Sock_CLOSE = 0x10,
|
||||
Sock_SEND = 0x20,
|
||||
Sock_SEND_MAC = 0x21,
|
||||
Sock_SEND_KEEP = 0x22,
|
||||
Sock_RECV = 0x40
|
||||
};
|
||||
|
||||
/*class SnCmd {
|
||||
public:
|
||||
static const uint8_t OPEN = 0x01;
|
||||
static const uint8_t LISTEN = 0x02;
|
||||
static const uint8_t CONNECT = 0x04;
|
||||
static const uint8_t DISCON = 0x08;
|
||||
static const uint8_t CLOSE = 0x10;
|
||||
static const uint8_t SEND = 0x20;
|
||||
static const uint8_t SEND_MAC = 0x21;
|
||||
static const uint8_t SEND_KEEP = 0x22;
|
||||
static const uint8_t RECV = 0x40;
|
||||
};
|
||||
*/
|
||||
|
||||
class SnIR {
|
||||
public:
|
||||
static const uint8_t SEND_OK = 0x10;
|
||||
static const uint8_t TIMEOUT = 0x08;
|
||||
static const uint8_t RECV = 0x04;
|
||||
static const uint8_t DISCON = 0x02;
|
||||
static const uint8_t CON = 0x01;
|
||||
};
|
||||
|
||||
class SnSR {
|
||||
public:
|
||||
static const uint8_t CLOSED = 0x00;
|
||||
static const uint8_t INIT = 0x13;
|
||||
static const uint8_t LISTEN = 0x14;
|
||||
static const uint8_t SYNSENT = 0x15;
|
||||
static const uint8_t SYNRECV = 0x16;
|
||||
static const uint8_t ESTABLISHED = 0x17;
|
||||
static const uint8_t FIN_WAIT = 0x18;
|
||||
static const uint8_t CLOSING = 0x1A;
|
||||
static const uint8_t TIME_WAIT = 0x1B;
|
||||
static const uint8_t CLOSE_WAIT = 0x1C;
|
||||
static const uint8_t LAST_ACK = 0x1D;
|
||||
static const uint8_t UDP = 0x22;
|
||||
static const uint8_t IPRAW = 0x32;
|
||||
static const uint8_t MACRAW = 0x42;
|
||||
static const uint8_t PPPOE = 0x5F;
|
||||
};
|
||||
|
||||
class IPPROTO {
|
||||
public:
|
||||
static const uint8_t IP = 0;
|
||||
static const uint8_t ICMP = 1;
|
||||
static const uint8_t IGMP = 2;
|
||||
static const uint8_t GGP = 3;
|
||||
static const uint8_t TCP = 6;
|
||||
static const uint8_t PUP = 12;
|
||||
static const uint8_t UDP = 17;
|
||||
static const uint8_t IDP = 22;
|
||||
static const uint8_t ND = 77;
|
||||
static const uint8_t RAW = 255;
|
||||
};
|
||||
|
||||
class W5100Class {
|
||||
|
||||
public:
|
||||
void init();
|
||||
|
||||
/**
|
||||
* @brief This function is being used for copy the data form Receive buffer of the chip to application buffer.
|
||||
*
|
||||
* It calculate the actual physical address where one has to read
|
||||
* the data from Receive buffer. Here also take care of the condition while it exceed
|
||||
* the Rx memory uper-bound of socket.
|
||||
*/
|
||||
void read_data(SOCKET s,
|
||||
volatile uint8_t * src,
|
||||
volatile uint8_t * dst,
|
||||
uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief This function is being called by send() and sendto() function also.
|
||||
*
|
||||
* This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer
|
||||
* register. User should read upper byte first and lower byte later to get proper value.
|
||||
*/
|
||||
void send_data_processing(SOCKET s,
|
||||
const uint8_t * data,
|
||||
uint16_t len);
|
||||
/**
|
||||
* @brief A copy of send_data_processing that uses the provided ptr for the
|
||||
* write offset. Only needed for the "streaming" UDP API, where
|
||||
* a single UDP packet is built up over a number of calls to
|
||||
* send_data_processing_ptr, because TX_WR doesn't seem to get updated
|
||||
* correctly in those scenarios
|
||||
* @param ptr value to use in place of TX_WR. If 0, then the value is read
|
||||
* in from TX_WR
|
||||
* @return New value for ptr, to be used in the next call
|
||||
*/
|
||||
// FIXME Update documentation
|
||||
void send_data_processing_offset(SOCKET s,
|
||||
uint16_t data_offset,
|
||||
const uint8_t * data,
|
||||
uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief This function is being called by recv() also.
|
||||
*
|
||||
* This function read the Rx read pointer register
|
||||
* and after copy the data from receive buffer update the Rx write pointer register.
|
||||
* User should read upper byte first and lower byte later to get proper value.
|
||||
*/
|
||||
void recv_data_processing(SOCKET s,
|
||||
uint8_t * data,
|
||||
uint16_t len,
|
||||
uint8_t peek = 0);
|
||||
|
||||
inline void setGatewayIp(uint8_t * _addr);
|
||||
inline void getGatewayIp(uint8_t * _addr);
|
||||
|
||||
inline void setSubnetMask(uint8_t * _addr);
|
||||
inline void getSubnetMask(uint8_t * _addr);
|
||||
|
||||
inline void setMACAddress(uint8_t * addr);
|
||||
inline void getMACAddress(uint8_t * addr);
|
||||
|
||||
inline void setIPAddress(uint8_t * addr);
|
||||
inline void getIPAddress(uint8_t * addr);
|
||||
|
||||
inline void setRetransmissionTime(uint16_t timeout);
|
||||
inline void setRetransmissionCount(uint8_t _retry);
|
||||
|
||||
void execCmdSn(SOCKET s,
|
||||
SockCMD _cmd);
|
||||
|
||||
uint16_t getTXFreeSize(SOCKET s);
|
||||
uint16_t getRXReceivedSize(SOCKET s);
|
||||
|
||||
|
||||
// W5100 Registers
|
||||
// ---------------
|
||||
private:
|
||||
static uint8_t write(uint16_t _addr,
|
||||
uint8_t _data);
|
||||
static uint16_t write(uint16_t addr,
|
||||
const uint8_t * buf,
|
||||
uint16_t len);
|
||||
static uint8_t read(uint16_t addr);
|
||||
static uint16_t read(uint16_t addr,
|
||||
uint8_t * buf,
|
||||
uint16_t len);
|
||||
|
||||
#define __GP_REGISTER8(name, address) \
|
||||
static inline void write##name(uint8_t _data) { \
|
||||
write(address, _data); \
|
||||
} \
|
||||
static inline uint8_t read##name() { \
|
||||
return read(address); \
|
||||
}
|
||||
#define __GP_REGISTER16(name, address) \
|
||||
static void write##name(uint16_t _data) { \
|
||||
write(address, _data >> 8); \
|
||||
write(address+1, _data & 0xFF); \
|
||||
} \
|
||||
static uint16_t read##name() { \
|
||||
uint16_t res = read(address); \
|
||||
res = (res << 8) + read(address + 1); \
|
||||
return res; \
|
||||
}
|
||||
#define __GP_REGISTER_N(name, address, size) \
|
||||
static uint16_t write##name(uint8_t *_buff) { \
|
||||
return write(address, _buff, size); \
|
||||
} \
|
||||
static uint16_t read##name(uint8_t *_buff) { \
|
||||
return read(address, _buff, size); \
|
||||
}
|
||||
|
||||
public:
|
||||
__GP_REGISTER8(MR,
|
||||
0x0000); // Mode
|
||||
__GP_REGISTER_N(GAR,
|
||||
0x0001,
|
||||
4); // Gateway IP address
|
||||
__GP_REGISTER_N(SUBR,
|
||||
0x0005,
|
||||
4); // Subnet mask address
|
||||
__GP_REGISTER_N(SHAR,
|
||||
0x0009,
|
||||
6); // Source MAC address
|
||||
__GP_REGISTER_N(SIPR,
|
||||
0x000F,
|
||||
4); // Source IP address
|
||||
__GP_REGISTER8(IR,
|
||||
0x0015); // Interrupt
|
||||
__GP_REGISTER8(IMR,
|
||||
0x0016); // Interrupt Mask
|
||||
__GP_REGISTER16(RTR,
|
||||
0x0017); // Timeout address
|
||||
__GP_REGISTER8(RCR,
|
||||
0x0019); // Retry count
|
||||
__GP_REGISTER8(RMSR,
|
||||
0x001A); // Receive memory size
|
||||
__GP_REGISTER8(TMSR,
|
||||
0x001B); // Transmit memory size
|
||||
__GP_REGISTER8(PATR,
|
||||
0x001C); // Authentication type address in PPPoE mode
|
||||
__GP_REGISTER8(PTIMER,
|
||||
0x0028); // PPP LCP Request Timer
|
||||
__GP_REGISTER8(PMAGIC,
|
||||
0x0029); // PPP LCP Magic Number
|
||||
__GP_REGISTER_N(UIPR,
|
||||
0x002A,
|
||||
4); // Unreachable IP address in UDP mode
|
||||
__GP_REGISTER16(UPORT,
|
||||
0x002E); // Unreachable Port address in UDP mode
|
||||
|
||||
#undef __GP_REGISTER8
|
||||
#undef __GP_REGISTER16
|
||||
#undef __GP_REGISTER_N
|
||||
|
||||
// W5100 Socket registers
|
||||
// ----------------------
|
||||
private:
|
||||
static inline uint8_t readSn(SOCKET _s,
|
||||
uint16_t _addr);
|
||||
static inline uint8_t writeSn(SOCKET _s,
|
||||
uint16_t _addr,
|
||||
uint8_t _data);
|
||||
static inline uint16_t readSn(SOCKET _s,
|
||||
uint16_t _addr,
|
||||
uint8_t * _buf,
|
||||
uint16_t len);
|
||||
static inline uint16_t writeSn(SOCKET _s,
|
||||
uint16_t _addr,
|
||||
uint8_t * _buf,
|
||||
uint16_t len);
|
||||
|
||||
static const uint16_t CH_BASE = 0x0400;
|
||||
static const uint16_t CH_SIZE = 0x0100;
|
||||
|
||||
#define __SOCKET_REGISTER8(name, address) \
|
||||
static inline void write##name(SOCKET _s, uint8_t _data) { \
|
||||
writeSn(_s, address, _data); \
|
||||
} \
|
||||
static inline uint8_t read##name(SOCKET _s) { \
|
||||
return readSn(_s, address); \
|
||||
}
|
||||
#define __SOCKET_REGISTER16(name, address) \
|
||||
static void write##name(SOCKET _s, uint16_t _data) { \
|
||||
writeSn(_s, address, _data >> 8); \
|
||||
writeSn(_s, address+1, _data & 0xFF); \
|
||||
} \
|
||||
static uint16_t read##name(SOCKET _s) { \
|
||||
uint16_t res = readSn(_s, address); \
|
||||
uint16_t res2 = readSn(_s,address + 1); \
|
||||
res = res << 8; \
|
||||
res2 = res2 & 0xFF; \
|
||||
res = res | res2; \
|
||||
return res; \
|
||||
}
|
||||
#define __SOCKET_REGISTER_N(name, address, size) \
|
||||
static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \
|
||||
return writeSn(_s, address, _buff, size); \
|
||||
} \
|
||||
static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \
|
||||
return readSn(_s, address, _buff, size); \
|
||||
}
|
||||
|
||||
public:
|
||||
__SOCKET_REGISTER8(SnMR,
|
||||
0x0000) // Mode
|
||||
__SOCKET_REGISTER8(SnCR,
|
||||
0x0001) // Command
|
||||
__SOCKET_REGISTER8(SnIR,
|
||||
0x0002) // Interrupt
|
||||
__SOCKET_REGISTER8(SnSR,
|
||||
0x0003) // Status
|
||||
__SOCKET_REGISTER16(SnPORT,
|
||||
0x0004) // Source Port
|
||||
__SOCKET_REGISTER_N(SnDHAR,
|
||||
0x0006,
|
||||
6) // Destination Hardw Addr
|
||||
__SOCKET_REGISTER_N(SnDIPR,
|
||||
0x000C,
|
||||
4) // Destination IP Addr
|
||||
__SOCKET_REGISTER16(SnDPORT,
|
||||
0x0010) // Destination Port
|
||||
__SOCKET_REGISTER16(SnMSSR,
|
||||
0x0012) // Max Segment Size
|
||||
__SOCKET_REGISTER8(SnPROTO,
|
||||
0x0014) // Protocol in IP RAW Mode
|
||||
__SOCKET_REGISTER8(SnTOS,
|
||||
0x0015) // IP TOS
|
||||
__SOCKET_REGISTER8(SnTTL,
|
||||
0x0016) // IP TTL
|
||||
__SOCKET_REGISTER16(SnTX_FSR,
|
||||
0x0020) // TX Free Size
|
||||
__SOCKET_REGISTER16(SnTX_RD,
|
||||
0x0022) // TX Read Pointer
|
||||
__SOCKET_REGISTER16(SnTX_WR,
|
||||
0x0024) // TX Write Pointer
|
||||
__SOCKET_REGISTER16(SnRX_RSR,
|
||||
0x0026) // RX Free Size
|
||||
__SOCKET_REGISTER16(SnRX_RD,
|
||||
0x0028) // RX Read Pointer
|
||||
__SOCKET_REGISTER16(SnRX_WR,
|
||||
0x002A) // RX Write Pointer (supported?)
|
||||
#undef __SOCKET_REGISTER8
|
||||
#undef __SOCKET_REGISTER16
|
||||
#undef __SOCKET_REGISTER_N
|
||||
private:
|
||||
static const uint8_t RST = 7; // Reset BIT
|
||||
|
||||
static const int SOCKETS = 4;
|
||||
static const uint16_t SMASK = 0x07FF; // Tx buffer MASK
|
||||
static const uint16_t RMASK = 0x07FF; // Rx buffer MASK
|
||||
public:
|
||||
static const uint16_t SSIZE = 2048; // Max Tx buffer size
|
||||
private:
|
||||
static const uint16_t RSIZE = 2048; // Max Rx buffer size
|
||||
uint16_t SBASE[SOCKETS]; // Tx buffer base address
|
||||
uint16_t RBASE[SOCKETS]; // Rx buffer base address
|
||||
|
||||
private:
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
inline static void initSS() {
|
||||
DDRB |= _BV(4);
|
||||
};
|
||||
inline static void setSS() {
|
||||
PORTB &= ~_BV(4);
|
||||
};
|
||||
inline static void resetSS() {
|
||||
PORTB |= _BV(4);
|
||||
};
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
inline static void initSS() {
|
||||
DDRB |= _BV(6);
|
||||
};
|
||||
inline static void setSS() {
|
||||
PORTB &= ~_BV(6);
|
||||
};
|
||||
inline static void resetSS() {
|
||||
PORTB |= _BV(6);
|
||||
};
|
||||
#elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__)
|
||||
inline static void initSS() {
|
||||
DDRB |= _BV(0);
|
||||
};
|
||||
inline static void setSS() {
|
||||
PORTB &= ~_BV(0);
|
||||
};
|
||||
inline static void resetSS() {
|
||||
PORTB |= _BV(0);
|
||||
};
|
||||
#else
|
||||
inline static void initSS() {
|
||||
DDRB |= _BV(2);
|
||||
};
|
||||
inline static void setSS() {
|
||||
PORTB &= ~_BV(2);
|
||||
};
|
||||
inline static void resetSS() {
|
||||
PORTB |= _BV(2);
|
||||
};
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
extern W5100Class W5100;
|
||||
|
||||
uint8_t W5100Class::readSn(SOCKET _s,
|
||||
uint16_t _addr)
|
||||
{
|
||||
return read(CH_BASE + _s * CH_SIZE + _addr);
|
||||
}
|
||||
|
||||
uint8_t W5100Class::writeSn(SOCKET _s,
|
||||
uint16_t _addr,
|
||||
uint8_t _data)
|
||||
{
|
||||
return write(CH_BASE + _s * CH_SIZE + _addr, _data);
|
||||
}
|
||||
|
||||
uint16_t W5100Class::readSn(SOCKET _s,
|
||||
uint16_t _addr,
|
||||
uint8_t * _buf,
|
||||
uint16_t _len)
|
||||
{
|
||||
return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len);
|
||||
}
|
||||
|
||||
uint16_t W5100Class::writeSn(SOCKET _s,
|
||||
uint16_t _addr,
|
||||
uint8_t * _buf,
|
||||
uint16_t _len)
|
||||
{
|
||||
return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len);
|
||||
}
|
||||
|
||||
void W5100Class::getGatewayIp(uint8_t * _addr)
|
||||
{
|
||||
readGAR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setGatewayIp(uint8_t * _addr)
|
||||
{
|
||||
writeGAR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::getSubnetMask(uint8_t * _addr)
|
||||
{
|
||||
readSUBR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setSubnetMask(uint8_t * _addr)
|
||||
{
|
||||
writeSUBR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::getMACAddress(uint8_t * _addr)
|
||||
{
|
||||
readSHAR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setMACAddress(uint8_t * _addr)
|
||||
{
|
||||
writeSHAR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::getIPAddress(uint8_t * _addr)
|
||||
{
|
||||
readSIPR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setIPAddress(uint8_t * _addr)
|
||||
{
|
||||
writeSIPR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setRetransmissionTime(uint16_t _timeout)
|
||||
{
|
||||
writeRTR(_timeout);
|
||||
}
|
||||
|
||||
void W5100Class::setRetransmissionCount(uint8_t _retry)
|
||||
{
|
||||
writeRCR(_retry);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* w5100Wrapper.h
|
||||
*
|
||||
* Created on: 26 de Mai de 2013
|
||||
* Author: mgf
|
||||
*/
|
||||
|
||||
#ifndef W5100WRAPPER_H_
|
||||
#define W5100WRAPPER_H_
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
typedef uint8_t SOCKET;
|
||||
typedef void CSnMR;
|
||||
typedef void CSnIR;
|
||||
typedef void CSnSR;
|
||||
typedef void CIPPROTO;
|
||||
typedef void CW5100Class;
|
||||
|
||||
#define MAX_SOCK_NUM 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
CSnMR *CSnMR_new();
|
||||
void CSnMR_delete(const CSnMR * obj);
|
||||
uint8_t SnMR_CLOSE();
|
||||
uint8_t SnMR_UDP();
|
||||
uint8_t SnMR_TCP();
|
||||
uint8_t SnMR_IPRAW();
|
||||
uint8_t SnMR_MACRAW();
|
||||
uint8_t SnMR_PPPOE();
|
||||
uint8_t SnMR_ND();
|
||||
uint8_t SnMR_MULTI();
|
||||
|
||||
CSnIR *CSnIR_new();
|
||||
void CSnIR_delete(const CSnIR * obj);
|
||||
uint8_t SnIR_SEND_OK();
|
||||
uint8_t SnIR_TIMEOUT();
|
||||
uint8_t SnIR_RECV();
|
||||
uint8_t SnIR_DISCON();
|
||||
uint8_t SnIR_CON();
|
||||
|
||||
|
||||
CSnSR *CSnSR_new();
|
||||
void CSnSR_delete(const CSnSR * obj);
|
||||
uint8_t SnSR_CLOSED();
|
||||
uint8_t SnSR_INIT();
|
||||
uint8_t SnSR_LISTEN();
|
||||
uint8_t SnSR_SYNSENT();
|
||||
uint8_t SnSR_SYNRECV();
|
||||
uint8_t SnSR_ESTABLISHED();
|
||||
uint8_t SnSR_FIN_WAIT();
|
||||
uint8_t SnSR_CLOSING();
|
||||
uint8_t SnSR_TIME_WAIT();
|
||||
uint8_t SnSR_CLOSE_WAIT();
|
||||
uint8_t SnSR_LAST_ACK();
|
||||
uint8_t SnSR_UDP();
|
||||
uint8_t SnSR_IPRAW();
|
||||
uint8_t SnSR_MACRAW();
|
||||
uint8_t SnSR_PPPOE();
|
||||
|
||||
CIPPROTO *CIPPROTO_new();
|
||||
void CIPPROTO_delete(const CIPPROTO * obj);
|
||||
uint8_t IPPROTO_IP();
|
||||
uint8_t IPPROTO_ICMP();
|
||||
uint8_t IPPROTO_IGMP();
|
||||
uint8_t IPPROTO_GGP();
|
||||
uint8_t IPPROTO_TCP();
|
||||
uint8_t IPPROTO_PUP();
|
||||
uint8_t IPPROTO_UDP();
|
||||
uint8_t IPPROTO_IDP();
|
||||
uint8_t IPPROTO_ND();
|
||||
uint8_t IPPROTO_RAW();
|
||||
|
||||
CW5100Class *CW5100Class_new();
|
||||
void init_func(const CW5100Class * obj);
|
||||
void CW5100Class_delete(const CW5100Class * obj);
|
||||
|
||||
void read_data_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
volatile uint8_t * src,
|
||||
volatile uint8_t * dst,
|
||||
uint16_t len);
|
||||
|
||||
void send_data_processing_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
const uint8_t * data,
|
||||
uint16_t len);
|
||||
void send_data_processing_offset_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
uint16_t data_offset,
|
||||
const uint8_t * data,
|
||||
uint16_t len);
|
||||
//FIXME: Removed defaul value of 0(zero) from the peek argument
|
||||
void recv_data_processing_func(const CW5100Class * obj,
|
||||
SOCKET s,
|
||||
uint8_t * data,
|
||||
uint16_t len,
|
||||
uint8_t peek);
|
||||
void setGatewayIp_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
void getGatewayIp_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
//
|
||||
void setSubnetMask_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
void getSubnetMask_func(const CW5100Class * obj,
|
||||
uint8_t * _addr);
|
||||
//
|
||||
void setMACAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
void getMACAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
//
|
||||
void setIPAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
void getIPAddress_func(const CW5100Class * obj,
|
||||
uint8_t * addr);
|
||||
//
|
||||
void setRetransmissionTime_func(const CW5100Class * obj,
|
||||
uint16_t timeout);
|
||||
void setRetransmissionCount_func(const CW5100Class * obj,
|
||||
uint8_t _retry);
|
||||
//
|
||||
|
||||
uint16_t getTXFreeSize_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
uint16_t getRXReceivedSize_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
|
||||
uint8_t readSnSR_func(const CW5100Class * obj,
|
||||
SOCKET s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* W5100WRAPPER_H_ */
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
||||
* SPI Master library for arduino.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "pins_arduino.h"
|
||||
#include "SPI.h"
|
||||
|
||||
SPIClass SPI;
|
||||
|
||||
void SPIClass::begin() {
|
||||
|
||||
// Set SS to high so a connected chip will be "deselected" by default
|
||||
digitalWrite(SS, HIGH);
|
||||
|
||||
// When the SS pin is set as OUTPUT, it can be used as
|
||||
// a general purpose output port (it doesn't influence
|
||||
// SPI operations).
|
||||
pinMode(SS, OUTPUT);
|
||||
|
||||
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
|
||||
// automatically switches to Slave, so the data direction of
|
||||
// the SS pin MUST be kept as OUTPUT.
|
||||
SPCR |= _BV(MSTR);
|
||||
SPCR |= _BV(SPE);
|
||||
|
||||
// Set direction register for SCK and MOSI pin.
|
||||
// MISO pin automatically overrides to INPUT.
|
||||
// By doing this AFTER enabling SPI, we avoid accidentally
|
||||
// clocking in a single bit since the lines go directly
|
||||
// from "input" to SPI control.
|
||||
// http://code.google.com/p/arduino/issues/detail?id=888
|
||||
pinMode(SCK, OUTPUT);
|
||||
pinMode(MOSI, OUTPUT);
|
||||
}
|
||||
|
||||
|
||||
void SPIClass::end() {
|
||||
SPCR &= ~_BV(SPE);
|
||||
}
|
||||
|
||||
void SPIClass::setBitOrder(uint8_t bitOrder)
|
||||
{
|
||||
if(bitOrder == LSBFIRST) {
|
||||
SPCR |= _BV(DORD);
|
||||
} else {
|
||||
SPCR &= ~(_BV(DORD));
|
||||
}
|
||||
}
|
||||
|
||||
void SPIClass::setDataMode(uint8_t mode)
|
||||
{
|
||||
SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
|
||||
}
|
||||
|
||||
void SPIClass::setClockDivider(uint8_t rate)
|
||||
{
|
||||
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK);
|
||||
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,400 @@
|
||||
#include "w5100.h"
|
||||
#include "socket.h"
|
||||
|
||||
static uint16_t local_port;
|
||||
|
||||
/**
|
||||
* @brief This Socket function initialize the channel in perticular mode, and set the port and wait for W5100 done it.
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
|
||||
{
|
||||
if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE))
|
||||
{
|
||||
close(s);
|
||||
W5100.writeSnMR(s, protocol | flag);
|
||||
if (port != 0) {
|
||||
W5100.writeSnPORT(s, port);
|
||||
}
|
||||
else {
|
||||
local_port++; // if don't set the source port, set local_port number.
|
||||
W5100.writeSnPORT(s, local_port);
|
||||
}
|
||||
|
||||
W5100.execCmdSn(s, Sock_OPEN);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function close the socket and parameter is "s" which represent the socket number
|
||||
*/
|
||||
void close(SOCKET s)
|
||||
{
|
||||
W5100.execCmdSn(s, Sock_CLOSE);
|
||||
W5100.writeSnIR(s, 0xFF);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function established the connection for the channel in passive (server) mode. This function waits for the request from the peer.
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
uint8_t listen(SOCKET s)
|
||||
{
|
||||
if (W5100.readSnSR(s) != SnSR::INIT)
|
||||
return 0;
|
||||
W5100.execCmdSn(s, Sock_LISTEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function established the connection for the channel in Active (client) mode.
|
||||
* This function waits for the untill the connection is established.
|
||||
*
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port)
|
||||
{
|
||||
if
|
||||
(
|
||||
((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
|
||||
((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
|
||||
(port == 0x00)
|
||||
)
|
||||
return 0;
|
||||
|
||||
// set destination IP
|
||||
W5100.writeSnDIPR(s, addr);
|
||||
W5100.writeSnDPORT(s, port);
|
||||
W5100.execCmdSn(s, Sock_CONNECT);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function used for disconnect the socket and parameter is "s" which represent the socket number
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
void disconnect(SOCKET s)
|
||||
{
|
||||
W5100.execCmdSn(s, Sock_DISCON);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function used to send the data in TCP mode
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len)
|
||||
{
|
||||
uint8_t status=0;
|
||||
uint16_t ret=0;
|
||||
uint16_t freesize=0;
|
||||
|
||||
if (len > W5100.SSIZE)
|
||||
ret = W5100.SSIZE; // check size not to exceed MAX size.
|
||||
else
|
||||
ret = len;
|
||||
|
||||
// if freebuf is available, start.
|
||||
do
|
||||
{
|
||||
freesize = W5100.getTXFreeSize(s);
|
||||
status = W5100.readSnSR(s);
|
||||
if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT))
|
||||
{
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (freesize < ret);
|
||||
|
||||
// copy data
|
||||
W5100.send_data_processing(s, (uint8_t *)buf, ret);
|
||||
W5100.execCmdSn(s, Sock_SEND);
|
||||
|
||||
/* +2008.01 bj */
|
||||
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
|
||||
{
|
||||
/* m2008.01 [bj] : reduce code */
|
||||
if ( W5100.readSnSR(s) == SnSR::CLOSED )
|
||||
{
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* +2008.01 bj */
|
||||
W5100.writeSnIR(s, SnIR::SEND_OK);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is an application I/F function which is used to receive the data in TCP mode.
|
||||
* It continues to wait for data as much as the application wants to receive.
|
||||
*
|
||||
* @return received data size for success else -1.
|
||||
*/
|
||||
int16_t recv(SOCKET s, uint8_t *buf, int16_t len)
|
||||
{
|
||||
// Check how much data is available
|
||||
int16_t ret = W5100.getRXReceivedSize(s);
|
||||
if ( ret == 0 )
|
||||
{
|
||||
// No data available.
|
||||
uint8_t status = W5100.readSnSR(s);
|
||||
if ( status == SnSR::LISTEN || status == SnSR::CLOSED || status == SnSR::CLOSE_WAIT )
|
||||
{
|
||||
// The remote end has closed its side of the connection, so this is the eof state
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The connection is still up, but there's no data waiting to be read
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else if (ret > len)
|
||||
{
|
||||
ret = len;
|
||||
}
|
||||
|
||||
if ( ret > 0 )
|
||||
{
|
||||
W5100.recv_data_processing(s, buf, ret);
|
||||
W5100.execCmdSn(s, Sock_RECV);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the first byte in the receive queue (no checking)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
uint16_t peek(SOCKET s, uint8_t *buf)
|
||||
{
|
||||
W5100.recv_data_processing(s, buf, 1, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is an application I/F function which is used to send the data for other then TCP mode.
|
||||
* Unlike TCP transmission, The peer's destination address and the port is needed.
|
||||
*
|
||||
* @return This function return send data size for success else -1.
|
||||
*/
|
||||
uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port)
|
||||
{
|
||||
uint16_t ret=0;
|
||||
|
||||
if (len > W5100.SSIZE) ret = W5100.SSIZE; // check size not to exceed MAX size.
|
||||
else ret = len;
|
||||
|
||||
if
|
||||
(
|
||||
((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
|
||||
((port == 0x00)) ||(ret == 0)
|
||||
)
|
||||
{
|
||||
/* +2008.01 [bj] : added return value */
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
W5100.writeSnDIPR(s, addr);
|
||||
W5100.writeSnDPORT(s, port);
|
||||
|
||||
// copy data
|
||||
W5100.send_data_processing(s, (uint8_t *)buf, ret);
|
||||
W5100.execCmdSn(s, Sock_SEND);
|
||||
|
||||
/* +2008.01 bj */
|
||||
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
|
||||
{
|
||||
if (W5100.readSnIR(s) & SnIR::TIMEOUT)
|
||||
{
|
||||
/* +2008.01 [bj]: clear interrupt */
|
||||
W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* +2008.01 bj */
|
||||
W5100.writeSnIR(s, SnIR::SEND_OK);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is an application I/F function which is used to receive the data in other then
|
||||
* TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well.
|
||||
*
|
||||
* @return This function return received data size for success else -1.
|
||||
*/
|
||||
uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port)
|
||||
{
|
||||
uint8_t head[8];
|
||||
uint16_t data_len=0;
|
||||
uint16_t ptr=0;
|
||||
|
||||
if ( len > 0 )
|
||||
{
|
||||
ptr = W5100.readSnRX_RD(s);
|
||||
switch (W5100.readSnMR(s) & 0x07)
|
||||
{
|
||||
case SnMR::UDP :
|
||||
W5100.read_data(s, (uint8_t *)ptr, head, 0x08);
|
||||
ptr += 8;
|
||||
// read peer's IP address, port number.
|
||||
addr[0] = head[0];
|
||||
addr[1] = head[1];
|
||||
addr[2] = head[2];
|
||||
addr[3] = head[3];
|
||||
*port = head[4];
|
||||
*port = (*port << 8) + head[5];
|
||||
data_len = head[6];
|
||||
data_len = (data_len << 8) + head[7];
|
||||
|
||||
W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy.
|
||||
ptr += data_len;
|
||||
|
||||
W5100.writeSnRX_RD(s, ptr);
|
||||
break;
|
||||
|
||||
case SnMR::IPRAW :
|
||||
W5100.read_data(s, (uint8_t *)ptr, head, 0x06);
|
||||
ptr += 6;
|
||||
|
||||
addr[0] = head[0];
|
||||
addr[1] = head[1];
|
||||
addr[2] = head[2];
|
||||
addr[3] = head[3];
|
||||
data_len = head[4];
|
||||
data_len = (data_len << 8) + head[5];
|
||||
|
||||
W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy.
|
||||
ptr += data_len;
|
||||
|
||||
W5100.writeSnRX_RD(s, ptr);
|
||||
break;
|
||||
|
||||
case SnMR::MACRAW:
|
||||
W5100.read_data(s,(uint8_t*)ptr,head,2);
|
||||
ptr+=2;
|
||||
data_len = head[0];
|
||||
data_len = (data_len<<8) + head[1] - 2;
|
||||
|
||||
W5100.read_data(s,(uint8_t*) ptr,buf,data_len);
|
||||
ptr += data_len;
|
||||
W5100.writeSnRX_RD(s, ptr);
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
W5100.execCmdSn(s, Sock_RECV);
|
||||
}
|
||||
return data_len;
|
||||
}
|
||||
|
||||
|
||||
uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len)
|
||||
{
|
||||
uint8_t status=0;
|
||||
uint16_t ret=0;
|
||||
|
||||
if (len > W5100.SSIZE)
|
||||
ret = W5100.SSIZE; // check size not to exceed MAX size.
|
||||
else
|
||||
ret = len;
|
||||
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
W5100.send_data_processing(s, (uint8_t *)buf, ret);
|
||||
W5100.execCmdSn(s, Sock_SEND);
|
||||
|
||||
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
|
||||
{
|
||||
status = W5100.readSnSR(s);
|
||||
if (W5100.readSnIR(s) & SnIR::TIMEOUT)
|
||||
{
|
||||
/* in case of igmp, if send fails, then socket closed */
|
||||
/* if you want change, remove this code. */
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
W5100.writeSnIR(s, SnIR::SEND_OK);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len)
|
||||
{
|
||||
uint16_t ret =0;
|
||||
if (len > W5100.getTXFreeSize(s))
|
||||
{
|
||||
ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size.
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = len;
|
||||
}
|
||||
W5100.send_data_processing_offset(s, offset, buf, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int startUDP(SOCKET s, uint8_t* addr, uint16_t port)
|
||||
{
|
||||
if
|
||||
(
|
||||
((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
|
||||
((port == 0x00))
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
W5100.writeSnDIPR(s, addr);
|
||||
W5100.writeSnDPORT(s, port);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int sendUDP(SOCKET s)
|
||||
{
|
||||
W5100.execCmdSn(s, Sock_SEND);
|
||||
|
||||
/* +2008.01 bj */
|
||||
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
|
||||
{
|
||||
if (W5100.readSnIR(s) & SnIR::TIMEOUT)
|
||||
{
|
||||
/* +2008.01 [bj]: clear interrupt */
|
||||
W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* +2008.01 bj */
|
||||
W5100.writeSnIR(s, SnIR::SEND_OK);
|
||||
|
||||
/* Sent ok */
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "w5100.h"
|
||||
|
||||
// W5100 controller instance
|
||||
W5100Class W5100;
|
||||
|
||||
#define TX_RX_MAX_BUF_SIZE 2048
|
||||
#define TX_BUF 0x1100
|
||||
#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE)
|
||||
|
||||
#define TXBUF_BASE 0x4000
|
||||
#define RXBUF_BASE 0x6000
|
||||
|
||||
void W5100Class::init(void)
|
||||
{
|
||||
delay(300);
|
||||
|
||||
SPI.begin();
|
||||
initSS();
|
||||
|
||||
writeMR(1<<RST);
|
||||
writeTMSR(0x55);
|
||||
writeRMSR(0x55);
|
||||
|
||||
for (int i=0; i<MAX_SOCK_NUM; i++) {
|
||||
SBASE[i] = TXBUF_BASE + SSIZE * i;
|
||||
RBASE[i] = RXBUF_BASE + RSIZE * i;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t W5100Class::getTXFreeSize(SOCKET s)
|
||||
{
|
||||
uint16_t val=0, val1=0;
|
||||
do {
|
||||
val1 = readSnTX_FSR(s);
|
||||
if (val1 != 0)
|
||||
val = readSnTX_FSR(s);
|
||||
}
|
||||
while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t W5100Class::getRXReceivedSize(SOCKET s)
|
||||
{
|
||||
uint16_t val=0,val1=0;
|
||||
do {
|
||||
val1 = readSnRX_RSR(s);
|
||||
if (val1 != 0)
|
||||
val = readSnRX_RSR(s);
|
||||
}
|
||||
while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
void W5100Class::send_data_processing(SOCKET s, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
// This is same as having no offset in a call to send_data_processing_offset
|
||||
send_data_processing_offset(s, 0, data, len);
|
||||
}
|
||||
|
||||
void W5100Class::send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
uint16_t ptr = readSnTX_WR(s);
|
||||
ptr += data_offset;
|
||||
uint16_t offset = ptr & SMASK;
|
||||
uint16_t dstAddr = offset + SBASE[s];
|
||||
|
||||
if (offset + len > SSIZE)
|
||||
{
|
||||
// Wrap around circular buffer
|
||||
uint16_t size = SSIZE - offset;
|
||||
write(dstAddr, data, size);
|
||||
write(SBASE[s], data + size, len - size);
|
||||
}
|
||||
else {
|
||||
write(dstAddr, data, len);
|
||||
}
|
||||
|
||||
ptr += len;
|
||||
writeSnTX_WR(s, ptr);
|
||||
}
|
||||
|
||||
|
||||
void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek)
|
||||
{
|
||||
uint16_t ptr;
|
||||
ptr = readSnRX_RD(s);
|
||||
read_data(s, (uint8_t *)ptr, data, len);
|
||||
if (!peek)
|
||||
{
|
||||
ptr += len;
|
||||
writeSnRX_RD(s, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void W5100Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len)
|
||||
{
|
||||
uint16_t size;
|
||||
uint16_t src_mask;
|
||||
uint16_t src_ptr;
|
||||
|
||||
src_mask = (uint16_t)src & RMASK;
|
||||
src_ptr = RBASE[s] + src_mask;
|
||||
|
||||
if( (src_mask + len) > RSIZE )
|
||||
{
|
||||
size = RSIZE - src_mask;
|
||||
read(src_ptr, (uint8_t *)dst, size);
|
||||
dst += size;
|
||||
read(RBASE[s], (uint8_t *) dst, len - size);
|
||||
}
|
||||
else
|
||||
read(src_ptr, (uint8_t *) dst, len);
|
||||
}
|
||||
|
||||
|
||||
uint8_t W5100Class::write(uint16_t _addr, uint8_t _data)
|
||||
{
|
||||
setSS();
|
||||
SPI.transfer(0xF0);
|
||||
SPI.transfer(_addr >> 8);
|
||||
SPI.transfer(_addr & 0xFF);
|
||||
SPI.transfer(_data);
|
||||
resetSS();
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len)
|
||||
{
|
||||
for (uint16_t i=0; i<_len; i++)
|
||||
{
|
||||
setSS();
|
||||
SPI.transfer(0xF0);
|
||||
SPI.transfer(_addr >> 8);
|
||||
SPI.transfer(_addr & 0xFF);
|
||||
_addr++;
|
||||
SPI.transfer(_buf[i]);
|
||||
resetSS();
|
||||
}
|
||||
return _len;
|
||||
}
|
||||
|
||||
uint8_t W5100Class::read(uint16_t _addr)
|
||||
{
|
||||
setSS();
|
||||
SPI.transfer(0x0F);
|
||||
SPI.transfer(_addr >> 8);
|
||||
SPI.transfer(_addr & 0xFF);
|
||||
uint8_t _data = SPI.transfer(0);
|
||||
resetSS();
|
||||
return _data;
|
||||
}
|
||||
|
||||
uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
|
||||
{
|
||||
for (uint16_t i=0; i<_len; i++)
|
||||
{
|
||||
setSS();
|
||||
SPI.transfer(0x0F);
|
||||
SPI.transfer(_addr >> 8);
|
||||
SPI.transfer(_addr & 0xFF);
|
||||
_addr++;
|
||||
_buf[i] = SPI.transfer(0);
|
||||
resetSS();
|
||||
}
|
||||
return _len;
|
||||
}
|
||||
|
||||
void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) {
|
||||
// Send command to socket
|
||||
writeSnCR(s, _cmd);
|
||||
// Wait for command to complete
|
||||
while (readSnCR(s))
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* w5100Wrapper.cpp
|
||||
*
|
||||
* Created on: 26 de Mai de 2013
|
||||
* Author: mgf
|
||||
*/
|
||||
|
||||
|
||||
#include "w5100.h"
|
||||
#include "w5100Wrapper.h"
|
||||
|
||||
extern "C"{
|
||||
|
||||
CSnMR * CSnMR_new(){
|
||||
SnMR* s = new SnMR();
|
||||
return (CSnMR*)s;
|
||||
}
|
||||
void CSnMR_delete(const CSnMR* obj){
|
||||
SnMR* s = (SnMR*)obj;
|
||||
delete s;
|
||||
}
|
||||
uint8_t SnMR_CLOSE(){ return SnMR::CLOSE; }
|
||||
uint8_t SnMR_UDP(){ return SnMR::UDP; }
|
||||
uint8_t SnMR_TCP(){ return SnMR::TCP; }
|
||||
uint8_t SnMR_IPRAW(){ return SnMR::IPRAW; }
|
||||
uint8_t SnMR_MACRAW(){ return SnMR::MACRAW; }
|
||||
uint8_t SnMR_PPPOE(){ return SnMR::PPPOE; }
|
||||
uint8_t SnMR_ND(){ return SnMR::ND; }
|
||||
uint8_t SnMR_MULTI(){ return SnMR::MULTI; }
|
||||
|
||||
CSnIR * CSnIR_new(){
|
||||
SnIR* s = new SnIR();
|
||||
return (CSnIR*) s;
|
||||
}
|
||||
void CSnIR_delete(const CSnIR* obj){
|
||||
SnIR* s = (SnIR*)obj;
|
||||
delete s;
|
||||
}
|
||||
uint8_t SnIR_SEND_OK(){ return SnIR::SEND_OK; }
|
||||
uint8_t SnIR_TIMEOUT(){ return SnIR::TIMEOUT; }
|
||||
uint8_t SnIR_RECV(){ return SnIR::RECV; }
|
||||
uint8_t SnIR_DISCON(){ return SnIR::DISCON; }
|
||||
uint8_t SnIR_CON(){ return SnIR::CON; }
|
||||
|
||||
CSnSR * CSnSR_new(){
|
||||
SnSR* s = new SnSR();
|
||||
return (CSnSR*) s;
|
||||
}
|
||||
void CSnSR_delete(const CSnSR* obj){
|
||||
SnSR* s = (SnSR*)obj;
|
||||
delete s;
|
||||
}
|
||||
uint8_t SnSR_CLOSED(){ return SnSR::CLOSED; }
|
||||
uint8_t SnSR_INIT(){ return SnSR::INIT; }
|
||||
uint8_t SnSR_LISTEN(){ return SnSR::LISTEN; }
|
||||
uint8_t SnSR_SYNSENT(){ return SnSR::SYNSENT; }
|
||||
uint8_t SnSR_SYNRECV(){ return SnSR::SYNRECV; }
|
||||
uint8_t SnSR_ESTABLISHED(){ return SnSR::ESTABLISHED; }
|
||||
uint8_t SnSR_FIN_WAIT(){ return SnSR::FIN_WAIT; }
|
||||
uint8_t SnSR_CLOSING(){ return SnSR::CLOSING; }
|
||||
uint8_t SnSR_TIME_WAIT(){ return SnSR::TIME_WAIT; }
|
||||
uint8_t SnSR_CLOSE_WAIT(){ return SnSR::CLOSE_WAIT; }
|
||||
uint8_t SnSR_LAST_ACK(){ return SnSR::LAST_ACK; }
|
||||
uint8_t SnSR_UDP(){ return SnSR::UDP; }
|
||||
uint8_t SnSR_IPRAW(){ return SnSR::IPRAW; }
|
||||
uint8_t SnSR_MACRAW(){ return SnSR::MACRAW; }
|
||||
uint8_t SnSR_PPPOE(){ return SnSR::PPPOE; }
|
||||
|
||||
CIPPROTO * CIPPROTO_new(){
|
||||
IPPROTO* i = new IPPROTO();
|
||||
return (CIPPROTO*) i;
|
||||
}
|
||||
void CIPPROTO_delete(const CIPPROTO* obj){
|
||||
IPPROTO* i = (IPPROTO*) obj;
|
||||
delete i;
|
||||
}
|
||||
uint8_t IPPROTO_IP(){ return IPPROTO::IP; }
|
||||
uint8_t IPPROTO_ICMP(){ return IPPROTO::ICMP; }
|
||||
uint8_t IPPROTO_IGMP(){ return IPPROTO::IGMP; }
|
||||
uint8_t IPPROTO_GGP(){ return IPPROTO::GGP; }
|
||||
uint8_t IPPROTO_TCP(){ return IPPROTO::TCP; }
|
||||
uint8_t IPPROTO_PUP(){ return IPPROTO::PUP; }
|
||||
uint8_t IPPROTO_UDP(){ return IPPROTO::UDP; }
|
||||
uint8_t IPPROTO_IDP(){ return IPPROTO::IDP; }
|
||||
uint8_t IPPROTO_ND(){ return IPPROTO::ND; }
|
||||
uint8_t IPPROTO_RAW(){ return IPPROTO::RAW; }
|
||||
|
||||
CW5100Class * CW5100Class_new(){
|
||||
return (CW5100Class*) &W5100;
|
||||
}
|
||||
|
||||
void init_func(const CW5100Class * obj){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->init();
|
||||
}
|
||||
|
||||
void read_data_func(const CW5100Class * obj, SOCKET s, volatile uint8_t * src, volatile uint8_t * dst,
|
||||
uint16_t len){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->read_data(s, src, dst, len);
|
||||
}
|
||||
|
||||
void send_data_processing_func(const CW5100Class * obj, SOCKET s, const uint8_t *data, uint16_t len){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->send_data_processing(s, data, len);
|
||||
}
|
||||
void send_data_processing_offset_func(const CW5100Class * obj, SOCKET s, uint16_t data_offset,
|
||||
const uint8_t *data, uint16_t len){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->send_data_processing_offset(s, data_offset, data, len);
|
||||
}
|
||||
//FIXME: Removed defaul value of 0(zero) from the peek argument
|
||||
void recv_data_processing_func(const CW5100Class * obj, SOCKET s, uint8_t *data, uint16_t len,
|
||||
uint8_t peek){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->recv_data_processing(s, data, len, peek);
|
||||
}
|
||||
void setGatewayIp_func(const CW5100Class * obj, uint8_t *_addr){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->setGatewayIp(_addr);
|
||||
}
|
||||
void getGatewayIp_func(const CW5100Class * obj, uint8_t *_addr){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->getGatewayIp(_addr);
|
||||
}
|
||||
|
||||
void setSubnetMask_func(const CW5100Class * obj, uint8_t *_addr){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->setSubnetMask(_addr);
|
||||
}
|
||||
void getSubnetMask_func(const CW5100Class * obj, uint8_t *_addr){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->getSubnetMask(_addr);
|
||||
}
|
||||
|
||||
void setMACAddress_func(const CW5100Class * obj, uint8_t * addr){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->setMACAddress(addr);
|
||||
}
|
||||
void getMACAddress_func(const CW5100Class * obj, uint8_t * addr){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->getMACAddress(addr);
|
||||
}
|
||||
void setIPAddress_func(const CW5100Class * obj, uint8_t * addr){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->setIPAddress(addr);
|
||||
}
|
||||
void getIPAddress_func(const CW5100Class * obj, uint8_t * addr){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->getIPAddress(addr);
|
||||
}
|
||||
void setRetransmissionTime_func(const CW5100Class * obj, uint16_t timeout){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->setRetransmissionTime(timeout);
|
||||
}
|
||||
void setRetransmissionCount_func(const CW5100Class * obj, uint8_t _retry){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
w->setRetransmissionCount(_retry);
|
||||
}
|
||||
|
||||
uint16_t getTXFreeSize_func(const CW5100Class * obj,SOCKET s){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
return w->getTXFreeSize(s);
|
||||
}
|
||||
uint16_t getRXReceivedSize_func(const CW5100Class * obj,SOCKET s){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
return w->getRXReceivedSize(s);
|
||||
}
|
||||
|
||||
uint8_t readSnSR_func(const CW5100Class* obj, SOCKET s){
|
||||
W5100Class* w = (W5100Class*) obj;
|
||||
return w->readSnSR(s);
|
||||
}
|
||||
|
||||
}//externC
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
#ifndef Arduino_h
|
||||
#define Arduino_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "binary.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HIGH 0x1
|
||||
#define LOW 0x0
|
||||
|
||||
#define INPUT 0x0
|
||||
#define OUTPUT 0x1
|
||||
#define INPUT_PULLUP 0x2
|
||||
|
||||
#define true 0x1
|
||||
#define false 0x0
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
|
||||
#define SERIAL 0x0
|
||||
#define DISPLAY 0x1
|
||||
|
||||
#define LSBFIRST 0
|
||||
#define MSBFIRST 1
|
||||
|
||||
#define CHANGE 1
|
||||
#define FALLING 2
|
||||
#define RISING 3
|
||||
|
||||
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
#define DEFAULT 0
|
||||
#define EXTERNAL 1
|
||||
#define INTERNAL 2
|
||||
#else
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||
#define INTERNAL1V1 2
|
||||
#define INTERNAL2V56 3
|
||||
#else
|
||||
#define INTERNAL 3
|
||||
#endif
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
#endif
|
||||
|
||||
// undefine stdlib's abs if encountered
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define interrupts() sei()
|
||||
#define noInterrupts() cli()
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||
|
||||
|
||||
typedef unsigned int word;
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef uint8_t boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
void init(void);
|
||||
|
||||
void pinMode(uint8_t,
|
||||
uint8_t);
|
||||
void digitalWrite(uint8_t,
|
||||
uint8_t);
|
||||
int digitalRead(uint8_t);
|
||||
int analogRead(uint8_t);
|
||||
void analogReference(uint8_t mode);
|
||||
void analogWrite(uint8_t,
|
||||
int);
|
||||
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
void delay(unsigned long);
|
||||
void delayMicroseconds(unsigned int us);
|
||||
unsigned long pulseIn(uint8_t pin,
|
||||
uint8_t state,
|
||||
unsigned long timeout);
|
||||
|
||||
void shiftOut(uint8_t dataPin,
|
||||
uint8_t clockPin,
|
||||
uint8_t bitOrder,
|
||||
uint8_t val);
|
||||
uint8_t shiftIn(uint8_t dataPin,
|
||||
uint8_t clockPin,
|
||||
uint8_t bitOrder);
|
||||
|
||||
void attachInterrupt(uint8_t,
|
||||
void (*)(void),
|
||||
int mode);
|
||||
void detachInterrupt(uint8_t);
|
||||
|
||||
void setup(void);
|
||||
void loop(void);
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
|
||||
#define analogInPinToBit(P) (P)
|
||||
|
||||
// On the ATmega1280, the addresses of some of the port registers are
|
||||
// greater than 255, so we can't store them in uint8_t's.
|
||||
extern const uint16_t PROGMEM port_to_mode_PGM[];
|
||||
extern const uint16_t PROGMEM port_to_input_PGM[];
|
||||
extern const uint16_t PROGMEM port_to_output_PGM[];
|
||||
|
||||
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
|
||||
// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
|
||||
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
|
||||
|
||||
// Get the bit location within the hardware port of the given virtual pin.
|
||||
// This comes from the pins_*.c file for the active board configuration.
|
||||
//
|
||||
// These perform slightly better as macros compared to inline functions
|
||||
//
|
||||
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
|
||||
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
|
||||
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
|
||||
#define analogInPinToBit(P) (P)
|
||||
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
|
||||
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
|
||||
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
|
||||
|
||||
#define NOT_A_PIN 0
|
||||
#define NOT_A_PORT 0
|
||||
|
||||
#ifdef ARDUINO_MAIN
|
||||
#define PA 1
|
||||
#define PB 2
|
||||
#define PC 3
|
||||
#define PD 4
|
||||
#define PE 5
|
||||
#define PF 6
|
||||
#define PG 7
|
||||
#define PH 8
|
||||
#define PJ 10
|
||||
#define PK 11
|
||||
#define PL 12
|
||||
#endif
|
||||
|
||||
#define NOT_ON_TIMER 0
|
||||
#define TIMER0A 1
|
||||
#define TIMER0B 2
|
||||
#define TIMER1A 3
|
||||
#define TIMER1B 4
|
||||
#define TIMER2 5
|
||||
#define TIMER2A 6
|
||||
#define TIMER2B 7
|
||||
|
||||
#define TIMER3A 8
|
||||
#define TIMER3B 9
|
||||
#define TIMER3C 10
|
||||
#define TIMER4A 11
|
||||
#define TIMER4B 12
|
||||
#define TIMER4C 13
|
||||
#define TIMER4D 14
|
||||
#define TIMER5A 15
|
||||
#define TIMER5B 16
|
||||
#define TIMER5C 17
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
#include "WCharacter.h"
|
||||
#include "WString.h"
|
||||
#include "HardwareSerial.h"
|
||||
uint16_t makeWord(uint16_t w);
|
||||
uint16_t makeWord(byte h,
|
||||
byte l);
|
||||
|
||||
#define word(...) makeWord(__VA_ARGS__)
|
||||
|
||||
unsigned long pulseIn(uint8_t pin,
|
||||
uint8_t state,
|
||||
unsigned long timeout = 1000000L);
|
||||
|
||||
void tone(uint8_t _pin,
|
||||
unsigned int frequency,
|
||||
unsigned long duration = 0);
|
||||
void noTone(uint8_t _pin);
|
||||
|
||||
// WMath prototypes
|
||||
long random(long);
|
||||
long random(long,
|
||||
long);
|
||||
void randomSeed(unsigned int);
|
||||
long map(long,
|
||||
long,
|
||||
long,
|
||||
long,
|
||||
long);
|
||||
|
||||
#endif
|
||||
|
||||
#include "pins_arduino.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
HardwareSerial.h - Hardware serial library for Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
Modified 14 August 2012 by Alarus
|
||||
*/
|
||||
|
||||
#ifndef HardwareSerial_h
|
||||
#define HardwareSerial_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
struct ring_buffer;
|
||||
|
||||
class HardwareSerial:public Stream {
|
||||
private:
|
||||
ring_buffer * _rx_buffer;
|
||||
ring_buffer *_tx_buffer;
|
||||
volatile uint8_t *_ubrrh;
|
||||
volatile uint8_t *_ubrrl;
|
||||
volatile uint8_t *_ucsra;
|
||||
volatile uint8_t *_ucsrb;
|
||||
volatile uint8_t *_ucsrc;
|
||||
volatile uint8_t *_udr;
|
||||
uint8_t _rxen;
|
||||
uint8_t _txen;
|
||||
uint8_t _rxcie;
|
||||
uint8_t _udrie;
|
||||
uint8_t _u2x;
|
||||
bool transmitting;
|
||||
public:
|
||||
HardwareSerial(ring_buffer * rx_buffer,
|
||||
ring_buffer * tx_buffer,
|
||||
volatile uint8_t * ubrrh,
|
||||
volatile uint8_t * ubrrl,
|
||||
volatile uint8_t * ucsra,
|
||||
volatile uint8_t * ucsrb,
|
||||
volatile uint8_t * ucsrc,
|
||||
volatile uint8_t * udr,
|
||||
uint8_t rxen,
|
||||
uint8_t txen,
|
||||
uint8_t rxcie,
|
||||
uint8_t udrie,
|
||||
uint8_t u2x);
|
||||
void begin(unsigned long);
|
||||
void begin(unsigned long,
|
||||
uint8_t);
|
||||
void end();
|
||||
virtual int available(void);
|
||||
virtual int peek(void);
|
||||
virtual int read(void);
|
||||
virtual void flush(void);
|
||||
virtual size_t write(uint8_t);
|
||||
inline size_t write(unsigned long n) {
|
||||
return write((uint8_t) n);
|
||||
} inline size_t write(long n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n) {
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
operator bool();
|
||||
};
|
||||
|
||||
// Define config for Serial.begin(baud, config);
|
||||
#define SERIAL_5N1 0x00
|
||||
#define SERIAL_6N1 0x02
|
||||
#define SERIAL_7N1 0x04
|
||||
#define SERIAL_8N1 0x06
|
||||
#define SERIAL_5N2 0x08
|
||||
#define SERIAL_6N2 0x0A
|
||||
#define SERIAL_7N2 0x0C
|
||||
#define SERIAL_8N2 0x0E
|
||||
#define SERIAL_5E1 0x20
|
||||
#define SERIAL_6E1 0x22
|
||||
#define SERIAL_7E1 0x24
|
||||
#define SERIAL_8E1 0x26
|
||||
#define SERIAL_5E2 0x28
|
||||
#define SERIAL_6E2 0x2A
|
||||
#define SERIAL_7E2 0x2C
|
||||
#define SERIAL_8E2 0x2E
|
||||
#define SERIAL_5O1 0x30
|
||||
#define SERIAL_6O1 0x32
|
||||
#define SERIAL_7O1 0x34
|
||||
#define SERIAL_8O1 0x36
|
||||
#define SERIAL_5O2 0x38
|
||||
#define SERIAL_6O2 0x3A
|
||||
#define SERIAL_7O2 0x3C
|
||||
#define SERIAL_8O2 0x3E
|
||||
|
||||
#if defined(UBRRH) || defined(UBRR0H)
|
||||
extern HardwareSerial Serial;
|
||||
#elif defined(USBCON)
|
||||
#include "USBAPI.h"
|
||||
// extern HardwareSerial Serial_;
|
||||
#endif
|
||||
#if defined(UBRR1H)
|
||||
extern HardwareSerial Serial1;
|
||||
#endif
|
||||
#if defined(UBRR2H)
|
||||
extern HardwareSerial Serial2;
|
||||
#endif
|
||||
#if defined(UBRR3H)
|
||||
extern HardwareSerial Serial3;
|
||||
#endif
|
||||
|
||||
extern void serialEventRun(void) __attribute__ ((weak));
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef server_h
|
||||
#define server_h
|
||||
|
||||
class Server:public Print {
|
||||
public:
|
||||
virtual void begin() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
|
||||
#ifndef __USBAPI__
|
||||
#define __USBAPI__
|
||||
|
||||
#if defined(USBCON)
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// USB
|
||||
|
||||
class USBDevice_ {
|
||||
public:
|
||||
USBDevice_();
|
||||
bool configured();
|
||||
|
||||
void attach();
|
||||
void detach(); // Serial port goes down too...
|
||||
void poll();
|
||||
};
|
||||
extern USBDevice_ USBDevice;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Serial over CDC (Serial1 is the physical port)
|
||||
|
||||
class Serial_:public Stream {
|
||||
private:
|
||||
ring_buffer * _cdc_rx_buffer;
|
||||
public:
|
||||
void begin(uint16_t baud_count);
|
||||
void end(void);
|
||||
|
||||
virtual int available(void);
|
||||
virtual void accept(void);
|
||||
virtual int peek(void);
|
||||
virtual int read(void);
|
||||
virtual void flush(void);
|
||||
virtual size_t write(uint8_t);
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
operator bool();
|
||||
};
|
||||
extern Serial_ Serial;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Mouse
|
||||
|
||||
#define MOUSE_LEFT 1
|
||||
#define MOUSE_RIGHT 2
|
||||
#define MOUSE_MIDDLE 4
|
||||
#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)
|
||||
|
||||
class Mouse_ {
|
||||
private:
|
||||
uint8_t _buttons;
|
||||
void buttons(uint8_t b);
|
||||
public:
|
||||
Mouse_(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
void click(uint8_t b = MOUSE_LEFT);
|
||||
void move(signed char x,
|
||||
signed char y,
|
||||
signed char wheel = 0);
|
||||
void press(uint8_t b = MOUSE_LEFT); // press LEFT by default
|
||||
void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
|
||||
bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default
|
||||
};
|
||||
extern Mouse_ Mouse;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Keyboard
|
||||
|
||||
#define KEY_LEFT_CTRL 0x80
|
||||
#define KEY_LEFT_SHIFT 0x81
|
||||
#define KEY_LEFT_ALT 0x82
|
||||
#define KEY_LEFT_GUI 0x83
|
||||
#define KEY_RIGHT_CTRL 0x84
|
||||
#define KEY_RIGHT_SHIFT 0x85
|
||||
#define KEY_RIGHT_ALT 0x86
|
||||
#define KEY_RIGHT_GUI 0x87
|
||||
|
||||
#define KEY_UP_ARROW 0xDA
|
||||
#define KEY_DOWN_ARROW 0xD9
|
||||
#define KEY_LEFT_ARROW 0xD8
|
||||
#define KEY_RIGHT_ARROW 0xD7
|
||||
#define KEY_BACKSPACE 0xB2
|
||||
#define KEY_TAB 0xB3
|
||||
#define KEY_RETURN 0xB0
|
||||
#define KEY_ESC 0xB1
|
||||
#define KEY_INSERT 0xD1
|
||||
#define KEY_DELETE 0xD4
|
||||
#define KEY_PAGE_UP 0xD3
|
||||
#define KEY_PAGE_DOWN 0xD6
|
||||
#define KEY_HOME 0xD2
|
||||
#define KEY_END 0xD5
|
||||
#define KEY_CAPS_LOCK 0xC1
|
||||
#define KEY_F1 0xC2
|
||||
#define KEY_F2 0xC3
|
||||
#define KEY_F3 0xC4
|
||||
#define KEY_F4 0xC5
|
||||
#define KEY_F5 0xC6
|
||||
#define KEY_F6 0xC7
|
||||
#define KEY_F7 0xC8
|
||||
#define KEY_F8 0xC9
|
||||
#define KEY_F9 0xCA
|
||||
#define KEY_F10 0xCB
|
||||
#define KEY_F11 0xCC
|
||||
#define KEY_F12 0xCD
|
||||
|
||||
// Low level key report: up to 6 keys and shift, ctrl etc at once
|
||||
typedef struct {
|
||||
uint8_t modifiers;
|
||||
uint8_t reserved;
|
||||
uint8_t keys[6];
|
||||
} KeyReport;
|
||||
|
||||
class Keyboard_:public Print {
|
||||
private:
|
||||
KeyReport _keyReport;
|
||||
void sendReport(KeyReport * keys);
|
||||
public:
|
||||
Keyboard_(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
virtual size_t write(uint8_t k);
|
||||
virtual size_t press(uint8_t k);
|
||||
virtual size_t release(uint8_t k);
|
||||
virtual void releaseAll(void);
|
||||
};
|
||||
extern Keyboard_ Keyboard;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// Low level API
|
||||
|
||||
typedef struct {
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint8_t wValueL;
|
||||
uint8_t wValueH;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} Setup;
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// HID 'Driver'
|
||||
|
||||
int HID_GetInterface(uint8_t * interfaceNum);
|
||||
int HID_GetDescriptor(int i);
|
||||
bool HID_Setup(Setup & setup);
|
||||
void HID_SendReport(uint8_t id,
|
||||
const void *data,
|
||||
int len);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// MSC 'Driver'
|
||||
|
||||
int MSC_GetInterface(uint8_t * interfaceNum);
|
||||
int MSC_GetDescriptor(int i);
|
||||
bool MSC_Setup(Setup & setup);
|
||||
bool MSC_Data(uint8_t rx,
|
||||
uint8_t tx);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
// CSC 'Driver'
|
||||
|
||||
int CDC_GetInterface(uint8_t * interfaceNum);
|
||||
int CDC_GetDescriptor(int i);
|
||||
bool CDC_Setup(Setup & setup);
|
||||
|
||||
//================================================================================
|
||||
//================================================================================
|
||||
|
||||
#define TRANSFER_PGM 0x80
|
||||
#define TRANSFER_RELEASE 0x40
|
||||
#define TRANSFER_ZERO 0x20
|
||||
|
||||
int USB_SendControl(uint8_t flags,
|
||||
const void *d,
|
||||
int len);
|
||||
int USB_RecvControl(void *d,
|
||||
int len);
|
||||
|
||||
uint8_t USB_Available(uint8_t ep);
|
||||
int USB_Send(uint8_t ep,
|
||||
const void *data,
|
||||
int len); // blocking
|
||||
int USB_Recv(uint8_t ep,
|
||||
void *data,
|
||||
int len); // non-blocking
|
||||
int USB_Recv(uint8_t ep); // non-blocking
|
||||
void USB_Flush(uint8_t ep);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* if defined(USBCON) */
|
||||
@@ -0,0 +1,292 @@
|
||||
|
||||
// Copyright (c) 2010, Peter Barrett
|
||||
/*
|
||||
** Permission to use, copy, modify, and/or distribute this software for
|
||||
** any purpose with or without fee is hereby granted, provided that the
|
||||
** above copyright notice and this permission notice appear in all copies.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
** SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __USBCORE_H__
|
||||
#define __USBCORE_H__
|
||||
|
||||
// Standard requests
|
||||
#define GET_STATUS 0
|
||||
#define CLEAR_FEATURE 1
|
||||
#define SET_FEATURE 3
|
||||
#define SET_ADDRESS 5
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_DESCRIPTOR 7
|
||||
#define GET_CONFIGURATION 8
|
||||
#define SET_CONFIGURATION 9
|
||||
#define GET_INTERFACE 10
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
|
||||
// bmRequestType
|
||||
#define REQUEST_HOSTTODEVICE 0x00
|
||||
#define REQUEST_DEVICETOHOST 0x80
|
||||
#define REQUEST_DIRECTION 0x80
|
||||
|
||||
#define REQUEST_STANDARD 0x00
|
||||
#define REQUEST_CLASS 0x20
|
||||
#define REQUEST_VENDOR 0x40
|
||||
#define REQUEST_TYPE 0x60
|
||||
|
||||
#define REQUEST_DEVICE 0x00
|
||||
#define REQUEST_INTERFACE 0x01
|
||||
#define REQUEST_ENDPOINT 0x02
|
||||
#define REQUEST_OTHER 0x03
|
||||
#define REQUEST_RECIPIENT 0x03
|
||||
|
||||
#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST + REQUEST_CLASS + REQUEST_INTERFACE)
|
||||
#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE + REQUEST_CLASS + REQUEST_INTERFACE)
|
||||
|
||||
// Class requests
|
||||
|
||||
#define CDC_SET_LINE_CODING 0x20
|
||||
#define CDC_GET_LINE_CODING 0x21
|
||||
#define CDC_SET_CONTROL_LINE_STATE 0x22
|
||||
|
||||
#define MSC_RESET 0xFF
|
||||
#define MSC_GET_MAX_LUN 0xFE
|
||||
|
||||
#define HID_GET_REPORT 0x01
|
||||
#define HID_GET_IDLE 0x02
|
||||
#define HID_GET_PROTOCOL 0x03
|
||||
#define HID_SET_REPORT 0x09
|
||||
#define HID_SET_IDLE 0x0A
|
||||
#define HID_SET_PROTOCOL 0x0B
|
||||
|
||||
// Descriptors
|
||||
|
||||
#define USB_DEVICE_DESC_SIZE 18
|
||||
#define USB_CONFIGUARTION_DESC_SIZE 9
|
||||
#define USB_INTERFACE_DESC_SIZE 9
|
||||
#define USB_ENDPOINT_DESC_SIZE 7
|
||||
|
||||
#define USB_DEVICE_DESCRIPTOR_TYPE 1
|
||||
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2
|
||||
#define USB_STRING_DESCRIPTOR_TYPE 3
|
||||
#define USB_INTERFACE_DESCRIPTOR_TYPE 4
|
||||
#define USB_ENDPOINT_DESCRIPTOR_TYPE 5
|
||||
|
||||
#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
|
||||
#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
|
||||
#define USB_DEVICE_CLASS_STORAGE 0x08
|
||||
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
|
||||
|
||||
#define USB_CONFIG_POWERED_MASK 0x40
|
||||
#define USB_CONFIG_BUS_POWERED 0x80
|
||||
#define USB_CONFIG_SELF_POWERED 0xC0
|
||||
#define USB_CONFIG_REMOTE_WAKEUP 0x20
|
||||
|
||||
// bMaxPower in Configuration Descriptor
|
||||
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
|
||||
|
||||
// bEndpointAddress in Endpoint Descriptor
|
||||
#define USB_ENDPOINT_DIRECTION_MASK 0x80
|
||||
#define USB_ENDPOINT_OUT(addr) ((addr) | 0x00)
|
||||
#define USB_ENDPOINT_IN(addr) ((addr) | 0x80)
|
||||
|
||||
#define USB_ENDPOINT_TYPE_MASK 0x03
|
||||
#define USB_ENDPOINT_TYPE_CONTROL 0x00
|
||||
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
|
||||
#define USB_ENDPOINT_TYPE_BULK 0x02
|
||||
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF)
|
||||
|
||||
#define CDC_V1_10 0x0110
|
||||
#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02
|
||||
|
||||
#define CDC_CALL_MANAGEMENT 0x01
|
||||
#define CDC_ABSTRACT_CONTROL_MODEL 0x02
|
||||
#define CDC_HEADER 0x00
|
||||
#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02
|
||||
#define CDC_UNION 0x06
|
||||
#define CDC_CS_INTERFACE 0x24
|
||||
#define CDC_CS_ENDPOINT 0x25
|
||||
#define CDC_DATA_INTERFACE_CLASS 0x0A
|
||||
|
||||
#define MSC_SUBCLASS_SCSI 0x06
|
||||
#define MSC_PROTOCOL_BULK_ONLY 0x50
|
||||
|
||||
#define HID_HID_DESCRIPTOR_TYPE 0x21
|
||||
#define HID_REPORT_DESCRIPTOR_TYPE 0x22
|
||||
#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23
|
||||
|
||||
|
||||
// Device
|
||||
typedef struct {
|
||||
u8 len; // 18
|
||||
u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE
|
||||
u16 usbVersion; // 0x200
|
||||
u8 deviceClass;
|
||||
u8 deviceSubClass;
|
||||
u8 deviceProtocol;
|
||||
u8 packetSize0; // Packet 0
|
||||
u16 idVendor;
|
||||
u16 idProduct;
|
||||
u16 deviceVersion; // 0x100
|
||||
u8 iManufacturer;
|
||||
u8 iProduct;
|
||||
u8 iSerialNumber;
|
||||
u8 bNumConfigurations;
|
||||
} DeviceDescriptor;
|
||||
|
||||
// Config
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 2
|
||||
u16 clen; // total length
|
||||
u8 numInterfaces;
|
||||
u8 config;
|
||||
u8 iconfig;
|
||||
u8 attributes;
|
||||
u8 maxPower;
|
||||
} ConfigDescriptor;
|
||||
|
||||
// String
|
||||
|
||||
// Interface
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 4
|
||||
u8 number;
|
||||
u8 alternate;
|
||||
u8 numEndpoints;
|
||||
u8 interfaceClass;
|
||||
u8 interfaceSubClass;
|
||||
u8 protocol;
|
||||
u8 iInterface;
|
||||
} InterfaceDescriptor;
|
||||
|
||||
// Endpoint
|
||||
typedef struct {
|
||||
u8 len; // 7
|
||||
u8 dtype; // 5
|
||||
u8 addr;
|
||||
u8 attr;
|
||||
u16 packetSize;
|
||||
u8 interval;
|
||||
} EndpointDescriptor;
|
||||
|
||||
// Interface Association Descriptor
|
||||
// Used to bind 2 interfaces together in CDC compostite device
|
||||
typedef struct {
|
||||
u8 len; // 8
|
||||
u8 dtype; // 11
|
||||
u8 firstInterface;
|
||||
u8 interfaceCount;
|
||||
u8 functionClass;
|
||||
u8 funtionSubClass;
|
||||
u8 functionProtocol;
|
||||
u8 iInterface;
|
||||
} IADDescriptor;
|
||||
|
||||
// CDC CS interface descriptor
|
||||
typedef struct {
|
||||
u8 len; // 5
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype;
|
||||
u8 d0;
|
||||
u8 d1;
|
||||
} CDCCSInterfaceDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len; // 4
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype;
|
||||
u8 d0;
|
||||
} CDCCSInterfaceDescriptor4;
|
||||
|
||||
typedef struct {
|
||||
u8 len;
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype; // 1
|
||||
u8 bmCapabilities;
|
||||
u8 bDataInterface;
|
||||
} CMFunctionalDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len;
|
||||
u8 dtype; // 0x24
|
||||
u8 subtype; // 1
|
||||
u8 bmCapabilities;
|
||||
} ACMFunctionalDescriptor;
|
||||
|
||||
typedef struct {
|
||||
// IAD
|
||||
IADDescriptor iad; // Only needed on compound device
|
||||
|
||||
// Control
|
||||
InterfaceDescriptor cif; //
|
||||
CDCCSInterfaceDescriptor header;
|
||||
CMFunctionalDescriptor callManagement; // Call Management
|
||||
ACMFunctionalDescriptor controlManagement; // ACM
|
||||
CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION
|
||||
EndpointDescriptor cifin;
|
||||
|
||||
// Data
|
||||
InterfaceDescriptor dif;
|
||||
EndpointDescriptor in;
|
||||
EndpointDescriptor out;
|
||||
} CDCDescriptor;
|
||||
|
||||
typedef struct {
|
||||
InterfaceDescriptor msc;
|
||||
EndpointDescriptor in;
|
||||
EndpointDescriptor out;
|
||||
} MSCDescriptor;
|
||||
|
||||
typedef struct {
|
||||
u8 len; // 9
|
||||
u8 dtype; // 0x21
|
||||
u8 addr;
|
||||
u8 versionL; // 0x101
|
||||
u8 versionH; // 0x101
|
||||
u8 country;
|
||||
u8 desctype; // 0x22 report
|
||||
u8 descLenL;
|
||||
u8 descLenH;
|
||||
} HIDDescDescriptor;
|
||||
|
||||
typedef struct {
|
||||
InterfaceDescriptor hid;
|
||||
HIDDescDescriptor desc;
|
||||
EndpointDescriptor in;
|
||||
} HIDDescriptor;
|
||||
|
||||
|
||||
#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \
|
||||
{ 18, 1, 0x200, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs }
|
||||
|
||||
#define D_CONFIG(_totalLength,_interfaces) \
|
||||
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED, USB_CONFIG_POWER_MA(500) }
|
||||
|
||||
#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \
|
||||
{ 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 }
|
||||
|
||||
#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \
|
||||
{ 7, 5, _addr,_attr,_packetSize, _interval }
|
||||
|
||||
#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \
|
||||
{ 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 }
|
||||
|
||||
#define D_HIDREPORT(_descriptorLength) \
|
||||
{ 9, 0x21, 0x1, 0x1, 0, 1, 0x22, _descriptorLength, 0 }
|
||||
|
||||
#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 }
|
||||
#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 }
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Udp.cpp: Library to send/receive UDP packets.
|
||||
*
|
||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
* might not happen often in practice, but in larger network topologies, a UDP
|
||||
* packet can be received out of sequence.
|
||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* 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.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#ifndef udp_h
|
||||
#define udp_h
|
||||
|
||||
#include <Stream.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
class UDP:public Stream {
|
||||
|
||||
public:
|
||||
virtual uint8_t begin(uint16_t) = 0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
|
||||
virtual void stop() = 0; // Finish with the UDP socket
|
||||
|
||||
// Sending UDP packets
|
||||
|
||||
// Start building up a packet to send to the remote host specific in ip and port
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
virtual int beginPacket(IPAddress ip,
|
||||
uint16_t port) = 0;
|
||||
// Start building up a packet to send to the remote host specific in host and port
|
||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||
virtual int beginPacket(const char *host,
|
||||
uint16_t port) = 0;
|
||||
// Finish off this packet and send it
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
virtual int endPacket() = 0;
|
||||
// Write a single byte into the packet
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
// Write size bytes from buffer into the packet
|
||||
virtual size_t write(const uint8_t * buffer,
|
||||
size_t size) = 0;
|
||||
|
||||
// Start processing the next available incoming packet
|
||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||
virtual int parsePacket() = 0;
|
||||
// Number of bytes remaining in the current packet
|
||||
virtual int available() = 0;
|
||||
// Read a single byte from the current packet
|
||||
virtual int read() = 0;
|
||||
// Read up to len bytes from the current packet and place them into buffer
|
||||
// Returns the number of bytes read, or 0 if none are available
|
||||
virtual int read(unsigned char *buffer,
|
||||
size_t len) = 0;
|
||||
// Read up to len characters from the current packet and place them into buffer
|
||||
// Returns the number of characters read, or 0 if none are available
|
||||
virtual int read(char *buffer,
|
||||
size_t len) = 0;
|
||||
// Return the next byte from the current packet without moving on to the next byte
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0; // Finish reading the current packet
|
||||
|
||||
// Return the IP address of the host who sent the current incoming packet
|
||||
virtual IPAddress remoteIP() = 0;
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
virtual uint16_t remotePort() = 0;
|
||||
protected:
|
||||
uint8_t * rawIPAddress(IPAddress & addr) {
|
||||
return addr.raw_address();
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,515 @@
|
||||
#ifndef Binary_h
|
||||
#define Binary_h
|
||||
|
||||
#define B0 0
|
||||
#define B00 0
|
||||
#define B000 0
|
||||
#define B0000 0
|
||||
#define B00000 0
|
||||
#define B000000 0
|
||||
#define B0000000 0
|
||||
#define B00000000 0
|
||||
#define B1 1
|
||||
#define B01 1
|
||||
#define B001 1
|
||||
#define B0001 1
|
||||
#define B00001 1
|
||||
#define B000001 1
|
||||
#define B0000001 1
|
||||
#define B00000001 1
|
||||
#define B10 2
|
||||
#define B010 2
|
||||
#define B0010 2
|
||||
#define B00010 2
|
||||
#define B000010 2
|
||||
#define B0000010 2
|
||||
#define B00000010 2
|
||||
#define B11 3
|
||||
#define B011 3
|
||||
#define B0011 3
|
||||
#define B00011 3
|
||||
#define B000011 3
|
||||
#define B0000011 3
|
||||
#define B00000011 3
|
||||
#define B100 4
|
||||
#define B0100 4
|
||||
#define B00100 4
|
||||
#define B000100 4
|
||||
#define B0000100 4
|
||||
#define B00000100 4
|
||||
#define B101 5
|
||||
#define B0101 5
|
||||
#define B00101 5
|
||||
#define B000101 5
|
||||
#define B0000101 5
|
||||
#define B00000101 5
|
||||
#define B110 6
|
||||
#define B0110 6
|
||||
#define B00110 6
|
||||
#define B000110 6
|
||||
#define B0000110 6
|
||||
#define B00000110 6
|
||||
#define B111 7
|
||||
#define B0111 7
|
||||
#define B00111 7
|
||||
#define B000111 7
|
||||
#define B0000111 7
|
||||
#define B00000111 7
|
||||
#define B1000 8
|
||||
#define B01000 8
|
||||
#define B001000 8
|
||||
#define B0001000 8
|
||||
#define B00001000 8
|
||||
#define B1001 9
|
||||
#define B01001 9
|
||||
#define B001001 9
|
||||
#define B0001001 9
|
||||
#define B00001001 9
|
||||
#define B1010 10
|
||||
#define B01010 10
|
||||
#define B001010 10
|
||||
#define B0001010 10
|
||||
#define B00001010 10
|
||||
#define B1011 11
|
||||
#define B01011 11
|
||||
#define B001011 11
|
||||
#define B0001011 11
|
||||
#define B00001011 11
|
||||
#define B1100 12
|
||||
#define B01100 12
|
||||
#define B001100 12
|
||||
#define B0001100 12
|
||||
#define B00001100 12
|
||||
#define B1101 13
|
||||
#define B01101 13
|
||||
#define B001101 13
|
||||
#define B0001101 13
|
||||
#define B00001101 13
|
||||
#define B1110 14
|
||||
#define B01110 14
|
||||
#define B001110 14
|
||||
#define B0001110 14
|
||||
#define B00001110 14
|
||||
#define B1111 15
|
||||
#define B01111 15
|
||||
#define B001111 15
|
||||
#define B0001111 15
|
||||
#define B00001111 15
|
||||
#define B10000 16
|
||||
#define B010000 16
|
||||
#define B0010000 16
|
||||
#define B00010000 16
|
||||
#define B10001 17
|
||||
#define B010001 17
|
||||
#define B0010001 17
|
||||
#define B00010001 17
|
||||
#define B10010 18
|
||||
#define B010010 18
|
||||
#define B0010010 18
|
||||
#define B00010010 18
|
||||
#define B10011 19
|
||||
#define B010011 19
|
||||
#define B0010011 19
|
||||
#define B00010011 19
|
||||
#define B10100 20
|
||||
#define B010100 20
|
||||
#define B0010100 20
|
||||
#define B00010100 20
|
||||
#define B10101 21
|
||||
#define B010101 21
|
||||
#define B0010101 21
|
||||
#define B00010101 21
|
||||
#define B10110 22
|
||||
#define B010110 22
|
||||
#define B0010110 22
|
||||
#define B00010110 22
|
||||
#define B10111 23
|
||||
#define B010111 23
|
||||
#define B0010111 23
|
||||
#define B00010111 23
|
||||
#define B11000 24
|
||||
#define B011000 24
|
||||
#define B0011000 24
|
||||
#define B00011000 24
|
||||
#define B11001 25
|
||||
#define B011001 25
|
||||
#define B0011001 25
|
||||
#define B00011001 25
|
||||
#define B11010 26
|
||||
#define B011010 26
|
||||
#define B0011010 26
|
||||
#define B00011010 26
|
||||
#define B11011 27
|
||||
#define B011011 27
|
||||
#define B0011011 27
|
||||
#define B00011011 27
|
||||
#define B11100 28
|
||||
#define B011100 28
|
||||
#define B0011100 28
|
||||
#define B00011100 28
|
||||
#define B11101 29
|
||||
#define B011101 29
|
||||
#define B0011101 29
|
||||
#define B00011101 29
|
||||
#define B11110 30
|
||||
#define B011110 30
|
||||
#define B0011110 30
|
||||
#define B00011110 30
|
||||
#define B11111 31
|
||||
#define B011111 31
|
||||
#define B0011111 31
|
||||
#define B00011111 31
|
||||
#define B100000 32
|
||||
#define B0100000 32
|
||||
#define B00100000 32
|
||||
#define B100001 33
|
||||
#define B0100001 33
|
||||
#define B00100001 33
|
||||
#define B100010 34
|
||||
#define B0100010 34
|
||||
#define B00100010 34
|
||||
#define B100011 35
|
||||
#define B0100011 35
|
||||
#define B00100011 35
|
||||
#define B100100 36
|
||||
#define B0100100 36
|
||||
#define B00100100 36
|
||||
#define B100101 37
|
||||
#define B0100101 37
|
||||
#define B00100101 37
|
||||
#define B100110 38
|
||||
#define B0100110 38
|
||||
#define B00100110 38
|
||||
#define B100111 39
|
||||
#define B0100111 39
|
||||
#define B00100111 39
|
||||
#define B101000 40
|
||||
#define B0101000 40
|
||||
#define B00101000 40
|
||||
#define B101001 41
|
||||
#define B0101001 41
|
||||
#define B00101001 41
|
||||
#define B101010 42
|
||||
#define B0101010 42
|
||||
#define B00101010 42
|
||||
#define B101011 43
|
||||
#define B0101011 43
|
||||
#define B00101011 43
|
||||
#define B101100 44
|
||||
#define B0101100 44
|
||||
#define B00101100 44
|
||||
#define B101101 45
|
||||
#define B0101101 45
|
||||
#define B00101101 45
|
||||
#define B101110 46
|
||||
#define B0101110 46
|
||||
#define B00101110 46
|
||||
#define B101111 47
|
||||
#define B0101111 47
|
||||
#define B00101111 47
|
||||
#define B110000 48
|
||||
#define B0110000 48
|
||||
#define B00110000 48
|
||||
#define B110001 49
|
||||
#define B0110001 49
|
||||
#define B00110001 49
|
||||
#define B110010 50
|
||||
#define B0110010 50
|
||||
#define B00110010 50
|
||||
#define B110011 51
|
||||
#define B0110011 51
|
||||
#define B00110011 51
|
||||
#define B110100 52
|
||||
#define B0110100 52
|
||||
#define B00110100 52
|
||||
#define B110101 53
|
||||
#define B0110101 53
|
||||
#define B00110101 53
|
||||
#define B110110 54
|
||||
#define B0110110 54
|
||||
#define B00110110 54
|
||||
#define B110111 55
|
||||
#define B0110111 55
|
||||
#define B00110111 55
|
||||
#define B111000 56
|
||||
#define B0111000 56
|
||||
#define B00111000 56
|
||||
#define B111001 57
|
||||
#define B0111001 57
|
||||
#define B00111001 57
|
||||
#define B111010 58
|
||||
#define B0111010 58
|
||||
#define B00111010 58
|
||||
#define B111011 59
|
||||
#define B0111011 59
|
||||
#define B00111011 59
|
||||
#define B111100 60
|
||||
#define B0111100 60
|
||||
#define B00111100 60
|
||||
#define B111101 61
|
||||
#define B0111101 61
|
||||
#define B00111101 61
|
||||
#define B111110 62
|
||||
#define B0111110 62
|
||||
#define B00111110 62
|
||||
#define B111111 63
|
||||
#define B0111111 63
|
||||
#define B00111111 63
|
||||
#define B1000000 64
|
||||
#define B01000000 64
|
||||
#define B1000001 65
|
||||
#define B01000001 65
|
||||
#define B1000010 66
|
||||
#define B01000010 66
|
||||
#define B1000011 67
|
||||
#define B01000011 67
|
||||
#define B1000100 68
|
||||
#define B01000100 68
|
||||
#define B1000101 69
|
||||
#define B01000101 69
|
||||
#define B1000110 70
|
||||
#define B01000110 70
|
||||
#define B1000111 71
|
||||
#define B01000111 71
|
||||
#define B1001000 72
|
||||
#define B01001000 72
|
||||
#define B1001001 73
|
||||
#define B01001001 73
|
||||
#define B1001010 74
|
||||
#define B01001010 74
|
||||
#define B1001011 75
|
||||
#define B01001011 75
|
||||
#define B1001100 76
|
||||
#define B01001100 76
|
||||
#define B1001101 77
|
||||
#define B01001101 77
|
||||
#define B1001110 78
|
||||
#define B01001110 78
|
||||
#define B1001111 79
|
||||
#define B01001111 79
|
||||
#define B1010000 80
|
||||
#define B01010000 80
|
||||
#define B1010001 81
|
||||
#define B01010001 81
|
||||
#define B1010010 82
|
||||
#define B01010010 82
|
||||
#define B1010011 83
|
||||
#define B01010011 83
|
||||
#define B1010100 84
|
||||
#define B01010100 84
|
||||
#define B1010101 85
|
||||
#define B01010101 85
|
||||
#define B1010110 86
|
||||
#define B01010110 86
|
||||
#define B1010111 87
|
||||
#define B01010111 87
|
||||
#define B1011000 88
|
||||
#define B01011000 88
|
||||
#define B1011001 89
|
||||
#define B01011001 89
|
||||
#define B1011010 90
|
||||
#define B01011010 90
|
||||
#define B1011011 91
|
||||
#define B01011011 91
|
||||
#define B1011100 92
|
||||
#define B01011100 92
|
||||
#define B1011101 93
|
||||
#define B01011101 93
|
||||
#define B1011110 94
|
||||
#define B01011110 94
|
||||
#define B1011111 95
|
||||
#define B01011111 95
|
||||
#define B1100000 96
|
||||
#define B01100000 96
|
||||
#define B1100001 97
|
||||
#define B01100001 97
|
||||
#define B1100010 98
|
||||
#define B01100010 98
|
||||
#define B1100011 99
|
||||
#define B01100011 99
|
||||
#define B1100100 100
|
||||
#define B01100100 100
|
||||
#define B1100101 101
|
||||
#define B01100101 101
|
||||
#define B1100110 102
|
||||
#define B01100110 102
|
||||
#define B1100111 103
|
||||
#define B01100111 103
|
||||
#define B1101000 104
|
||||
#define B01101000 104
|
||||
#define B1101001 105
|
||||
#define B01101001 105
|
||||
#define B1101010 106
|
||||
#define B01101010 106
|
||||
#define B1101011 107
|
||||
#define B01101011 107
|
||||
#define B1101100 108
|
||||
#define B01101100 108
|
||||
#define B1101101 109
|
||||
#define B01101101 109
|
||||
#define B1101110 110
|
||||
#define B01101110 110
|
||||
#define B1101111 111
|
||||
#define B01101111 111
|
||||
#define B1110000 112
|
||||
#define B01110000 112
|
||||
#define B1110001 113
|
||||
#define B01110001 113
|
||||
#define B1110010 114
|
||||
#define B01110010 114
|
||||
#define B1110011 115
|
||||
#define B01110011 115
|
||||
#define B1110100 116
|
||||
#define B01110100 116
|
||||
#define B1110101 117
|
||||
#define B01110101 117
|
||||
#define B1110110 118
|
||||
#define B01110110 118
|
||||
#define B1110111 119
|
||||
#define B01110111 119
|
||||
#define B1111000 120
|
||||
#define B01111000 120
|
||||
#define B1111001 121
|
||||
#define B01111001 121
|
||||
#define B1111010 122
|
||||
#define B01111010 122
|
||||
#define B1111011 123
|
||||
#define B01111011 123
|
||||
#define B1111100 124
|
||||
#define B01111100 124
|
||||
#define B1111101 125
|
||||
#define B01111101 125
|
||||
#define B1111110 126
|
||||
#define B01111110 126
|
||||
#define B1111111 127
|
||||
#define B01111111 127
|
||||
#define B10000000 128
|
||||
#define B10000001 129
|
||||
#define B10000010 130
|
||||
#define B10000011 131
|
||||
#define B10000100 132
|
||||
#define B10000101 133
|
||||
#define B10000110 134
|
||||
#define B10000111 135
|
||||
#define B10001000 136
|
||||
#define B10001001 137
|
||||
#define B10001010 138
|
||||
#define B10001011 139
|
||||
#define B10001100 140
|
||||
#define B10001101 141
|
||||
#define B10001110 142
|
||||
#define B10001111 143
|
||||
#define B10010000 144
|
||||
#define B10010001 145
|
||||
#define B10010010 146
|
||||
#define B10010011 147
|
||||
#define B10010100 148
|
||||
#define B10010101 149
|
||||
#define B10010110 150
|
||||
#define B10010111 151
|
||||
#define B10011000 152
|
||||
#define B10011001 153
|
||||
#define B10011010 154
|
||||
#define B10011011 155
|
||||
#define B10011100 156
|
||||
#define B10011101 157
|
||||
#define B10011110 158
|
||||
#define B10011111 159
|
||||
#define B10100000 160
|
||||
#define B10100001 161
|
||||
#define B10100010 162
|
||||
#define B10100011 163
|
||||
#define B10100100 164
|
||||
#define B10100101 165
|
||||
#define B10100110 166
|
||||
#define B10100111 167
|
||||
#define B10101000 168
|
||||
#define B10101001 169
|
||||
#define B10101010 170
|
||||
#define B10101011 171
|
||||
#define B10101100 172
|
||||
#define B10101101 173
|
||||
#define B10101110 174
|
||||
#define B10101111 175
|
||||
#define B10110000 176
|
||||
#define B10110001 177
|
||||
#define B10110010 178
|
||||
#define B10110011 179
|
||||
#define B10110100 180
|
||||
#define B10110101 181
|
||||
#define B10110110 182
|
||||
#define B10110111 183
|
||||
#define B10111000 184
|
||||
#define B10111001 185
|
||||
#define B10111010 186
|
||||
#define B10111011 187
|
||||
#define B10111100 188
|
||||
#define B10111101 189
|
||||
#define B10111110 190
|
||||
#define B10111111 191
|
||||
#define B11000000 192
|
||||
#define B11000001 193
|
||||
#define B11000010 194
|
||||
#define B11000011 195
|
||||
#define B11000100 196
|
||||
#define B11000101 197
|
||||
#define B11000110 198
|
||||
#define B11000111 199
|
||||
#define B11001000 200
|
||||
#define B11001001 201
|
||||
#define B11001010 202
|
||||
#define B11001011 203
|
||||
#define B11001100 204
|
||||
#define B11001101 205
|
||||
#define B11001110 206
|
||||
#define B11001111 207
|
||||
#define B11010000 208
|
||||
#define B11010001 209
|
||||
#define B11010010 210
|
||||
#define B11010011 211
|
||||
#define B11010100 212
|
||||
#define B11010101 213
|
||||
#define B11010110 214
|
||||
#define B11010111 215
|
||||
#define B11011000 216
|
||||
#define B11011001 217
|
||||
#define B11011010 218
|
||||
#define B11011011 219
|
||||
#define B11011100 220
|
||||
#define B11011101 221
|
||||
#define B11011110 222
|
||||
#define B11011111 223
|
||||
#define B11100000 224
|
||||
#define B11100001 225
|
||||
#define B11100010 226
|
||||
#define B11100011 227
|
||||
#define B11100100 228
|
||||
#define B11100101 229
|
||||
#define B11100110 230
|
||||
#define B11100111 231
|
||||
#define B11101000 232
|
||||
#define B11101001 233
|
||||
#define B11101010 234
|
||||
#define B11101011 235
|
||||
#define B11101100 236
|
||||
#define B11101101 237
|
||||
#define B11101110 238
|
||||
#define B11101111 239
|
||||
#define B11110000 240
|
||||
#define B11110001 241
|
||||
#define B11110010 242
|
||||
#define B11110011 243
|
||||
#define B11110100 244
|
||||
#define B11110101 245
|
||||
#define B11110110 246
|
||||
#define B11110111 247
|
||||
#define B11111000 248
|
||||
#define B11111001 249
|
||||
#define B11111010 250
|
||||
#define B11111011 251
|
||||
#define B11111100 252
|
||||
#define B11111101 253
|
||||
#define B11111110 254
|
||||
#define B11111111 255
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
/* Header to define new/delete operators as they aren't provided by avr-gcc by default
|
||||
Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453
|
||||
*/
|
||||
|
||||
#ifndef NEW_H
|
||||
#define NEW_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void *operator new(size_t size);
|
||||
void operator delete(void *ptr);
|
||||
|
||||
__extension__ typedef int __guard __attribute__ ((mode(__DI__)));
|
||||
|
||||
extern "C" int __cxa_guard_acquire(__guard *);
|
||||
extern "C" void __cxa_guard_release(__guard *);
|
||||
extern "C" void __cxa_guard_abort(__guard *);
|
||||
|
||||
extern "C" void __cxa_pure_virtual(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
pins_arduino.h - Pin definition functions for Arduino
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2007 David A. Mellis
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define NUM_DIGITAL_PINS 20
|
||||
#define NUM_ANALOG_INPUTS 6
|
||||
#define analogInputToDigitalPin(p) ((p < 6) ? (p) + 14 : -1)
|
||||
|
||||
#if defined(__AVR_ATmega8__)
|
||||
#define digitalPinHasPWM(p) ((p) == 9 || (p) == 10 || (p) == 11)
|
||||
#else
|
||||
#define digitalPinHasPWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11)
|
||||
#endif
|
||||
|
||||
static const uint8_t SS = 10;
|
||||
static const uint8_t MOSI = 11;
|
||||
static const uint8_t MISO = 12;
|
||||
static const uint8_t SCK = 13;
|
||||
|
||||
static const uint8_t SDA = 18;
|
||||
static const uint8_t SCL = 19;
|
||||
static const uint8_t LED_BUILTIN = 13;
|
||||
|
||||
static const uint8_t A0 = 14;
|
||||
static const uint8_t A1 = 15;
|
||||
static const uint8_t A2 = 16;
|
||||
static const uint8_t A3 = 17;
|
||||
static const uint8_t A4 = 18;
|
||||
static const uint8_t A5 = 19;
|
||||
static const uint8_t A6 = 20;
|
||||
static const uint8_t A7 = 21;
|
||||
|
||||
#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0))
|
||||
#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1))
|
||||
#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0))))
|
||||
#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14)))
|
||||
|
||||
#ifdef ARDUINO_MAIN
|
||||
|
||||
// On the Arduino board, digital pins are also used
|
||||
// for the analog output (software PWM). Analog input
|
||||
// pins are a separate set.
|
||||
|
||||
// ATMEL ATMEGA8 & 168 / ARDUINO
|
||||
//
|
||||
// +-\/-+
|
||||
// PC6 1| |28 PC5 (AI 5)
|
||||
// (D 0) PD0 2| |27 PC4 (AI 4)
|
||||
// (D 1) PD1 3| |26 PC3 (AI 3)
|
||||
// (D 2) PD2 4| |25 PC2 (AI 2)
|
||||
// PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
|
||||
// (D 4) PD4 6| |23 PC0 (AI 0)
|
||||
// VCC 7| |22 GND
|
||||
// GND 8| |21 AREF
|
||||
// PB6 9| |20 AVCC
|
||||
// PB7 10| |19 PB5 (D 13)
|
||||
// PWM+ (D 5) PD5 11| |18 PB4 (D 12)
|
||||
// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
|
||||
// (D 7) PD7 13| |16 PB2 (D 10) PWM
|
||||
// (D 8) PB0 14| |15 PB1 (D 9) PWM
|
||||
// +----+
|
||||
//
|
||||
// (PWM+ indicates the additional PWM pins on the ATmega168.)
|
||||
|
||||
// ATMEL ATMEGA1280 / ARDUINO
|
||||
//
|
||||
// 0-7 PE0-PE7 works
|
||||
// 8-13 PB0-PB5 works
|
||||
// 14-21 PA0-PA7 works
|
||||
// 22-29 PH0-PH7 works
|
||||
// 30-35 PG5-PG0 works
|
||||
// 36-43 PC7-PC0 works
|
||||
// 44-51 PJ7-PJ0 works
|
||||
// 52-59 PL7-PL0 works
|
||||
// 60-67 PD7-PD0 works
|
||||
// A0-A7 PF0-PF7
|
||||
// A8-A15 PK0-PK7
|
||||
|
||||
|
||||
// these arrays map port names (e.g. port B) to the
|
||||
// appropriate addresses for various functions (e.g. reading
|
||||
// and writing)
|
||||
const uint16_t PROGMEM port_to_mode_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & DDRB,
|
||||
(uint16_t) & DDRC,
|
||||
(uint16_t) & DDRD,
|
||||
};
|
||||
|
||||
const uint16_t PROGMEM port_to_output_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & PORTB,
|
||||
(uint16_t) & PORTC,
|
||||
(uint16_t) & PORTD,
|
||||
};
|
||||
|
||||
const uint16_t PROGMEM port_to_input_PGM[] = {
|
||||
NOT_A_PORT,
|
||||
NOT_A_PORT,
|
||||
(uint16_t) & PINB,
|
||||
(uint16_t) & PINC,
|
||||
(uint16_t) & PIND,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
|
||||
PD, /* 0 */
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PD,
|
||||
PB, /* 8 */
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PB,
|
||||
PC, /* 14 */
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
PC,
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
|
||||
_BV(0), /* 0, port D */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(6),
|
||||
_BV(7),
|
||||
_BV(0), /* 8, port B */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
_BV(0), /* 14, port C */
|
||||
_BV(1),
|
||||
_BV(2),
|
||||
_BV(3),
|
||||
_BV(4),
|
||||
_BV(5),
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
|
||||
NOT_ON_TIMER, /* 0 - port D */
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
// on the ATmega168, digital pin 3 has hardware pwm
|
||||
#if defined(__AVR_ATmega8__)
|
||||
NOT_ON_TIMER,
|
||||
#else
|
||||
TIMER2B,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
// on the ATmega168, digital pins 5 and 6 have hardware pwm
|
||||
#if defined(__AVR_ATmega8__)
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
#else
|
||||
TIMER0B,
|
||||
TIMER0A,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER, /* 8 - port B */
|
||||
TIMER1A,
|
||||
TIMER1B,
|
||||
#if defined(__AVR_ATmega8__)
|
||||
TIMER2,
|
||||
#else
|
||||
TIMER2A,
|
||||
#endif
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER, /* 14 - port C */
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
NOT_ON_TIMER,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
wiring_private.h - Internal header file.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
|
||||
*/
|
||||
|
||||
#ifndef WiringPrivate_h
|
||||
#define WiringPrivate_h
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef cbi
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif
|
||||
#ifndef sbi
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif
|
||||
|
||||
#define EXTERNAL_INT_0 0
|
||||
#define EXTERNAL_INT_1 1
|
||||
#define EXTERNAL_INT_2 2
|
||||
#define EXTERNAL_INT_3 3
|
||||
#define EXTERNAL_INT_4 4
|
||||
#define EXTERNAL_INT_5 5
|
||||
#define EXTERNAL_INT_6 6
|
||||
#define EXTERNAL_INT_7 7
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 8
|
||||
#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 3
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define EXTERNAL_NUM_INTERRUPTS 4
|
||||
#else
|
||||
#define EXTERNAL_NUM_INTERRUPTS 2
|
||||
#endif
|
||||
|
||||
typedef void (*voidFuncPtr) (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "rp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "bv.h"
|
||||
|
||||
/* Encodes the property APDU and returns the length,
|
||||
or sets the error, and returns -1 */
|
||||
int Encode_Property_APDU(uint8_t * apdu,
|
||||
BACNET_READ_PROPERTY_DATA * rp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = -1;
|
||||
|
||||
/* handle each object type */
|
||||
switch (rp_data->object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Valid_Object_Instance_Number(rp_data->object_instance)) {
|
||||
apdu_len =
|
||||
Device_Encode_Property_APDU(&apdu[0],
|
||||
rp_data->object_instance, rp_data->object_property,
|
||||
rp_data->array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Valid_Instance(rp_data->object_instance)) {
|
||||
apdu_len =
|
||||
Analog_Value_Encode_Property_APDU(&apdu[0],
|
||||
rp_data->object_instance, rp_data->object_property,
|
||||
rp_data->array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Valid_Instance(rp_data->object_instance)) {
|
||||
apdu_len =
|
||||
Binary_Value_Encode_Property_APDU(&apdu[0],
|
||||
rp_data->object_instance, rp_data->object_property,
|
||||
rp_data->array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
void handler_read_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
int len = 0;
|
||||
int ack_len = 0;
|
||||
int property_len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len =
|
||||
npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address,
|
||||
&npdu_data);
|
||||
if (service_data->segmented_message) {
|
||||
/* we don't support segmentation - send an abort */
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
goto RP_ABORT;
|
||||
}
|
||||
len = rp_decode_service_request(service_request, service_len, &data);
|
||||
if (len < 0) {
|
||||
/* bad decoding - send an abort */
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
goto RP_ABORT;
|
||||
}
|
||||
/* most cases will be error */
|
||||
ack_len =
|
||||
rp_ack_encode_apdu_init(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, &data);
|
||||
/* FIXME: add buffer len as passed into function or use smart buffer */
|
||||
property_len =
|
||||
Encode_Property_APDU(&Handler_Transmit_Buffer[pdu_len + ack_len],
|
||||
&data, &error_class, &error_code);
|
||||
if (property_len >= 0) {
|
||||
len =
|
||||
rp_ack_encode_apdu_object_property_end(&Handler_Transmit_Buffer
|
||||
[pdu_len + property_len + ack_len]);
|
||||
len += ack_len + property_len;
|
||||
} else {
|
||||
switch (property_len) {
|
||||
/* BACnet APDU too small to fit data, so proper response is Abort */
|
||||
case BACNET_STATUS_ABORT:
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
RP_ABORT:
|
||||
pdu_len += len;
|
||||
|
||||
datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "whois.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
bool Send_I_Am_Flag = true;
|
||||
|
||||
void sendIamUnicast(uint8_t * buffer,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
BACNET_ADDRESS dest;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
|
||||
/* encode the data */
|
||||
int npdu_len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
/* The destination will be the same as the src, so copy it over. */
|
||||
memcpy(&dest, src, sizeof(BACNET_ADDRESS));
|
||||
/* dest->net = 0; - no, must direct back to src->net to meet BTL tests */
|
||||
|
||||
datalink_get_my_address(&my_address);
|
||||
/* encode the NPDU portion of the packet */
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
npdu_len = npdu_encode_pdu(&buffer[0], &dest, &my_address, &npdu_data);
|
||||
/* encode the APDU portion of the packet */
|
||||
apdu_len =
|
||||
iam_encode_apdu(&buffer[npdu_len], Device_Object_Instance_Number(),
|
||||
MAX_APDU, SEGMENTATION_NONE, Device_Vendor_Identifier());
|
||||
/* send data */
|
||||
pdu_len = npdu_len + apdu_len;
|
||||
int bytes = datalink_send_pdu(&dest, &npdu_data, &buffer[0], pdu_len);
|
||||
}
|
||||
|
||||
void handler_who_is(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
int32_t low_limit = 0;
|
||||
int32_t high_limit = 0;
|
||||
int32_t target_device;
|
||||
|
||||
len =
|
||||
whois_decode_service_request(service_request, service_len, &low_limit,
|
||||
&high_limit);
|
||||
if (len == 0) {
|
||||
sendIamUnicast(&Handler_Transmit_Buffer[0], src);
|
||||
} else if (len != -1) {
|
||||
/* is my device id within the limits? */
|
||||
target_device = Device_Object_Instance_Number();
|
||||
if (((target_device >= low_limit) && (target_device <= high_limit)) {
|
||||
sendIamUnicast(&Handler_Transmit_Buffer[0], src);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "wp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "bv.h"
|
||||
|
||||
/* too big to reside on stack frame for PIC */
|
||||
static BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
|
||||
void handler_write_property(uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len =
|
||||
npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address,
|
||||
&npdu_data);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
} else if (service_data->segmented_message) {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
} else {
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet/IP for Wiznet on Arduino-Uno
|
||||
*
|
||||
* This port is for BACnet/ip and uses part of the Arduino Ethernet
|
||||
* library so it needs the stock Arduino Etherenet Shield
|
||||
* (the one with the W5100 chip). The port was done by writting a C
|
||||
* wrapper around the c++ Ethernet library and adapting the
|
||||
* existing port for Atmega168 (mainly functions bip.c and bip-init.c)
|
||||
* to use the wrapper functions. The port also needs Arduino core and
|
||||
* Ethernet libraries to compile.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "datalink.h"
|
||||
#include "npdu.h"
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "uart.h"
|
||||
#include "w5100Wrapper.h"
|
||||
#include "Arduino.h"
|
||||
#include <avr/io.h>
|
||||
#define BAUD 9600
|
||||
#include <util/setbaud.h>
|
||||
|
||||
/* From the WhoIs hander - performed by the DLMSTP module */
|
||||
extern bool Send_I_Am_Flag;
|
||||
/* local version override */
|
||||
const char *BACnet_Version = "1.0";
|
||||
static uint8_t Ethernet_MAC_Address[MAX_MAC_LEN] =
|
||||
{ 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
uint8_t ipAddress[] = { 192, 168, 0, 185 };
|
||||
uint8_t gateway[] = { 192, 168, 0, 1 };
|
||||
uint8_t netmask[] = { 255, 255, 255, 0 };
|
||||
|
||||
FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
||||
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
|
||||
FILE uart_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
|
||||
|
||||
/* For porting to IAR, see:
|
||||
http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/
|
||||
|
||||
/* dummy function - so we can use default demo handlers */
|
||||
bool dcc_communication_enabled(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
//INIT W5100
|
||||
init_func(CW5100Class_new());
|
||||
setMACAddress_func(CW5100Class_new(), Ethernet_MAC_Address);
|
||||
setIPAddress_func(CW5100Class_new(), ipAddress);
|
||||
setGatewayIp_func(CW5100Class_new(), gateway);
|
||||
setSubnetMask_func(CW5100Class_new(), netmask);
|
||||
|
||||
uart_init();
|
||||
stdout = &uart_output;
|
||||
stdin = &uart_input;
|
||||
stderr = &uart_output;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Starting BACNET application..\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static uint8_t PDUBuffer[MAX_MPDU];
|
||||
int main(void)
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
BACNET_ADDRESS src; /* source address */
|
||||
|
||||
init();
|
||||
|
||||
setup();
|
||||
|
||||
datalink_init(NULL);
|
||||
for (;;) {
|
||||
|
||||
/* other tasks */
|
||||
/* BACnet handling */
|
||||
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
|
||||
if (pdu_len) {
|
||||
npdu_handler(&src, &PDUBuffer[0], pdu_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* typedef char _Bool; */
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
/* Defines the standard integer types that are used in code */
|
||||
|
||||
#ifndef STDINT_H
|
||||
#define STDINT_H 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t; /* 1 byte 0 to 255 */
|
||||
typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
@@ -0,0 +1,35 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef TXBUF_H
|
||||
#define TXBUF_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "datalink.h"
|
||||
|
||||
extern uint8_t Handler_Transmit_Buffer[MAX_PDU];
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief For redirecting stdout, stdin and stderr
|
||||
* see http://www.appelsiini.net/2011/simple-usart-with-avr-libc
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
#include <util/setbaud.h>
|
||||
#include "hardware.h"
|
||||
#include "uart.h"
|
||||
|
||||
void uart_init(void)
|
||||
{
|
||||
UBRR0H = UBRRH_VALUE;
|
||||
UBRR0L = UBRRL_VALUE;
|
||||
|
||||
#if USE_2X
|
||||
UCSR0A |= _BV(U2X0);
|
||||
#else
|
||||
UCSR0A &= ~(_BV(U2X0));
|
||||
#endif
|
||||
|
||||
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
|
||||
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */
|
||||
}
|
||||
|
||||
void uart_putchar(char c,
|
||||
FILE * stream)
|
||||
{
|
||||
if (c == '\n') {
|
||||
uart_putchar('\r', stream);
|
||||
}
|
||||
loop_until_bit_is_set(UCSR0A, UDRE0);
|
||||
UDR0 = c;
|
||||
}
|
||||
|
||||
char uart_getchar(FILE * stream)
|
||||
{
|
||||
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
|
||||
return UDR0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file
|
||||
* @author Miguel Fernandes <miguelandre.fernandes@gmail.com>
|
||||
* @date 6 de Jun de 2013
|
||||
* @brief BACnet Virtual Link Control for Wiznet on Arduino-Uno
|
||||
*/
|
||||
#ifndef UART_H_
|
||||
#define UART_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void uart_init(void);
|
||||
void uart_putchar(char c,
|
||||
FILE * stream);
|
||||
char uart_getchar(FILE * stream);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/* Defines the standard integer types that are used in code */
|
||||
|
||||
#ifndef STDINT_H
|
||||
#define STDINT_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned char uint8_t; /* 1 byte 0 to 255 */
|
||||
typedef signed char int8_t; /* 1 byte -127 to 127 */
|
||||
typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */
|
||||
typedef signed short int16_t; /* 2 bytes -32767 to 32767 */
|
||||
/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */
|
||||
typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */
|
||||
typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */
|
||||
/* typedef signed long long int64_t; */
|
||||
/* typedef unsigned long long uint64_t; */
|
||||
|
||||
#endif /* STDINT_H */
|
||||
@@ -0,0 +1,252 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||
#include <stdbool.h> /* for the standard bool type. */
|
||||
#include "bacdcode.h"
|
||||
#include "bip.h"
|
||||
#include "eth.h"
|
||||
#include "net.h" /* custom per port */
|
||||
|
||||
static int BIP_Socket = -1;
|
||||
/* port to use - stored in host byte order */
|
||||
static uint16_t BIP_Port = 0xBAC0;
|
||||
/* IP Address - stored in host byte order */
|
||||
static struct in_addr BIP_Address;
|
||||
/* Broadcast Address - stored in host byte order */
|
||||
static struct in_addr BIP_Broadcast_Address;
|
||||
|
||||
void bip_set_socket(
|
||||
int sock_fd)
|
||||
{
|
||||
BIP_Socket = sock_fd;
|
||||
}
|
||||
|
||||
int bip_socket(
|
||||
void)
|
||||
{
|
||||
return BIP_Socket;
|
||||
}
|
||||
|
||||
bool bip_valid(
|
||||
void)
|
||||
{
|
||||
return (BIP_Socket != -1);
|
||||
}
|
||||
|
||||
void bip_cleanup(
|
||||
void)
|
||||
{
|
||||
/* if (bip_valid()) */
|
||||
/* close(BIP_Socket); */
|
||||
BIP_Socket = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* set using network byte order */
|
||||
void bip_set_addr(
|
||||
uint32_t net_address)
|
||||
{
|
||||
/* BIP_Address.s_addr = ntohl(net_address); */
|
||||
BIP_Address.s_addr = net_address;
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint32_t bip_get_addr(
|
||||
void)
|
||||
{
|
||||
return BIP_Address.s_addr;
|
||||
}
|
||||
|
||||
/* set using network byte order */
|
||||
void bip_set_broadcast_addr(
|
||||
uint32_t net_address)
|
||||
{
|
||||
/* BIP_Broadcast_Address.s_addr = ntohl(net_address); */
|
||||
BIP_Broadcast_Address.s_addr = net_address;
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint32_t bip_get_broadcast_addr(
|
||||
void)
|
||||
{
|
||||
return BIP_Broadcast_Address.s_addr;
|
||||
}
|
||||
|
||||
/* set using host byte order */
|
||||
void bip_set_port(
|
||||
uint16_t port)
|
||||
{
|
||||
BIP_Port = port;
|
||||
}
|
||||
|
||||
/* returns host byte order */
|
||||
uint16_t bip_get_port(
|
||||
void)
|
||||
{
|
||||
return BIP_Port;
|
||||
}
|
||||
|
||||
/* function to send a packet out the BACnet/IP socket (Annex J) */
|
||||
/* returns number of bytes sent on success, negative number on failure */
|
||||
int bip_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len)
|
||||
{ /* number of bytes of data */
|
||||
|
||||
struct sockaddr_in bip_dest;
|
||||
uint8_t mtu[4];
|
||||
int mtu_len = 0;
|
||||
int bytes_sent = 0;
|
||||
UDP_HDR udphdr;
|
||||
IP_HDR iphdr;
|
||||
uint8_t mac[6];
|
||||
|
||||
(void) npdu_data;
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
/* if (BIP_Socket < 0) */
|
||||
/* return BIP_Socket; */
|
||||
|
||||
mtu[0] = BVLL_TYPE_BACNET_IP;
|
||||
bip_dest.sin_family = AF_INET;
|
||||
|
||||
if (dest->mac_len == 6) {
|
||||
memcpy(&(bip_dest.sin_addr.s_addr), &dest->mac[0], 4);
|
||||
decode_unsigned16(&dest->mac[4], &(bip_dest.sin_port));
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_UNICAST_NPDU;
|
||||
}
|
||||
/* broadcast */
|
||||
else if (dest->mac_len == 0) {
|
||||
bip_dest.sin_addr.s_addr = BIP_Broadcast_Address.s_addr;
|
||||
bip_dest.sin_port = htons(BIP_Port);
|
||||
memset(&(bip_dest.sin_zero), '\0', 8);
|
||||
mtu[1] = BVLC_ORIGINAL_BROADCAST_NPDU;
|
||||
} else
|
||||
return -1;
|
||||
|
||||
mtu_len = 2;
|
||||
mtu_len +=
|
||||
encode_unsigned16(&mtu[mtu_len],
|
||||
(uint16_t) (pdu_len + 4 /*inclusive */ ));
|
||||
mtu_len += pdu_len;
|
||||
|
||||
/* IP address should be in network byte order */
|
||||
ARPIsResolved(bip_dest.sin_addr.s_addr, mac);
|
||||
|
||||
iphdr.vhl = 0x45;
|
||||
iphdr.tos = 0;
|
||||
iphdr.iplen = htons(mtu_len + sizeof(IP_HDR) + sizeof(UDP_HDR));
|
||||
++ipid;
|
||||
iphdr.ipid = htons(ipid);
|
||||
iphdr.ipoffset[0] = iphdr.ipoffset[1] = 0;
|
||||
iphdr.ttl = UIP_TTL;
|
||||
iphdr.proto = UIP_PROTO_UDP;
|
||||
iphdr.ipchksum = 0;
|
||||
iphdr.srcipaddr = BIP_Address.s_addr;
|
||||
iphdr.destipaddr = bip_dest.sin_addr.s_addr;
|
||||
|
||||
/* Calculate IP checksum. */
|
||||
iphdr.ipchksum = ~(ip_getchksum((uint8_t *) & iphdr));
|
||||
|
||||
/* Ports are sent in Network byte order. BIP_Port is stored in Host byte order */
|
||||
udphdr.srcport = htons(BIP_Port);
|
||||
udphdr.destport = bip_dest.sin_port;
|
||||
udphdr.udplen = htons(mtu_len + sizeof(UDP_HDR));
|
||||
/* Not using UDP checksums */
|
||||
udphdr.udpchksum = 0;
|
||||
|
||||
EthernetSendHeader(mac, UIP_ETHTYPE_IP);
|
||||
EthernetSend((uint8_t *) & iphdr, sizeof(IP_HDR));
|
||||
EthernetSend((uint8_t *) & udphdr, sizeof(UDP_HDR));
|
||||
EthernetSend(mtu, 4);
|
||||
EthernetSend(pdu, pdu_len);
|
||||
EthernetFlush();
|
||||
uip_stat.ip.sent++;
|
||||
|
||||
}
|
||||
|
||||
/* receives a BACnet/IP packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
uint16_t bip_receive(
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout)
|
||||
{ /* number of milliseconds to wait for a packet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bip_get_my_address(
|
||||
BACNET_ADDRESS * my_address)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
my_address->mac_len = 6;
|
||||
(void) encode_unsigned32(&my_address->mac[0], htonl(BIP_Address.s_addr));
|
||||
(void) encode_unsigned16(&my_address->mac[4], htons(BIP_Port));
|
||||
my_address->net = 0; /* local only, no routing */
|
||||
my_address->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
my_address->adr[i] = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void bip_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest)
|
||||
{ /* destination address */
|
||||
int i = 0; /* counter */
|
||||
|
||||
if (dest) {
|
||||
dest->mac_len = 6;
|
||||
(void) encode_unsigned32(&dest->mac[0],
|
||||
htonl(BIP_Broadcast_Address.s_addr));
|
||||
(void) encode_unsigned16(&dest->mac[4], htons(BIP_Port));
|
||||
dest->net = BACNET_BROADCAST_NETWORK;
|
||||
dest->len = 0; /* no SLEN */
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
/* no SADR */
|
||||
dest->adr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef NET_H
|
||||
#define NET_H
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
struct sockaddr {
|
||||
uint16_t sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
|
||||
struct in_addr {
|
||||
uint32_t s_addr; /* load with inet_aton() */
|
||||
};
|
||||
|
||||
struct sockaddr_in {
|
||||
int16_t sin_family; /* e.g. AF_INET */
|
||||
uint16_t sin_port; /* e.g. htons(3490) */
|
||||
struct in_addr sin_addr; /* see struct in_addr, below */
|
||||
char sin_zero[8]; /* zero this if you want to */
|
||||
};
|
||||
|
||||
|
||||
typedef int socklen_t;
|
||||
|
||||
/**
|
||||
* Convert 16-bit quantity from host byte order to network byte order.
|
||||
*
|
||||
* This macro is primarily used for converting constants from host
|
||||
* byte order to network byte order. For converting variables to
|
||||
* network byte order, use the htons() function instead.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#ifndef htons
|
||||
#define htons(n) ((((uint16_t)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
|
||||
#endif /* HTONS */
|
||||
|
||||
#define ntohs(n) (((((uint16_t)(n) & 0xFF)) << 8) | (((uint16_t)(n) & 0xFF00) >> 8))
|
||||
#define htonl(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
|
||||
((((uint32_t)(n) & 0xFF00)) << 8) | \
|
||||
((((uint32_t)(n) & 0xFF0000)) >> 8) | \
|
||||
((((uint32_t)(n) & 0xFF000000)) >> 24))
|
||||
|
||||
#define ntohl(n) (((((uint32_t)(n) & 0xFF)) << 24) | \
|
||||
((((uint32_t)(n) & 0xFF00)) << 8) | \
|
||||
((((uint32_t)(n) & 0xFF0000)) >> 8) | \
|
||||
((((uint32_t)(n) & 0xFF000000)) >> 24))
|
||||
|
||||
|
||||
#define AF_UNIX 1 /* local to host (pipes, portals) */
|
||||
#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
|
||||
#define AF_IMPLINK 3 /* arpanet imp addresses */
|
||||
#define AF_PUP 4 /* pup protocols: e.g. BSP */
|
||||
#define AF_CHAOS 5 /* mit CHAOS protocols */
|
||||
#define AF_NS 6 /* XEROX NS protocols */
|
||||
#define AF_IPX AF_NS /* IPX protocols: IPX, SPX, etc. */
|
||||
#define AF_ISO 7 /* ISO protocols */
|
||||
#define AF_OSI AF_ISO /* OSI is ISO */
|
||||
#define AF_ECMA 8 /* european computer manufacturers */
|
||||
#define AF_DATAKIT 9 /* datakit protocols */
|
||||
#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
|
||||
#define AF_SNA 11 /* IBM SNA */
|
||||
#define AF_DECnet 12 /* DECnet */
|
||||
#define AF_DLI 13 /* Direct data link interface */
|
||||
#define AF_LAT 14 /* LAT */
|
||||
#define AF_HYLINK 15 /* NSC Hyperchannel */
|
||||
#define AF_APPLETALK 16 /* AppleTalk */
|
||||
#define AF_NETBIOS 17 /* NetBios-style addresses */
|
||||
#define AF_VOICEVIEW 18 /* VoiceView */
|
||||
#define AF_FIREFOX 19 /* Protocols from Firefox */
|
||||
#define AF_UNKNOWN1 20 /* Somebody is using this! */
|
||||
#define AF_BAN 21 /* Banyan */
|
||||
#define AF_ATM 22 /* Native ATM Services */
|
||||
#define AF_INET6 23 /* Internetwork Version 6 */
|
||||
#define AF_CLUSTER 24 /* Microsoft Wolfpack */
|
||||
#define AF_12844 25 /* IEEE 1284.4 WG AF */
|
||||
#define AF_IRDA 26 /* IrDA */
|
||||
#define AF_NETDES 28 /* Network Designers OSI & gateway
|
||||
enabled protocols */
|
||||
#define AF_TCNPROCESS 29
|
||||
#define AF_TCNMESSAGE 30
|
||||
#define AF_ICLFXBM 31
|
||||
|
||||
#define AF_MAX 32
|
||||
|
||||
extern void set_address(
|
||||
uint32_t * net_address,
|
||||
uint8_t octet1,
|
||||
uint8_t octet2,
|
||||
uint8_t octet3,
|
||||
uint8_t octet4);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef STDBOOL_H
|
||||
#define STDBOOL_H
|
||||
|
||||
/* C99 Boolean types for compilers without C99 support */
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
/*typedef int _Bool; */
|
||||
#ifndef bool
|
||||
#define bool _Bool
|
||||
#endif
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
#define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
@@ -0,0 +1,13 @@
|
||||
-sysdirs C:\WinAVR~1\avr\include;C:\WinAVR~1\lib\gcc\avr\4.2.2\include;C:\WinAVR~1\avr\include\avr;C:\WinAVR~1\avr\include\compat;C:\WinAVR~1\avr\include\util
|
||||
-IC:\WinAVR~1\avr\include
|
||||
-IC:\WinAVR~1\avr\include\avr
|
||||
-IC:\WinAVR~1\avr\include\compat
|
||||
-IC:\WinAVR~1\avr\include\util
|
||||
-IC:\WinAVR~1\lib\gcc\avr\4.2.2\include
|
||||
-I../../include
|
||||
-I.
|
||||
-castfcnptr
|
||||
-fullinitblock
|
||||
-weak
|
||||
-D__AVR_ATmega168__
|
||||
-D__GNUC__
|
||||
@@ -0,0 +1,210 @@
|
||||
###############################################################################
|
||||
# Makefile for BACnet
|
||||
###############################################################################
|
||||
|
||||
## General Flags
|
||||
MCU = atmega168
|
||||
AVRDUDE_MCU = m168
|
||||
TARGET = bacnet
|
||||
## Tools
|
||||
CC = avr-gcc
|
||||
AR = avr-ar
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
LINT = splint
|
||||
|
||||
# programmer id--check the avrdude for complete list
|
||||
# # of available opts. These should include stk500,
|
||||
# # avr910, avrisp, bsd, pony and more. Set this to
|
||||
# # one of the valid "-c PROGRAMMER-ID" values
|
||||
# # described in the avrdude info page.
|
||||
# #
|
||||
AVRDUDE_PROGRAMMERID = avrispmkII
|
||||
#
|
||||
# # port--serial or parallel port to which your
|
||||
# # hardware programmer is attached
|
||||
# #
|
||||
AVRDUDE_PORT = /dev/ttyUSB0
|
||||
|
||||
# Source locations
|
||||
BACNET_CORE = ../../src
|
||||
BACNET_INCLUDE = ../../include
|
||||
BACNET_HANDLER = ../../demo/handler
|
||||
BACNET_OBJECT = ../../demo/object
|
||||
BACNET_DEMO = ../../demo
|
||||
|
||||
# local files for this project
|
||||
CSRC = main.c \
|
||||
timer.c \
|
||||
stack.c \
|
||||
rs485.c \
|
||||
dlmstp.c \
|
||||
apdu.c \
|
||||
h_rp.c \
|
||||
device.c \
|
||||
av.c \
|
||||
bv.c \
|
||||
h_whois.c \
|
||||
h_wp.c
|
||||
|
||||
# common demo files needed
|
||||
DEMOSRC = $(BACNET_DEMO)/handler/txbuf.c \
|
||||
$(BACNET_DEMO)/handler/h_npdu.c \
|
||||
$(BACNET_DEMO)/handler/s_iam.c \
|
||||
$(BACNET_DEMO)/handler/noserv.c
|
||||
|
||||
# core BACnet stack files
|
||||
CORESRC = \
|
||||
$(BACNET_CORE)/crc.c \
|
||||
$(BACNET_CORE)/npdu.c \
|
||||
$(BACNET_CORE)/bacdcode.c \
|
||||
$(BACNET_CORE)/bacint.c \
|
||||
$(BACNET_CORE)/bacreal.c \
|
||||
$(BACNET_CORE)/bacstr.c \
|
||||
$(BACNET_CORE)/iam.c \
|
||||
$(BACNET_CORE)/rp.c \
|
||||
$(BACNET_CORE)/wp.c \
|
||||
$(BACNET_CORE)/whois.c \
|
||||
$(BACNET_CORE)/bacaddr.c \
|
||||
$(BACNET_CORE)/abort.c \
|
||||
$(BACNET_CORE)/reject.c \
|
||||
$(BACNET_CORE)/bacerror.c \
|
||||
$(BACNET_CORE)/bacapp.c
|
||||
|
||||
# $(BACNET_CORE)/version.c
|
||||
# $(BACNET_CORE)/bacprop.c \
|
||||
# $(BACNET_CORE)/bactext.c \
|
||||
# $(BACNET_CORE)/datetime.c \
|
||||
# $(BACNET_CORE)/indtext.c \
|
||||
# $(BACNET_CORE)/bigend.c \
|
||||
# $(BACNET_CORE)/arf.c \
|
||||
# $(BACNET_CORE)/awf.c \
|
||||
# $(BACNET_CORE)/cov.c \
|
||||
# $(BACNET_CORE)/dcc.c \
|
||||
# $(BACNET_CORE)/iam/iam_client.c \
|
||||
# $(BACNET_CORE)/ihave.c \
|
||||
# $(BACNET_CORE)/rd.c \
|
||||
# $(BACNET_CORE)/rpm.c \
|
||||
# $(BACNET_CORE)/timesync.c \
|
||||
# $(BACNET_CORE)/whohas.c \
|
||||
# $(BACNET_CORE)/filename.c \
|
||||
# $(BACNET_CORE)/tsm.c \
|
||||
# $(BACNET_CORE)/address.c \
|
||||
|
||||
## Include Directories
|
||||
INCLUDES = -I. -I$(BACNET_INCLUDE)
|
||||
INCLUDES += -I$(BACNET_OBJECT)
|
||||
INCLUDES += -I$(BACNET_HANDLER)
|
||||
|
||||
# Source to Object conversion
|
||||
COBJ = $(CSRC:.c=.o)
|
||||
DEMOOBJ = $(DEMOSRC:.c=.o)
|
||||
COREOBJ = $(CORESRC:.c=.o)
|
||||
|
||||
LIBRARY = lib$(TARGET).a
|
||||
|
||||
## Options common to compile, link and assembly rules
|
||||
COMMON = -mmcu=$(MCU)
|
||||
|
||||
OPTIMIZE_FLAGS = -mcall-prologues
|
||||
#OPTIMIZE_FLAGS += -finline-functions
|
||||
OPTIMIZE_FLAGS += -finline-functions-called-once
|
||||
#OPTIMIZATION = -O0
|
||||
#OPTIMIZATION = -Os
|
||||
OPTIMIZATION = -Os $(OPTIMIZE_FLAGS)
|
||||
#OPTIMIZATION = -O3 $(OPTIMIZE_FLAGS)
|
||||
|
||||
## Compile options common for all C compilation units.
|
||||
BFLAGS = -DBACDL_MSTP
|
||||
BFLAGS += -DMAX_APDU=50
|
||||
BFLAGS += -DBIG_ENDIAN=0
|
||||
BFLAGS += -DMAX_TSM_TRANSACTIONS=0
|
||||
#BFLAGS += -DCRC_USE_TABLE
|
||||
BFLAGS += -DBACAPP_REAL
|
||||
BFLAGS += -DBACAPP_OBJECT_ID
|
||||
BFLAGS += -DBACAPP_UNSIGNED
|
||||
BFLAGS += -DBACAPP_ENUMERATED
|
||||
BFLAGS += -DBACAPP_CHARACTER_STRING
|
||||
BFLAGS += -DWRITE_PROPERTY
|
||||
BFLAGS += -DMAX_ANALOG_VALUES=10
|
||||
BFLAGS += -DMAX_BINARY_VALUES=10
|
||||
CFLAGS = $(COMMON)
|
||||
# dead code removal
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
CFLAGS += -Wall -gdwarf-2 $(BFLAGS) $(OPTIMIZATION) -fsigned-char
|
||||
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d
|
||||
|
||||
## Assembly specific flags
|
||||
ASMFLAGS = $(COMMON)
|
||||
ASMFLAGS += $(CFLAGS)
|
||||
ASMFLAGS += -x assembler-with-cpp -Wa,-gdwarf2
|
||||
|
||||
## Linker flags
|
||||
LDFLAGS = $(COMMON)
|
||||
#dead code removal
|
||||
#LDFLAGS += -Wl,-nostartfiles,-nostdlib
|
||||
LDFLAGS += -Wl,--gc-sections,-static
|
||||
LDFLAGS += -Wl,-Map=$(TARGET).map,-L.,-l$(TARGET)
|
||||
#LDFLAGS += -Wl,-Map=$(TARGET).map
|
||||
|
||||
## Intel Hex file production flags
|
||||
HEX_FLASH_FLAGS = -R .eeprom
|
||||
HEX_EEPROM_FLAGS = -j .eeprom
|
||||
HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load"
|
||||
HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings
|
||||
|
||||
## Objects that must be built in order to link
|
||||
OBJECTS = $(COBJ) $(DEMOOBJ)
|
||||
#OBJECTS = $(COBJ)
|
||||
|
||||
## Build
|
||||
TARGET_ELF=$(TARGET).elf
|
||||
|
||||
all: $(LIBRARY) $(TARGET_ELF) $(TARGET).hex $(TARGET).eep $(TARGET).lst \
|
||||
size Makefile
|
||||
|
||||
##Link
|
||||
$(TARGET_ELF): $(OBJECTS) $(LIBRARY)
|
||||
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||
|
||||
%.hex: $(TARGET_ELF)
|
||||
$(OBJCOPY) -O ihex $(HEX_FLASH_FLAGS) $< $@
|
||||
|
||||
%.eep: $(TARGET_ELF)
|
||||
-$(OBJCOPY) $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0
|
||||
|
||||
%.lst: $(TARGET_ELF)
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
lib: $(LIBRARY)
|
||||
|
||||
$(LIBRARY): $(COREOBJ) Makefile
|
||||
$(AR) rcs $@ $(COREOBJ)
|
||||
$(OBJDUMP) --syms $@ > $(LIBRARY:.a=.lst)
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $*.c -o $@
|
||||
|
||||
size: ${TARGET_ELF}
|
||||
@echo
|
||||
@${SIZE} ${TARGET_ELF}
|
||||
|
||||
lint:
|
||||
$(LINT) $(BFLAGS) $(CSRC)
|
||||
|
||||
install: $(TARGET_ELF)
|
||||
$(AVRDUDE) -c $(AVRDUDE_PROGRAMMERID) \
|
||||
-p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -e \
|
||||
-U flash:w:$(TARGET).hex
|
||||
|
||||
## Clean target
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm -rf $(OBJECTS) $(TARGET_ELF) dep/*
|
||||
-rm -rf $(LIBRARY) $(COREOBJ) $(LIBRARY:.a=.lst)
|
||||
-rm -rf $(TARGET).hex $(TARGET).eep $(TARGET).lst $(TARGET).map
|
||||
|
||||
## Other dependencies
|
||||
-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*)
|
||||
Binary file not shown.
@@ -0,0 +1,165 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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"
|
||||
|
||||
/* Analog Input = Photocell */
|
||||
#define MAX_ANALOG_INPUTS 9
|
||||
#if (MAX_ANALOG_INPUTS > 9)
|
||||
#error Modify the Analog_Input_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
float Present_Value[MAX_ANALOG_INPUTS];
|
||||
|
||||
/* we simply have 0-n object instances. Yours might be */
|
||||
/* more complex, and then you need validate that the */
|
||||
/* given instance exists */
|
||||
bool Analog_Input_Valid_Instance(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
if (object_instance < MAX_ANALOG_INPUTS)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Analog_Input_Count(
|
||||
void)
|
||||
{
|
||||
return MAX_ANALOG_INPUTS;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
uint32_t Analog_Input_Index_To_Instance(
|
||||
unsigned index)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
/* we simply have 0-n object instances. */
|
||||
unsigned Analog_Input_Instance_To_Index(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
return object_instance;
|
||||
}
|
||||
|
||||
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "AI-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_ANALOG_INPUTS) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu length, or -1 on error */
|
||||
/* assumption - object has already exists */
|
||||
int Analog_Input_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index;
|
||||
|
||||
|
||||
(void) array_index;
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_INPUT,
|
||||
object_instance);
|
||||
break;
|
||||
/* note: Name and Description don't have to be the same.
|
||||
You could make Description writable and different.
|
||||
Note that Object-Name must be unique in this device */
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_DESCRIPTION:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Input_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_INPUT);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Input_Instance_To_Index(object_instance);
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0], Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef AI_H
|
||||
#define AI_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "rp.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
void Analog_Input_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
|
||||
bool Analog_Input_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Analog_Input_Count(
|
||||
void);
|
||||
uint32_t Analog_Input_Index_To_Instance(
|
||||
unsigned index);
|
||||
unsigned Analog_Input_Instance_To_Index(
|
||||
uint32_t instance);
|
||||
bool Analog_Input_Object_Instance_Add(
|
||||
uint32_t instance);
|
||||
|
||||
char *Analog_Input_Name(
|
||||
uint32_t object_instance);
|
||||
bool Analog_Input_Name_Set(
|
||||
uint32_t object_instance,
|
||||
char *new_name);
|
||||
|
||||
char *Analog_Input_Description(
|
||||
uint32_t instance);
|
||||
bool Analog_Input_Description_Set(
|
||||
uint32_t instance,
|
||||
char *new_name);
|
||||
|
||||
bool Analog_Input_Units_Set(
|
||||
uint32_t instance,
|
||||
uint16_t units);
|
||||
uint16_t Analog_Input_Units(
|
||||
uint32_t instance);
|
||||
|
||||
int Analog_Input_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Analog_Input_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
float Analog_Input_Present_Value(
|
||||
uint32_t object_instance);
|
||||
void Analog_Input_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value);
|
||||
|
||||
void Analog_Input_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAnalogInput(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#define ANALOG_INPUT_OBJ_FUNCTIONS \
|
||||
OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count, \
|
||||
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance, \
|
||||
Analog_Input_Name, Analog_Input_Read_Property, NULL, \
|
||||
Analog_Input_Property_Lists, NULL, NULL
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "bits.h"
|
||||
#include "apdu.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "handlers.h"
|
||||
|
||||
bool apdu_service_supported(
|
||||
BACNET_SERVICES_SUPPORTED service_supported)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (service_supported == SERVICE_SUPPORTED_READ_PROPERTY) {
|
||||
status = true;
|
||||
}
|
||||
if (service_supported == SERVICE_SUPPORTED_WHO_IS) {
|
||||
status = true;
|
||||
}
|
||||
#ifdef WRITE_PROPERTY
|
||||
if (service_supported == SERVICE_SUPPORTED_WRITE_PROPERTY) {
|
||||
status = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t apdu_decode_confirmed_service_request(
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data,
|
||||
uint8_t * service_choice,
|
||||
uint8_t ** service_request,
|
||||
uint16_t * service_request_len)
|
||||
{
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
service_data->segmented_message = (apdu[0] & BIT3) ? true : false;
|
||||
service_data->more_follows = (apdu[0] & BIT2) ? true : false;
|
||||
service_data->segmented_response_accepted =
|
||||
(apdu[0] & BIT1) ? true : false;
|
||||
service_data->max_segs = decode_max_segs(apdu[1]);
|
||||
service_data->max_resp = decode_max_apdu(apdu[1]);
|
||||
service_data->invoke_id = apdu[2];
|
||||
len = 3;
|
||||
if (service_data->segmented_message) {
|
||||
service_data->sequence_number = apdu[len++];
|
||||
service_data->proposed_window_number = apdu[len++];
|
||||
}
|
||||
*service_choice = apdu[len++];
|
||||
*service_request = &apdu[len];
|
||||
*service_request_len = apdu_len - len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void apdu_handler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t * apdu, /* APDU data */
|
||||
uint16_t apdu_len)
|
||||
{
|
||||
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
|
||||
uint8_t service_choice = 0;
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
uint16_t len = 0; /* counts where we are in PDU */
|
||||
|
||||
if (apdu) {
|
||||
/* PDU Type */
|
||||
switch (apdu[0] & 0xF0) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
len = apdu_decode_confirmed_service_request(&apdu[0], /* APDU data */
|
||||
apdu_len, &service_data, &service_choice, &service_request,
|
||||
&service_request_len);
|
||||
if (service_choice == SERVICE_CONFIRMED_READ_PROPERTY) {
|
||||
handler_read_property(service_request, service_request_len,
|
||||
src, &service_data);
|
||||
}
|
||||
#ifdef WRITE_PROPERTY
|
||||
else if (service_choice == SERVICE_CONFIRMED_WRITE_PROPERTY) {
|
||||
handler_write_property(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
handler_unrecognized_service(service_request,
|
||||
service_request_len, src, &service_data);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
|
||||
service_choice = apdu[1];
|
||||
service_request = &apdu[2];
|
||||
service_request_len = apdu_len - 2;
|
||||
if (service_choice == SERVICE_UNCONFIRMED_WHO_IS) {
|
||||
handler_who_is(service_request, service_request_len, src);
|
||||
}
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
case PDU_TYPE_SEGMENT_ACK:
|
||||
case PDU_TYPE_ERROR:
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 "hardware.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "bacapp.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "av.h"
|
||||
|
||||
#if (MAX_ANALOG_VALUES > 10)
|
||||
#error Modify the Analog_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
float AV_Present_Value[MAX_ANALOG_VALUES];
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return object_instance;
|
||||
}
|
||||
|
||||
/* note: the object name must be unique within this device */
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "AV-"; /* okay for single thread */
|
||||
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
|
||||
return text_string;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Analog_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
unsigned object_index;
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE,
|
||||
object_instance);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Analog_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_ANALOG_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
object_index = Analog_Value_Instance_To_Index(object_instance);
|
||||
apdu_len =
|
||||
encode_application_real(&apdu[0],
|
||||
AV_Present_Value[object_index]);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
||||
break;
|
||||
case PROP_UNITS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], UNITS_PERCENT);
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Analog_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*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 */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*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) {
|
||||
object_index =
|
||||
Analog_Value_Instance_To_Index(wp_data->object_instance);
|
||||
AV_Present_Value[object_index] = value.type.Real;
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
case PROP_DESCRIPTION:
|
||||
case PROP_PRIORITY_ARRAY:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testAnalog_Value(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_ANALOG_VALUE;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
len =
|
||||
Analog_Value_Encode_Property_APDU(&apdu[0], instance,
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len =
|
||||
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_ANALOG_VALUE);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_ANALOG_VALUE
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Analog Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testAnalog_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_ANALOG_VALUE */
|
||||
#endif /* TEST */
|
||||
@@ -0,0 +1,86 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef AV_H
|
||||
#define AV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifndef MAX_ANALOG_VALUES
|
||||
#define MAX_ANALOG_VALUES 4
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
void Analog_Value_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Analog_Value_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Analog_Value_Count(
|
||||
void);
|
||||
uint32_t Analog_Value_Index_To_Instance(
|
||||
unsigned index);
|
||||
char *Analog_Value_Name(
|
||||
uint32_t object_instance);
|
||||
|
||||
int Analog_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Analog_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Analog_Value_Present_Value_Set(
|
||||
uint32_t object_instance,
|
||||
float value,
|
||||
uint8_t priority);
|
||||
float Analog_Value_Present_Value(
|
||||
uint32_t object_instance);
|
||||
|
||||
void Analog_Value_Init(
|
||||
void);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testAnalog_Value(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef AVR035_H
|
||||
#define AVR035_H
|
||||
|
||||
/* from AVR035: Efficient C Coding for AVR */
|
||||
|
||||
/* a=register, b=bit number to act upon */
|
||||
#define BIT_SET(a,b) ((a) |= (1<<(b)))
|
||||
#define BIT_CLEAR(a,b) ((a) &= ~(1<<(b)))
|
||||
#define BIT_FLIP(a,b) ((a) ^= (1<<(b)))
|
||||
#define BIT_CHECK(a,b) ((a) & (1<<(b)))
|
||||
|
||||
/* x=target variable, y=mask */
|
||||
#define BITMASK_SET(x,y) ((x) |= (y))
|
||||
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
|
||||
#define BITMASK_FLIP(x,y) ((x) ^= (y))
|
||||
#define BITMASK_CHECK(x,y) ((x) & (y))
|
||||
|
||||
#endif
|
||||
File diff suppressed because one or more lines are too long
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,329 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 "hardware.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacenum.h"
|
||||
#include "config.h" /* the custom stuff */
|
||||
#include "wp.h"
|
||||
#include "bv.h"
|
||||
|
||||
#if (MAX_BINARY_VALUES > 10)
|
||||
#error Modify the Binary_Value_Name to handle multiple digits
|
||||
#endif
|
||||
|
||||
static BACNET_BINARY_PV Present_Value[MAX_BINARY_VALUES];
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static 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 */
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance)
|
||||
{
|
||||
static char text_string[5] = "BV-0"; /* okay for single thread */
|
||||
|
||||
if (object_instance < MAX_BINARY_VALUES) {
|
||||
text_string[3] = '0' + (uint8_t) object_instance;
|
||||
return text_string;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return apdu len, or -1 on error */
|
||||
int Binary_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
BACNET_BINARY_PV present_value = BINARY_INACTIVE;
|
||||
BACNET_POLARITY polarity = POLARITY_NORMAL;
|
||||
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_BINARY_VALUE,
|
||||
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:
|
||||
characterstring_init_ansi(&char_string,
|
||||
Binary_Value_Name(object_instance));
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], OBJECT_BINARY_VALUE);
|
||||
break;
|
||||
case PROP_PRESENT_VALUE:
|
||||
present_value = Binary_Value_Present_Value(object_instance);
|
||||
apdu_len = encode_application_enumerated(&apdu[0], present_value);
|
||||
break;
|
||||
case PROP_STATUS_FLAGS:
|
||||
/* note: see the details in the standard on how to use these */
|
||||
bitstring_init(&bit_string);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false);
|
||||
bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_EVENT_STATE:
|
||||
/* note: see the details in the standard on how to use this */
|
||||
apdu_len =
|
||||
encode_application_enumerated(&apdu[0], EVENT_STATE_NORMAL);
|
||||
break;
|
||||
case PROP_OUT_OF_SERVICE:
|
||||
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:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = -1;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/* returns true if successful */
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
unsigned int object_index = 0;
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Binary_Value_Valid_Instance(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*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 */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*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) {
|
||||
if ((value.type.Enumerated == BINARY_ACTIVE) ||
|
||||
(value.type.Enumerated == BINARY_INACTIVE)) {
|
||||
object_index =
|
||||
Binary_Value_Instance_To_Index
|
||||
(wp_data->object_instance);
|
||||
/* NOTE: this Binary value has no priority array */
|
||||
Present_Value[object_index] =
|
||||
(BACNET_BINARY_PV) value.type.Enumerated;
|
||||
/* 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. */
|
||||
if (Present_Value[0] == BINARY_ACTIVE) {
|
||||
LED_GREEN_ON();
|
||||
} else {
|
||||
LED_GREEN_OFF();
|
||||
}
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_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 {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
case PROP_OBJECT_NAME:
|
||||
case PROP_OBJECT_TYPE:
|
||||
case PROP_STATUS_FLAGS:
|
||||
case PROP_EVENT_STATE:
|
||||
case PROP_POLARITY:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
void testBinary_Value(
|
||||
Test * pTest)
|
||||
{
|
||||
uint8_t apdu[MAX_APDU] = { 0 };
|
||||
int len = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint8_t tag_number = 0;
|
||||
BACNET_OBJECT_TYPE decoded_type = OBJECT_BINARY_VALUE;
|
||||
uint32_t decoded_instance = 0;
|
||||
uint32_t instance = 123;
|
||||
BACNET_ERROR_CLASS error_class;
|
||||
BACNET_ERROR_CODE error_code;
|
||||
|
||||
|
||||
len =
|
||||
Binary_Value_Encode_Property_APDU(&apdu[0], instance,
|
||||
PROP_OBJECT_IDENTIFIER, BACNET_ARRAY_ALL, &error_class, &error_code);
|
||||
ct_test(pTest, len != 0);
|
||||
len = decode_tag_number_and_value(&apdu[0], &tag_number, &len_value);
|
||||
ct_test(pTest, tag_number == BACNET_APPLICATION_TAG_OBJECT_ID);
|
||||
len =
|
||||
decode_object_id(&apdu[len], (int *) &decoded_type, &decoded_instance);
|
||||
ct_test(pTest, decoded_type == OBJECT_BINARY_VALUE);
|
||||
ct_test(pTest, decoded_instance == instance);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST_BINARY_VALUE
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
Test *pTest;
|
||||
bool rc;
|
||||
|
||||
pTest = ct_create("BACnet Binary_Value", NULL);
|
||||
/* individual tests */
|
||||
rc = ct_addTestFunction(pTest, testBinary_Value);
|
||||
assert(rc);
|
||||
|
||||
ct_setStream(pTest, stdout);
|
||||
ct_run(pTest);
|
||||
(void) ct_report(pTest);
|
||||
ct_destroy(pTest);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST_BINARY_VALUE */
|
||||
#endif /* TEST */
|
||||
@@ -0,0 +1,81 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef BV_H
|
||||
#define BV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacerror.h"
|
||||
#include "wp.h"
|
||||
|
||||
#ifndef MAX_BINARY_VALUES
|
||||
#define MAX_BINARY_VALUES 10
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Binary_Value_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
bool Binary_Value_Valid_Instance(
|
||||
uint32_t object_instance);
|
||||
unsigned Binary_Value_Count(
|
||||
void);
|
||||
uint32_t Binary_Value_Index_To_Instance(
|
||||
unsigned index);
|
||||
char *Binary_Value_Name(
|
||||
uint32_t object_instance);
|
||||
|
||||
void Binary_Value_Init(
|
||||
void);
|
||||
|
||||
int Binary_Value_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Binary_Value_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
#ifdef TEST
|
||||
#include "ctest.h"
|
||||
void testBinary_Value(
|
||||
Test * pTest);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,503 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacstr.h"
|
||||
#include "bacenum.h"
|
||||
#include "apdu.h"
|
||||
#include "dcc.h"
|
||||
#include "dlmstp.h"
|
||||
#include "rs485.h"
|
||||
#include "version.h"
|
||||
#include "stack.h"
|
||||
/* objects */
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "bv.h"
|
||||
#include "wp.h"
|
||||
|
||||
/* note: you really only need to define variables for
|
||||
properties that are writable or that may change.
|
||||
The properties that are constant can be hard coded
|
||||
into the read-property encoding. */
|
||||
static uint32_t Object_Instance_Number = 260001;
|
||||
static char Object_Name[20] = "My Device";
|
||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||
|
||||
void Device_Init(
|
||||
void)
|
||||
{
|
||||
/* Reinitialize_State = BACNET_REINIT_IDLE; */
|
||||
/* dcc_set_status_duration(COMMUNICATION_ENABLE, 0); */
|
||||
/* FIXME: Get the data from the eeprom */
|
||||
/* I2C_Read_Block(EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&Object_Instance_Number,
|
||||
sizeof(Object_Instance_Number),
|
||||
EEPROM_BACNET_ID_ADDR); */
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* FIXME: Write the data to the eeprom */
|
||||
/* I2C_Write_Block(
|
||||
EEPROM_DEVICE_ADDRESS,
|
||||
(char *)&Object_Instance_Number,
|
||||
sizeof(Object_Instance_Number),
|
||||
EEPROM_BACNET_ID_ADDR); */
|
||||
} else
|
||||
status = false;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id)
|
||||
{
|
||||
/* BACnet allows for a wildcard instance number */
|
||||
return (Object_Instance_Number == object_id);
|
||||
}
|
||||
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void)
|
||||
{
|
||||
return BACNET_VENDOR_ID;
|
||||
}
|
||||
|
||||
unsigned Device_Object_List_Count(
|
||||
void)
|
||||
{
|
||||
unsigned count = 1; /* at least 1 for device object */
|
||||
|
||||
/* FIXME: add objects as needed */
|
||||
count += Analog_Value_Count();
|
||||
count += Binary_Value_Count();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool Device_Object_List_Identifier(
|
||||
uint32_t array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance)
|
||||
{
|
||||
bool status = false;
|
||||
uint32_t object_index = 0;
|
||||
uint32_t object_count = 0;
|
||||
|
||||
/* device object */
|
||||
if (array_index == 1) {
|
||||
*object_type = OBJECT_DEVICE;
|
||||
*instance = Object_Instance_Number;
|
||||
status = true;
|
||||
}
|
||||
/* normalize the index since
|
||||
we know it is not the previous objects */
|
||||
/* array index starts at 1 */
|
||||
object_index = array_index - 1;
|
||||
/* 1 for the device object */
|
||||
object_count = 1;
|
||||
/* FIXME: add objects as needed */
|
||||
/* analog value objects */
|
||||
if (!status) {
|
||||
/* array index starts at 1, and 1 for the device object */
|
||||
object_index -= object_count;
|
||||
object_count = Analog_Value_Count();
|
||||
if (object_index < object_count) {
|
||||
*object_type = OBJECT_ANALOG_VALUE;
|
||||
*instance = Analog_Value_Index_To_Instance(object_index);
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
/* binary value objects */
|
||||
if (!status) {
|
||||
object_index -= object_count;
|
||||
object_count = Binary_Value_Count();
|
||||
/* is it a valid index for this object? */
|
||||
if (object_index < object_count) {
|
||||
*object_type = OBJECT_BINARY_VALUE;
|
||||
*instance = Binary_Value_Index_To_Instance(object_index);
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* return the length of the apdu encoded or -1 for error */
|
||||
int Device_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = 0; /* return value */
|
||||
int len = 0; /* apdu len intermediate value */
|
||||
BACNET_BIT_STRING bit_string;
|
||||
BACNET_CHARACTER_STRING char_string;
|
||||
uint32_t i = 0;
|
||||
int object_type = 0;
|
||||
uint32_t instance = 0;
|
||||
uint32_t count = 0;
|
||||
|
||||
object_instance = object_instance;
|
||||
/* FIXME: change the hardcoded names to suit your application */
|
||||
switch (property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], OBJECT_DEVICE,
|
||||
Object_Instance_Number);
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
characterstring_init_ansi(&char_string, Object_Name);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_OBJECT_TYPE:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||
break;
|
||||
case PROP_SYSTEM_STATUS:
|
||||
apdu_len = encode_application_enumerated(&apdu[0], System_Status);
|
||||
break;
|
||||
case PROP_VENDOR_NAME:
|
||||
characterstring_init_ansi(&char_string, BACNET_VENDOR_NAME);
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_VENDOR_IDENTIFIER:
|
||||
apdu_len =
|
||||
encode_application_unsigned(&apdu[0],
|
||||
Device_Vendor_Identifier());
|
||||
break;
|
||||
case PROP_MODEL_NAME:
|
||||
characterstring_init_ansi(&char_string, "GNU Demo");
|
||||
apdu_len =
|
||||
encode_application_character_string(&apdu[0], &char_string);
|
||||
break;
|
||||
case PROP_FIRMWARE_REVISION:
|
||||
characterstring_init_ansi(&char_string, BACNET_VERSION_TEXT);
|
||||
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);
|
||||
/* must have the bit string as big as it can be */
|
||||
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);
|
||||
}
|
||||
/* FIXME: indicate the objects that YOU support */
|
||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true);
|
||||
bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true);
|
||||
apdu_len = encode_application_bitstring(&apdu[0], &bit_string);
|
||||
break;
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
/* Array element zero is the number of objects in the list */
|
||||
if (array_index == 0)
|
||||
apdu_len = encode_application_unsigned(&apdu[0], count);
|
||||
/* if no index was specified, then try to encode the entire list */
|
||||
/* into one packet. Note that more than likely you will have */
|
||||
/* to return an error if the number of encoded objects exceeds */
|
||||
/* your maximum APDU size. */
|
||||
else if (array_index == BACNET_ARRAY_ALL) {
|
||||
for (i = 1; i <= count; i++) {
|
||||
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 */
|
||||
*error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
apdu_len = BACNET_STATUS_ABORT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Device_Object_List_Identifier(array_index, &object_type,
|
||||
&instance))
|
||||
apdu_len =
|
||||
encode_application_object_id(&apdu[0], object_type,
|
||||
instance);
|
||||
else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_ARRAY_INDEX;
|
||||
apdu_len = 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], SEGMENTATION_NONE);
|
||||
break;
|
||||
case PROP_APDU_TIMEOUT:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 60000);
|
||||
break;
|
||||
case PROP_NUMBER_OF_APDU_RETRIES:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], 0);
|
||||
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], 0);
|
||||
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;
|
||||
case 512:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], stack_size());
|
||||
break;
|
||||
case 513:
|
||||
apdu_len = encode_application_unsigned(&apdu[0], stack_unused());
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
apdu_len = -1;
|
||||
break;
|
||||
}
|
||||
/* only array properties can have array options */
|
||||
if ((apdu_len >= 0) && (property != PROP_OBJECT_LIST) &&
|
||||
(array_index != BACNET_ARRAY_ALL)) {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
apdu_len = BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
bool Device_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
bool status = false; /* return value */
|
||||
int len = 0;
|
||||
BACNET_APPLICATION_DATA_VALUE value;
|
||||
|
||||
if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) {
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
return false;
|
||||
}
|
||||
/* decode the some of the request */
|
||||
len =
|
||||
bacapp_decode_application_data(wp_data->application_data,
|
||||
wp_data->application_data_len, &value);
|
||||
/* FIXME: len < application_data_len: more data? */
|
||||
if (len < 0) {
|
||||
/* error while decoding - a value larger than we can handle */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*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 */
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
|
||||
return false;
|
||||
}
|
||||
switch (wp_data->object_property) {
|
||||
case PROP_OBJECT_IDENTIFIER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) {
|
||||
if ((value.type.Object_Id.type == OBJECT_DEVICE) &&
|
||||
(Device_Set_Object_Instance_Number(value.type.
|
||||
Object_Id.instance))) {
|
||||
/* we could send an I-Am broadcast to let the world know */
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_INFO_FRAMES:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int <= 255) {
|
||||
dlmstp_set_max_info_frames(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_MAX_MASTER:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if ((value.type.Unsigned_Int > 0) &&
|
||||
(value.type.Unsigned_Int <= 127)) {
|
||||
dlmstp_set_max_master(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_OBJECT_NAME:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) {
|
||||
uint8_t encoding;
|
||||
|
||||
encoding =
|
||||
characterstring_encoding(&value.type.Character_String);
|
||||
if (encoding == CHARACTER_ANSI_X34) {
|
||||
if (characterstring_ansi_copy(&Object_Name[0],
|
||||
sizeof(Object_Name),
|
||||
&value.type.Character_String)) {
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case 9600:
|
||||
if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) {
|
||||
if (value.type.Unsigned_Int > 115200) {
|
||||
RS485_Set_Baud_Rate(value.type.Unsigned_Int);
|
||||
status = true;
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
|
||||
}
|
||||
} else {
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_INVALID_DATA_TYPE;
|
||||
}
|
||||
break;
|
||||
case PROP_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:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_PROPERTY;
|
||||
*error_code = ERROR_CODE_UNKNOWN_PROPERTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2005 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef DEVICE_H
|
||||
#define DEVICE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacenum.h"
|
||||
#include "wp.h"
|
||||
#include "readrange.h"
|
||||
|
||||
typedef unsigned (
|
||||
*object_count_function) (
|
||||
void);
|
||||
typedef uint32_t(
|
||||
*object_index_to_instance_function)
|
||||
(
|
||||
unsigned index);
|
||||
typedef char *(
|
||||
*object_name_function)
|
||||
(
|
||||
uint32_t object_instance);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Device_Object_Function_Set(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
object_count_function count_function,
|
||||
object_index_to_instance_function index_function,
|
||||
object_name_function name_function);
|
||||
|
||||
void Device_Init(
|
||||
void);
|
||||
|
||||
void Device_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void);
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id);
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id);
|
||||
unsigned Device_Object_List_Count(
|
||||
void);
|
||||
bool Device_Object_List_Identifier(
|
||||
uint32_t array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance);
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(
|
||||
void);
|
||||
void Device_Set_System_Status(
|
||||
BACNET_DEVICE_STATUS status);
|
||||
|
||||
const char *Device_Vendor_Name(
|
||||
void);
|
||||
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void);
|
||||
|
||||
const char *Device_Model_Name(
|
||||
void);
|
||||
bool Device_Set_Model_Name(
|
||||
const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Firmware_Revision(
|
||||
void);
|
||||
|
||||
const char *Device_Application_Software_Version(
|
||||
void);
|
||||
bool Device_Set_Application_Software_Version(
|
||||
const char *name,
|
||||
size_t length);
|
||||
|
||||
bool Device_Set_Object_Name(
|
||||
const char *name,
|
||||
size_t length);
|
||||
const char *Device_Object_Name(
|
||||
void);
|
||||
|
||||
const char *Device_Description(
|
||||
void);
|
||||
bool Device_Set_Description(
|
||||
const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Location(
|
||||
void);
|
||||
bool Device_Set_Location(
|
||||
const char *name,
|
||||
size_t length);
|
||||
|
||||
/* some stack-centric constant values - no set methods */
|
||||
uint8_t Device_Protocol_Version(
|
||||
void);
|
||||
uint8_t Device_Protocol_Revision(
|
||||
void);
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||
void);
|
||||
|
||||
uint8_t Device_Database_Revision(
|
||||
void);
|
||||
void Device_Set_Database_Revision(
|
||||
uint8_t revision);
|
||||
|
||||
bool Device_Valid_Object_Name(
|
||||
const char *object_name,
|
||||
int *object_type,
|
||||
uint32_t * object_instance);
|
||||
char *Device_Valid_Object_Id(
|
||||
int object_type,
|
||||
uint32_t object_instance);
|
||||
|
||||
int Device_Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_ID property,
|
||||
uint32_t array_index,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool Device_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
bool DeviceGetRRInfo(
|
||||
uint32_t Object, /* Which particular object - obviously not important for device object */
|
||||
BACNET_PROPERTY_ID Property, /* Which property */
|
||||
RR_PROP_INFO * pInfo, /* Where to put the information */
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,169 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "rp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "bv.h"
|
||||
|
||||
/* Encodes the property APDU and returns the length,
|
||||
or sets the error, and returns -1 */
|
||||
int Encode_Property_APDU(
|
||||
uint8_t * apdu,
|
||||
BACNET_READ_PROPERTY_DATA * rp_data,
|
||||
BACNET_ERROR_CLASS * error_class,
|
||||
BACNET_ERROR_CODE * error_code)
|
||||
{
|
||||
int apdu_len = -1;
|
||||
|
||||
/* handle each object type */
|
||||
switch (rp_data->object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
/* Test for case of indefinite Device object instance */
|
||||
if (rp_data->object_instance == BACNET_MAX_INSTANCE) {
|
||||
rp_data->object_instance = Device_Object_Instance_Number();
|
||||
}
|
||||
if (Device_Valid_Object_Instance_Number(rp_data->object_instance)) {
|
||||
apdu_len =
|
||||
Device_Encode_Property_APDU(&apdu[0],
|
||||
rp_data->object_instance, rp_data->object_property,
|
||||
rp_data->array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Valid_Instance(rp_data->object_instance)) {
|
||||
apdu_len =
|
||||
Analog_Value_Encode_Property_APDU(&apdu[0],
|
||||
rp_data->object_instance, rp_data->object_property,
|
||||
rp_data->array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Valid_Instance(rp_data->object_instance)) {
|
||||
apdu_len =
|
||||
Binary_Value_Encode_Property_APDU(&apdu[0],
|
||||
rp_data->object_instance, rp_data->object_property,
|
||||
rp_data->array_index, error_class, error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*error_class = ERROR_CLASS_OBJECT;
|
||||
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
void handler_read_property(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
int len = 0;
|
||||
int ack_len = 0;
|
||||
int property_len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len =
|
||||
npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address,
|
||||
&npdu_data);
|
||||
if (service_data->segmented_message) {
|
||||
/* we don't support segmentation - send an abort */
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
goto RP_ABORT;
|
||||
}
|
||||
len = rp_decode_service_request(service_request, service_len, &data);
|
||||
if (len < 0) {
|
||||
/* bad decoding - send an abort */
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
goto RP_ABORT;
|
||||
}
|
||||
/* most cases will be error */
|
||||
ack_len =
|
||||
rp_ack_encode_apdu_init(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, &data);
|
||||
/* FIXME: add buffer len as passed into function or use smart buffer */
|
||||
property_len =
|
||||
Encode_Property_APDU(&Handler_Transmit_Buffer[pdu_len + ack_len],
|
||||
&data, &error_class, &error_code);
|
||||
if (property_len >= 0) {
|
||||
len =
|
||||
rp_ack_encode_apdu_object_property_end(&Handler_Transmit_Buffer
|
||||
[pdu_len + property_len + ack_len]);
|
||||
len += ack_len + property_len;
|
||||
} else {
|
||||
switch (property_len) {
|
||||
/* BACnet APDU too small to fit data, so proper response is Abort */
|
||||
case BACNET_STATUS_ABORT:
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
RP_ABORT:
|
||||
pdu_len += len;
|
||||
bytes_sent =
|
||||
datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0],
|
||||
pdu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "whois.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
|
||||
bool Send_I_Am_Flag = true;
|
||||
|
||||
void handler_who_is(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src)
|
||||
{
|
||||
int len = 0;
|
||||
int32_t low_limit = 0;
|
||||
int32_t high_limit = 0;
|
||||
int32_t target_device;
|
||||
|
||||
(void) src;
|
||||
len =
|
||||
whois_decode_service_request(service_request, service_len, &low_limit,
|
||||
&high_limit);
|
||||
if (len == 0) {
|
||||
Send_I_Am_Flag = true;
|
||||
} else if (len != BACNET_STATUS_ERROR) {
|
||||
/* is my device id within the limits? */
|
||||
target_device = Device_Object_Instance_Number();
|
||||
if ((target_device >= low_limit) && (target_device <= high_limit)) {
|
||||
Send_I_Am_Flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "config.h"
|
||||
#include "txbuf.h"
|
||||
#include "bacdef.h"
|
||||
#include "bacdcode.h"
|
||||
#include "bacerror.h"
|
||||
#include "apdu.h"
|
||||
#include "npdu.h"
|
||||
#include "abort.h"
|
||||
#include "wp.h"
|
||||
/* demo objects */
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
#include "bv.h"
|
||||
|
||||
/* too big to reside on stack frame for PIC */
|
||||
static BACNET_WRITE_PROPERTY_DATA wp_data;
|
||||
|
||||
void handler_write_property(
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS * src,
|
||||
BACNET_CONFIRMED_SERVICE_DATA * service_data)
|
||||
{
|
||||
int len = 0;
|
||||
int pdu_len = 0;
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT;
|
||||
int bytes_sent = 0;
|
||||
BACNET_ADDRESS my_address;
|
||||
|
||||
/* decode the service request only */
|
||||
len = wp_decode_service_request(service_request, service_len, &wp_data);
|
||||
/* encode the NPDU portion of the packet */
|
||||
datalink_get_my_address(&my_address);
|
||||
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
|
||||
pdu_len =
|
||||
npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address,
|
||||
&npdu_data);
|
||||
/* bad decoding or something we didn't understand - send an abort */
|
||||
if (len <= 0) {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_OTHER, true);
|
||||
} else if (service_data->segmented_message) {
|
||||
len =
|
||||
abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
} else {
|
||||
switch (wp_data.object_type) {
|
||||
case OBJECT_DEVICE:
|
||||
if (Device_Write_Property(&wp_data, &error_class, &error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_ANALOG_VALUE:
|
||||
if (Analog_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
case OBJECT_BINARY_VALUE:
|
||||
if (Binary_Value_Write_Property(&wp_data, &error_class,
|
||||
&error_code)) {
|
||||
len =
|
||||
encode_simple_ack(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY);
|
||||
} else {
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, error_class,
|
||||
error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
len =
|
||||
bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
|
||||
service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
error_class, error_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
pdu_len += len;
|
||||
bytes_sent =
|
||||
datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0],
|
||||
pdu_len);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef HARDWARE_H
|
||||
#define HARDWARE_H
|
||||
|
||||
#if !defined(F_CPU)
|
||||
/* The processor clock frequency */
|
||||
#define F_CPU 7372800UL
|
||||
#endif
|
||||
|
||||
#if defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ASM__)
|
||||
#include <iom168.h>
|
||||
#else
|
||||
#if !defined(__AVR_ATmega168__)
|
||||
#error Firmware is configured for ATmega168 only (-mmcu=atmega168)
|
||||
#endif
|
||||
#endif
|
||||
#include "iar2gcc.h"
|
||||
#include "avr035.h"
|
||||
|
||||
#define LED_NPDU_INIT() BIT_SET(DDRD, DDD5)
|
||||
#define LED_NPDU_ON() BIT_CLEAR(PORTD, PD5)
|
||||
#define LED_NPDU_OFF() BIT_SET(PORTD, PD5)
|
||||
/* #define LED_NPDU PORTD_Bit5 */
|
||||
/* #define LED_NPDU_OFF() {LED_NPDU = false;} */
|
||||
/* #define LED_NPDU_ON() {LED_NPDU = true;} */
|
||||
|
||||
#define LED_GREEN_INIT() BIT_SET(DDRD, DDD4)
|
||||
#define LED_GREEN_ON() BIT_CLEAR(PORTD, PD4)
|
||||
#define LED_GREEN_OFF() BIT_SET(PORTD, PD4)
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,228 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2007 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
#ifndef IAR2GCC_H
|
||||
#define IAR2GCC_H
|
||||
|
||||
#if !defined(F_CPU)
|
||||
#define F_CPU (7372800)
|
||||
#endif
|
||||
|
||||
/* IAR */
|
||||
#if defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ASM__)
|
||||
#include <inavr.h>
|
||||
#include <ioavr.h>
|
||||
/* BitValue is used alot in GCC examples */
|
||||
#ifndef _BV
|
||||
#define _BV(bit_num) (1 << (bit_num))
|
||||
#endif
|
||||
|
||||
/* inline function */
|
||||
static inline void _delay_us(
|
||||
uint8_t microseconds)
|
||||
{
|
||||
do {
|
||||
__delay_cycles(F_CPU / 1000000UL);
|
||||
} while (microseconds--);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Input/Output Registers */
|
||||
#if defined(__GNUC__)
|
||||
#include <avr/io.h>
|
||||
|
||||
typedef struct {
|
||||
unsigned char bit0:1;
|
||||
unsigned char bit1:1;
|
||||
unsigned char bit2:1;
|
||||
unsigned char bit3:1;
|
||||
unsigned char bit4:1;
|
||||
unsigned char bit5:1;
|
||||
unsigned char bit6:1;
|
||||
unsigned char bit7:1;
|
||||
} BitRegisterType;
|
||||
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#define GPIO_BITREG(port,bitnum) \
|
||||
((volatile BitRegisterType*)_SFR_MEM_ADDR(port) \
|
||||
)->bit ## bitnum
|
||||
|
||||
#define PINA_Bit0 GPIO_BITREG(PINA,0)
|
||||
#define PINA_Bit1 GPIO_BITREG(PINA,1)
|
||||
#define PINA_Bit2 GPIO_BITREG(PINA,2)
|
||||
#define PINA_Bit3 GPIO_BITREG(PINA,3)
|
||||
#define PINA_Bit4 GPIO_BITREG(PINA,4)
|
||||
#define PINA_Bit5 GPIO_BITREG(PINA,5)
|
||||
#define PINA_Bit6 GPIO_BITREG(PINA,6)
|
||||
#define PINA_Bit7 GPIO_BITREG(PINA,7)
|
||||
|
||||
#define PORTA_Bit0 GPIO_BITREG(PORTA,0)
|
||||
#define PORTA_Bit1 GPIO_BITREG(PORTA,1)
|
||||
#define PORTA_Bit2 GPIO_BITREG(PORTA,2)
|
||||
#define PORTA_Bit3 GPIO_BITREG(PORTA,3)
|
||||
#define PORTA_Bit4 GPIO_BITREG(PORTA,4)
|
||||
#define PORTA_Bit5 GPIO_BITREG(PORTA,5)
|
||||
#define PORTA_Bit6 GPIO_BITREG(PORTA,6)
|
||||
#define PORTA_Bit7 GPIO_BITREG(PORTA,7)
|
||||
|
||||
#define PINB_Bit0 GPIO_BITREG(PINB,0)
|
||||
#define PINB_Bit1 GPIO_BITREG(PINB,1)
|
||||
#define PINB_Bit2 GPIO_BITREG(PINB,2)
|
||||
#define PINB_Bit3 GPIO_BITREG(PINB,3)
|
||||
#define PINB_Bit4 GPIO_BITREG(PINB,4)
|
||||
#define PINB_Bit5 GPIO_BITREG(PINB,5)
|
||||
#define PINB_Bit6 GPIO_BITREG(PINB,6)
|
||||
#define PINB_Bit7 GPIO_BITREG(PINB,7)
|
||||
|
||||
#define PORTB_Bit0 GPIO_BITREG(PORTB,0)
|
||||
#define PORTB_Bit1 GPIO_BITREG(PORTB,1)
|
||||
#define PORTB_Bit2 GPIO_BITREG(PORTB,2)
|
||||
#define PORTB_Bit3 GPIO_BITREG(PORTB,3)
|
||||
#define PORTB_Bit4 GPIO_BITREG(PORTB,4)
|
||||
#define PORTB_Bit5 GPIO_BITREG(PORTB,5)
|
||||
#define PORTB_Bit6 GPIO_BITREG(PORTB,6)
|
||||
#define PORTB_Bit7 GPIO_BITREG(PORTB,7)
|
||||
|
||||
#define PINC_Bit0 GPIO_BITREG(PINC,0)
|
||||
#define PINC_Bit1 GPIO_BITREG(PINC,1)
|
||||
#define PINC_Bit2 GPIO_BITREG(PINC,2)
|
||||
#define PINC_Bit3 GPIO_BITREG(PINC,3)
|
||||
#define PINC_Bit4 GPIO_BITREG(PINC,4)
|
||||
#define PINC_Bit5 GPIO_BITREG(PINC,5)
|
||||
#define PINC_Bit6 GPIO_BITREG(PINC,6)
|
||||
#define PINC_Bit7 GPIO_BITREG(PINC,7)
|
||||
|
||||
#define PORTC_Bit0 GPIO_BITREG(PORTC,0)
|
||||
#define PORTC_Bit1 GPIO_BITREG(PORTC,1)
|
||||
#define PORTC_Bit2 GPIO_BITREG(PORTC,2)
|
||||
#define PORTC_Bit3 GPIO_BITREG(PORTC,3)
|
||||
#define PORTC_Bit4 GPIO_BITREG(PORTC,4)
|
||||
#define PORTC_Bit5 GPIO_BITREG(PORTC,5)
|
||||
#define PORTC_Bit6 GPIO_BITREG(PORTC,6)
|
||||
#define PORTC_Bit7 GPIO_BITREG(PORTC,7)
|
||||
|
||||
#define PIND_Bit0 GPIO_BITREG(PIND,0)
|
||||
#define PIND_Bit1 GPIO_BITREG(PIND,1)
|
||||
#define PIND_Bit2 GPIO_BITREG(PIND,2)
|
||||
#define PIND_Bit3 GPIO_BITREG(PIND,3)
|
||||
#define PIND_Bit4 GPIO_BITREG(PIND,4)
|
||||
#define PIND_Bit5 GPIO_BITREG(PIND,5)
|
||||
#define PIND_Bit6 GPIO_BITREG(PIND,6)
|
||||
#define PIND_Bit7 GPIO_BITREG(PIND,7)
|
||||
|
||||
#define PORTD_Bit0 GPIO_BITREG(PORTD,0)
|
||||
#define PORTD_Bit1 GPIO_BITREG(PORTD,1)
|
||||
#define PORTD_Bit2 GPIO_BITREG(PORTD,2)
|
||||
#define PORTD_Bit3 GPIO_BITREG(PORTD,3)
|
||||
#define PORTD_Bit4 GPIO_BITREG(PORTD,4)
|
||||
#define PORTD_Bit5 GPIO_BITREG(PORTD,5)
|
||||
#define PORTD_Bit6 GPIO_BITREG(PORTD,6)
|
||||
#define PORTD_Bit7 GPIO_BITREG(PORTD,7)
|
||||
|
||||
#define GPIOR0_Bit0 GPIO_BITREG(GPIOR0,0)
|
||||
#define GPIOR0_Bit1 GPIO_BITREG(GPIOR0,1)
|
||||
#define GPIOR0_Bit2 GPIO_BITREG(GPIOR0,2)
|
||||
#define GPIOR0_Bit3 GPIO_BITREG(GPIOR0,3)
|
||||
#define GPIOR0_Bit4 GPIO_BITREG(GPIOR0,4)
|
||||
#define GPIOR0_Bit5 GPIO_BITREG(GPIOR0,5)
|
||||
#define GPIOR0_Bit6 GPIO_BITREG(GPIOR0,6)
|
||||
#define GPIOR0_Bit7 GPIO_BITREG(GPIOR0,7)
|
||||
|
||||
#define GPIOR1_Bit0 GPIO_BITREG(GPIOR1,0)
|
||||
#define GPIOR1_Bit1 GPIO_BITREG(GPIOR1,1)
|
||||
#define GPIOR1_Bit2 GPIO_BITREG(GPIOR1,2)
|
||||
#define GPIOR1_Bit3 GPIO_BITREG(GPIOR1,3)
|
||||
#define GPIOR1_Bit4 GPIO_BITREG(GPIOR1,4)
|
||||
#define GPIOR1_Bit5 GPIO_BITREG(GPIOR1,5)
|
||||
#define GPIOR1_Bit6 GPIO_BITREG(GPIOR1,6)
|
||||
#define GPIOR1_Bit7 GPIO_BITREG(GPIOR1,7)
|
||||
|
||||
#define GPIOR2_Bit0 GPIO_BITREG(GPIOR2,0)
|
||||
#define GPIOR2_Bit1 GPIO_BITREG(GPIOR2,1)
|
||||
#define GPIOR2_Bit2 GPIO_BITREG(GPIOR2,2)
|
||||
#define GPIOR2_Bit3 GPIO_BITREG(GPIOR2,3)
|
||||
#define GPIOR2_Bit4 GPIO_BITREG(GPIOR2,4)
|
||||
#define GPIOR2_Bit5 GPIO_BITREG(GPIOR2,5)
|
||||
#define GPIOR2_Bit6 GPIO_BITREG(GPIOR2,6)
|
||||
#define GPIOR2_Bit7 GPIO_BITREG(GPIOR2,7)
|
||||
|
||||
#endif
|
||||
|
||||
/* Global Interrupts */
|
||||
#if defined(__GNUC__)
|
||||
#define __enable_interrupt() sei()
|
||||
#define __disable_interrupt() cli()
|
||||
#endif
|
||||
|
||||
/* Interrupts */
|
||||
#if defined(__ICCAVR__)
|
||||
#define PRAGMA(x) _Pragma( #x )
|
||||
#define ISR(vec) PRAGMA( vector=vec ) __interrupt void handler_##vec(void)
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#include <avr/interrupt.h>
|
||||
#endif
|
||||
|
||||
/* Flash */
|
||||
#if defined(__ICCAVR__)
|
||||
#define FLASH_DECLARE(x) __flash x
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#define FLASH_DECLARE(x) x __attribute__((__progmem__))
|
||||
#endif
|
||||
|
||||
/* EEPROM */
|
||||
#if defined(__ICCAVR__)
|
||||
#define EEPROM_DECLARE(x) __eeprom x
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#include <avr/eeprom.h>
|
||||
#define EEPROM_DECLARE(x) x __attribute__((section (".eeprom")))
|
||||
#endif
|
||||
|
||||
/* IAR intrinsic routines */
|
||||
#if defined(__GNUC__)
|
||||
/* FIXME: intrinsic routines: map to assembler for size/speed */
|
||||
#define __multiply_unsigned(x,y) ((x)*(y))
|
||||
/* FIXME: __root means to not optimize or strip */
|
||||
#define __root
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,168 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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 "hardware.h"
|
||||
#include "timer.h"
|
||||
#include "rs485.h"
|
||||
#include "datalink.h"
|
||||
#include "npdu.h"
|
||||
#include "handlers.h"
|
||||
#include "txbuf.h"
|
||||
#include "iam.h"
|
||||
#include "device.h"
|
||||
#include "av.h"
|
||||
|
||||
/* From the WhoIs hander - performed by the DLMSTP module */
|
||||
extern bool Send_I_Am_Flag;
|
||||
/* local version override */
|
||||
const char *BACnet_Version = "1.0";
|
||||
|
||||
/* For porting to IAR, see:
|
||||
http://www.avrfreaks.net/wiki/index.php/Documentation:AVR_GCC/IarToAvrgcc*/
|
||||
|
||||
/* dummy function - so we can use default demo handlers */
|
||||
bool dcc_communication_enabled(
|
||||
void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void init(
|
||||
void)
|
||||
{
|
||||
/* Initialize the Clock Prescaler for ATmega48/88/168 */
|
||||
/* The default CLKPSx bits are factory set to 0011 */
|
||||
/* Enbable the Clock Prescaler */
|
||||
CLKPR = _BV(CLKPCE);
|
||||
/* CLKPS3 CLKPS2 CLKPS1 CLKPS0 Clock Division Factor
|
||||
------ ------ ------ ------ ---------------------
|
||||
0 0 0 0 1
|
||||
0 0 0 1 2
|
||||
0 0 1 0 4
|
||||
0 0 1 1 8
|
||||
0 1 0 0 16
|
||||
0 1 0 1 32
|
||||
0 1 1 0 64
|
||||
0 1 1 1 128
|
||||
1 0 0 0 256
|
||||
1 x x x Reserved
|
||||
*/
|
||||
/* Set the CLKPS3..0 bits to Prescaler of 1 */
|
||||
CLKPR = 0;
|
||||
/* Initialize I/O ports */
|
||||
/* For Port DDRx (Data Direction) Input=0, Output=1 */
|
||||
/* For Port PORTx (Bit Value) TriState=0, High=1 */
|
||||
DDRB = 0;
|
||||
PORTB = 0;
|
||||
DDRC = 0;
|
||||
PORTC = 0;
|
||||
DDRD = 0;
|
||||
PORTD = 0;
|
||||
|
||||
/* Configure the watchdog timer - Disabled for testing */
|
||||
BIT_CLEAR(MCUSR, WDRF);
|
||||
WDTCSR = 0;
|
||||
|
||||
/* Configure Specialized Hardware */
|
||||
RS485_Initialize();
|
||||
|
||||
/* configure one LED for NPDU indication */
|
||||
/* default: off, output */
|
||||
LED_NPDU_OFF();
|
||||
LED_NPDU_INIT();
|
||||
/* Configure Software LED */
|
||||
LED_GREEN_INIT();
|
||||
LED_GREEN_OFF();
|
||||
|
||||
/* Configure Timer0 for millisecond timer */
|
||||
Timer_Initialize();
|
||||
|
||||
/* Enable global interrupts */
|
||||
__enable_interrupt();
|
||||
}
|
||||
|
||||
static void task_milliseconds(
|
||||
void)
|
||||
{
|
||||
while (Timer_Milliseconds) {
|
||||
Timer_Milliseconds--;
|
||||
/* add other millisecond timer tasks here */
|
||||
RS485_LED_Timers();
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t Address_Switch;
|
||||
|
||||
static void input_switch_read(
|
||||
void)
|
||||
{
|
||||
uint8_t value;
|
||||
static uint8_t old_value = 0;
|
||||
|
||||
value = BITMASK_CHECK(PINC, 0x0F);
|
||||
value |= (BITMASK_CHECK(PINB, 0x07) << 4);
|
||||
if (value != old_value) {
|
||||
old_value = value;
|
||||
} else {
|
||||
if (old_value != Address_Switch) {
|
||||
Address_Switch = old_value;
|
||||
#if defined(BACDL_MSTP)
|
||||
dlmstp_set_mac_address(Address_Switch);
|
||||
#endif
|
||||
Device_Set_Object_Instance_Number(86000 + Address_Switch);
|
||||
Send_I_Am_Flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t PDUBuffer[MAX_MPDU];
|
||||
int main(
|
||||
void)
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
BACNET_ADDRESS src; /* source address */
|
||||
|
||||
init();
|
||||
#if defined(BACDL_MSTP)
|
||||
RS485_Set_Baud_Rate(38400);
|
||||
dlmstp_set_max_master(127);
|
||||
dlmstp_set_max_info_frames(1);
|
||||
#endif
|
||||
datalink_init(NULL);
|
||||
for (;;) {
|
||||
input_switch_read();
|
||||
task_milliseconds();
|
||||
/* other tasks */
|
||||
/* BACnet handling */
|
||||
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
|
||||
if (pdu_len) {
|
||||
LED_NPDU_ON();
|
||||
npdu_handler(&src, &PDUBuffer[0], pdu_len);
|
||||
LED_NPDU_OFF();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
This port was done with the Atmel ATmega168 using two tools:
|
||||
1. The WinAVR compiler avr-gcc (GCC) 4.1.2 (WinAVR 20070525)
|
||||
and tools from <http://winavr.sourceforge.net/>, hints and
|
||||
sample code from <http://www.avrfreaks.net/> and
|
||||
<http://savannah.gnu.org/projects/avr-libc/>.
|
||||
"avr-binutils, avr-gcc, and avr-libc form the heart of the
|
||||
Free Software toolchain for the Atmel AVR microcontrollers."
|
||||
2. AVR Studio from Atmel <http://atmel.com/>
|
||||
|
||||
Alternatively, the project also builds using IAR Embedded Workbench AVR.
|
||||
|
||||
The hardware is expected to utilize the signals as defined
|
||||
in the spreadsheet hardware.ods (OpenOffice.org calc).
|
||||
Attach a DS75176 RS-485 transceiver (or similar) to the USART.
|
||||
DS75176 ATmega168
|
||||
------ ---------
|
||||
RO RXD
|
||||
/RE --choice of I/O
|
||||
DE --choice of I/O
|
||||
DI TXD
|
||||
GND GND
|
||||
DO --to RS-485 wire
|
||||
DO --to RS-485 wire
|
||||
+5V From 5V Regulator
|
||||
|
||||
The makefile allows you to build just the dlmstp or a simple
|
||||
server. dlmstp is the datalink layer for MS/TP over RS-485.
|
||||
|
||||
I used the makefile from the command line on Windows:
|
||||
C:\code\bacnet-stack\ports\atmega168> make clean all
|
||||
|
||||
CStack check for GCC is included in the device object as property 512.
|
||||
The compile shows 648 bytes of RAM used, and the ATmega168 has 1024 bytes
|
||||
of RAM, leaving 376 for the CStack. Property 512 index 0 returns 376 from
|
||||
a ReadProperty request. My understanding is that the remaining unallocated
|
||||
RAM is used for the CStack. Keep this in mind when developing.
|
||||
After some ReadProperty and WriteProperty requests, the CStack shows
|
||||
159 CStack bytes free, meaning that 216 bytes of CStack are used.
|
||||
Note that the value 0xC5 (197) was used to paint the CStack.
|
||||
|
||||
I also used the bacnet.aps project file in AVR Studio to
|
||||
make the project and simulate it, but have not kept it updated (FIXME).
|
||||
|
||||
Compiler settings for IAR Embedded Workbench (FIXME: makefile?):
|
||||
General Options
|
||||
---------------
|
||||
Target
|
||||
Processor configuration: --cpu=m168. ATmega168
|
||||
Memory Model: Small
|
||||
System configuration: Configure system using dialogs (not in .XCL file)
|
||||
Output
|
||||
Executable
|
||||
Output Directories: Debug\Exe, Debug\Obj, Debug\List
|
||||
Library Configuration
|
||||
Library: CLIB
|
||||
Library Options
|
||||
Printf formatter: Small
|
||||
Scanf formatter: Medium
|
||||
Heap Configuration
|
||||
CLIB heap size: 0x10
|
||||
System
|
||||
CSTACK: 0x200
|
||||
RSTACK: 32
|
||||
Initialize unused interrupt vectors with RETI instructions (enabled)
|
||||
Enable bit defnitions in I/O-Include files. (enabled)
|
||||
MISRA C
|
||||
not enabled
|
||||
|
||||
C/C++ Compiler
|
||||
--------------
|
||||
Language
|
||||
Language: C
|
||||
Require prototypes (not enabled)
|
||||
Allow IAR extensions
|
||||
Plain 'char' is Signed
|
||||
Enable multibyte support (not enabled)
|
||||
Code
|
||||
Memory utilization:
|
||||
Place aggregate initializers in flash memory (enabled)
|
||||
Force generation of all global and static variables (not enabled)
|
||||
Register utilization:
|
||||
Number of registers to lock for global variables: 0
|
||||
Use ICCA90 1.x calling convention (not enabled)
|
||||
Optimizations
|
||||
Size: High (Maximum optimization)
|
||||
Number of cross-call passes: Unlimited
|
||||
Always do cross call optimization (not enabled)
|
||||
Output
|
||||
Module type: Override default (not enabled)
|
||||
Object module name (not enabled)
|
||||
Generate debug information (enabled)
|
||||
No error messages in output files (not enabled)
|
||||
List
|
||||
Output list file (not enabled)
|
||||
Output assembler file (enabled)
|
||||
Preprocessor
|
||||
Ignore standard include paths (not enabled)
|
||||
Include paths:
|
||||
$PROJ_DIR$
|
||||
$PROJ_DIR$\..\..\include
|
||||
Preinclude file: (none)
|
||||
Defined symbols:
|
||||
BACDL_MSTP
|
||||
MAX_APDU=50
|
||||
BIG_ENDIAN=0
|
||||
MAX_TSM_TRANSACTIONS=0
|
||||
BACAPP_REAL
|
||||
BACAPP_UNSIGNED
|
||||
BACAPP_ENUMERATED
|
||||
BACAPP_CHARACTER_STRING
|
||||
BACAPP_OBJECT_ID
|
||||
WRITE_PROPERTY
|
||||
Diagnostics
|
||||
(not enabled)
|
||||
MISRA C
|
||||
(not enabled)
|
||||
Extra Options
|
||||
Use command line options (not enabled)
|
||||
|
||||
Note: The BACnet Stack at Sourceforge source code has to be built
|
||||
with lots of different compilers. The IAR compiler has particularly
|
||||
strong (pedantic) source checking and generates several warnings when
|
||||
compiling the source code. Unfortunately not all warnings can be
|
||||
fixed by modifying the source code. Some warnings have therefore been
|
||||
disabled in the project file.
|
||||
Compiler Diagnostics:
|
||||
(Pe550) I initilize all local variables as a best practice.
|
||||
Linker Diagnostics:
|
||||
(w31) The supplied standard libraries expect char parameters to
|
||||
be unsigned (in functions such as strncpy(), etc.). It may
|
||||
be possible to recompile the libraries with signed plain char's.
|
||||
|
||||
The BACnet Capabilities include WhoIs, I-Am, ReadProperty, and
|
||||
WriteProperty support. The BACnet objects include a Device object,
|
||||
10 Binary Value objects, and 10 Analog Value objects. An LED is
|
||||
controlled by Binary Value object instance 0. All required object
|
||||
properties can be retrieved using ReadProperty. The Present_Value
|
||||
property of the Analog Value and Binary Value objects can be
|
||||
written using WriteProperty. The Object_Identifier, Object_Name,
|
||||
Max_Info_Frames, Max_Master, and baud rate (property 9600) of the
|
||||
Device object can be written using WriteProperty.
|
||||
|
||||
With full optimization, the statistics on the demo are:
|
||||
|
||||
IAR Atmel AVR C/C++ Compiler V5.10A/W32
|
||||
12 732 bytes of CODE memory (+ 36 range fill )
|
||||
955 bytes of DATA memory (+ 24 absolute ) (includes CStack=0×200)
|
||||
|
||||
avr-gcc (GCC) 4.2.2 (WinAVR 20071221rc1)
|
||||
Program: 15790 bytes (96.4% Full)
|
||||
Data: 414 bytes (40.4% Full) (does not include CStack=0×262)
|
||||
|
||||
Hopefully you find this code useful!
|
||||
|
||||
Steve Karg <skarg@users.sourceforge.net>
|
||||
@@ -0,0 +1,327 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/* 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 "mstp.h" */
|
||||
|
||||
/* This file has been customized for use with ATMEGA168 */
|
||||
#include "hardware.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* Timers for turning off the TX,RX LED indications */
|
||||
static uint8_t LED1_Off_Timer;
|
||||
static uint8_t LED3_Off_Timer;
|
||||
|
||||
/* baud rate */
|
||||
static uint32_t RS485_Baud = 9600;
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in
|
||||
* receive mode.
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Initialize(
|
||||
void)
|
||||
{
|
||||
/* enable Transmit and Receive */
|
||||
UCSR0B = _BV(TXEN0) | _BV(RXEN0);
|
||||
|
||||
/* Set USART Control and Status Register n C */
|
||||
/* Asynchronous USART 8-bit data, No parity, 1 stop */
|
||||
/* Set USART Mode Select: UMSELn1 UMSELn0 = 00 for Asynchronous USART */
|
||||
/* Set Parity Mode: UPMn1 UPMn0 = 00 for Parity Disabled */
|
||||
/* Set Stop Bit Select: USBSn = 0 for 1 stop bit */
|
||||
/* Set Character Size: UCSZn2 UCSZn1 UCSZn0 = 011 for 8-bit */
|
||||
/* Clock Polarity: UCPOLn = 0 when asynchronous mode is used. */
|
||||
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
|
||||
/* Clear Power Reduction USART0 */
|
||||
BIT_CLEAR(PRR, PRUSART0);
|
||||
/* Use port PD2 for RTS - enable and disable of Transceiver Tx/Rx */
|
||||
/* Set port bit as Output - initially receiving */
|
||||
BIT_CLEAR(PORTD, PD2);
|
||||
BIT_SET(DDRD, DDD2);
|
||||
/* Configure Transmit and Receive LEDs - initially off */
|
||||
BIT_SET(PORTD, PD6);
|
||||
BIT_SET(PORTD, PD7);
|
||||
BIT_SET(DDRD, DDD6);
|
||||
BIT_SET(DDRD, DDD7);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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: true if valid baud rate
|
||||
* 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;
|
||||
/* 2x speed mode */
|
||||
BIT_SET(UCSR0A, U2X0);
|
||||
/* configure baud rate */
|
||||
UBRR0 = (F_CPU / (8UL * RS485_Baud)) - 1;
|
||||
/* FIXME: store the baud rate */
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Enable or disable the transmitter
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Transmitter_Enable(
|
||||
bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
BIT_SET(PORTD, PD2);
|
||||
} else {
|
||||
BIT_CLEAR(PORTD, PD2);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Waits on the SilenceTimer for 40 bits.
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
void RS485_Turnaround_Delay(
|
||||
void)
|
||||
{
|
||||
uint8_t nbytes = 4;
|
||||
|
||||
RS485_Transmitter_Enable(false);
|
||||
while (nbytes) {
|
||||
while (!BIT_CHECK(UCSR0A, UDRE0)) {
|
||||
/* do nothing - wait until Tx buffer is empty */
|
||||
}
|
||||
/* Send the data byte */
|
||||
UDR0 = 0xff;
|
||||
nbytes--;
|
||||
}
|
||||
/* was the frame sent? */
|
||||
while (!BIT_CHECK(UCSR0A, TXC0)) {
|
||||
/* do nothing - wait until the entire frame in the
|
||||
Transmit Shift Register has been shifted out */
|
||||
}
|
||||
/* Clear the Transmit Complete flag by writing a one to it. */
|
||||
BIT_SET(UCSR0A, TXC0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Timers for delaying the LED indicators going off
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: expected to be called once a millisecond
|
||||
*****************************************************************************/
|
||||
void RS485_LED_Timers(
|
||||
void)
|
||||
{
|
||||
if (LED1_Off_Timer) {
|
||||
LED1_Off_Timer--;
|
||||
if (LED1_Off_Timer == 0) {
|
||||
BIT_SET(PORTD, PD6);
|
||||
}
|
||||
}
|
||||
if (LED3_Off_Timer) {
|
||||
LED3_Off_Timer--;
|
||||
if (LED3_Off_Timer == 0) {
|
||||
BIT_SET(PORTD, PD7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Turn on the LED, and set the off timer to turn it off
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
static void RS485_LED1_On(
|
||||
void)
|
||||
{
|
||||
BIT_CLEAR(PORTD, PD6);
|
||||
LED1_Off_Timer = 20;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Turn on the LED, and set the off timer to turn it off
|
||||
* RETURN: none
|
||||
* ALGORITHM: none
|
||||
* NOTES: none
|
||||
*****************************************************************************/
|
||||
static void RS485_LED3_On(
|
||||
void)
|
||||
{
|
||||
BIT_CLEAR(PORTD, PD7);
|
||||
LED3_Off_Timer = 20;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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 */
|
||||
RS485_LED3_On();
|
||||
while (nbytes) {
|
||||
while (!BIT_CHECK(UCSR0A, UDRE0)) {
|
||||
/* do nothing - wait until Tx buffer is empty */
|
||||
}
|
||||
/* Send the data byte */
|
||||
UDR0 = *buffer;
|
||||
buffer++;
|
||||
nbytes--;
|
||||
}
|
||||
/* was the frame sent? */
|
||||
while (!BIT_CHECK(UCSR0A, TXC0)) {
|
||||
/* do nothing - wait until the entire frame in the
|
||||
Transmit Shift Register has been shifted out */
|
||||
}
|
||||
/* Clear the Transmit Complete flag by writing a one to it. */
|
||||
BIT_SET(UCSR0A, TXC0);
|
||||
/* per MSTP spec, sort of */
|
||||
Timer_Silence_Reset();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DESCRIPTION: Return true if a framing or overrun error is present
|
||||
* RETURN: true if error
|
||||
* ALGORITHM: autobaud - if there are a lot of errors, switch baud rate
|
||||
* NOTES: Clears any error flags.
|
||||
*****************************************************************************/
|
||||
bool RS485_ReceiveError(
|
||||
void)
|
||||
{
|
||||
bool ReceiveError = false;
|
||||
uint8_t dummy_data;
|
||||
|
||||
/* check for framing error */
|
||||
#if 0
|
||||
if (BIT_CHECK(UCSR0A, FE0)) {
|
||||
/* FIXME: how do I clear the error flags? */
|
||||
BITMASK_CLEAR(UCSR0A, (_BV(FE0) | _BV(DOR0) | _BV(UPE0)));
|
||||
ReceiveError = true;
|
||||
}
|
||||
#endif
|
||||
/* check for overrun error */
|
||||
if (BIT_CHECK(UCSR0A, DOR0)) {
|
||||
/* flush the receive buffer */
|
||||
do {
|
||||
dummy_data = UDR0;
|
||||
} while (BIT_CHECK(UCSR0A, RXC0));
|
||||
ReceiveError = true;
|
||||
}
|
||||
if (ReceiveError) {
|
||||
RS485_LED1_On();
|
||||
}
|
||||
|
||||
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 * data)
|
||||
{
|
||||
bool DataAvailable = false;
|
||||
|
||||
/* check for data */
|
||||
if (BIT_CHECK(UCSR0A, RXC0)) {
|
||||
*data = UDR0;
|
||||
DataAvailable = true;
|
||||
RS485_LED1_On();
|
||||
}
|
||||
|
||||
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 /* TEST_RS485 */
|
||||
@@ -0,0 +1,73 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2004 Steve Karg
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
|
||||
#ifndef RS485_H
|
||||
#define RS485_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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);
|
||||
|
||||
void RS485_LED_Timers(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stdint.h>
|
||||
#include "hardware.h"
|
||||
|
||||
/* stack checking */
|
||||
#if defined(__GNUC__)
|
||||
extern uint8_t _end;
|
||||
extern uint8_t __stack;
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define STACK_CANARY (0xC5)
|
||||
void stack_init(
|
||||
void) __attribute__ ((naked)) __attribute__ ((section(".init1")));
|
||||
#endif
|
||||
|
||||
void stack_init(
|
||||
void)
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
#if 0
|
||||
uint8_t *p = &_end;
|
||||
|
||||
while (p <= &__stack) {
|
||||
*p = STACK_CANARY;
|
||||
p++;
|
||||
}
|
||||
#else
|
||||
__asm volatile (
|
||||
" ldi r30,lo8(_end)\n" " ldi r31,hi8(_end)\n" " ldi r24,lo8(0xc5)\n" /* STACK_CANARY = 0xc5 */
|
||||
" ldi r25,hi8(__stack)\n" " rjmp .cmp\n" ".loop:\n"
|
||||
" st Z+,r24\n" ".cmp:\n" " cpi r30,lo8(__stack)\n"
|
||||
" cpc r31,r25\n" " brlo .loop\n" " breq .loop"::);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned stack_size(
|
||||
void)
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
return (&__stack) - (&_end);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t stack_byte(
|
||||
unsigned offset)
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
return *(&_end + offset);
|
||||
#else
|
||||
offset = offset;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned stack_unused(
|
||||
void)
|
||||
{
|
||||
unsigned count = 0;
|
||||
#if defined(__GNUC__)
|
||||
uint8_t *p = &_end;
|
||||
|
||||
while (p <= &__stack) {
|
||||
if ((*p) != STACK_CANARY) {
|
||||
count = p - (&_end);
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef STACK_H
|
||||
#define STACK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* C stack checking */
|
||||
void stack_init(
|
||||
void);
|
||||
|
||||
unsigned stack_size(
|
||||
void);
|
||||
|
||||
uint8_t stack_byte(
|
||||
unsigned offset);
|
||||
|
||||
unsigned stack_unused(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user