From d39044261c8f275716ceb23d72d4c0658a157fd7 Mon Sep 17 00:00:00 2001 From: skarg Date: Mon, 26 Jun 2017 17:48:02 +0000 Subject: [PATCH] Added some arduino_uno files that we missed during first import [WIP]. --- bacnet-stack/ports/arduino_uno/bip.h | 117 ++++++ bacnet-stack/ports/arduino_uno/device.c | 460 ++++++++++++++++++++++++ bacnet-stack/ports/arduino_uno/h_rp.c | 161 +++++++++ bacnet-stack/ports/arduino_uno/uart.c | 44 +++ bacnet-stack/ports/arduino_uno/uart.h | 27 ++ 5 files changed, 809 insertions(+) create mode 100644 bacnet-stack/ports/arduino_uno/bip.h create mode 100644 bacnet-stack/ports/arduino_uno/device.c create mode 100644 bacnet-stack/ports/arduino_uno/h_rp.c create mode 100644 bacnet-stack/ports/arduino_uno/uart.c create mode 100644 bacnet-stack/ports/arduino_uno/uart.h diff --git a/bacnet-stack/ports/arduino_uno/bip.h b/bacnet-stack/ports/arduino_uno/bip.h new file mode 100644 index 00000000..1bb3284d --- /dev/null +++ b/bacnet-stack/ports/arduino_uno/bip.h @@ -0,0 +1,117 @@ +/************************************************************************** +* +* Copyright (C) 2012 Steve Karg +* +* 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 +#include +#include +#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 diff --git a/bacnet-stack/ports/arduino_uno/device.c b/bacnet-stack/ports/arduino_uno/device.c new file mode 100644 index 00000000..60cf0a7a --- /dev/null +++ b/bacnet-stack/ports/arduino_uno/device.c @@ -0,0 +1,460 @@ +/************************************************************************** +* +* Copyright (C) 2007 Steve Karg +* +* 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 +#include +#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; +} diff --git a/bacnet-stack/ports/arduino_uno/h_rp.c b/bacnet-stack/ports/arduino_uno/h_rp.c new file mode 100644 index 00000000..5a1ffe2b --- /dev/null +++ b/bacnet-stack/ports/arduino_uno/h_rp.c @@ -0,0 +1,161 @@ +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* 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 +#include +#include +#include +#include +#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; +} diff --git a/bacnet-stack/ports/arduino_uno/uart.c b/bacnet-stack/ports/arduino_uno/uart.c new file mode 100644 index 00000000..83b5674a --- /dev/null +++ b/bacnet-stack/ports/arduino_uno/uart.c @@ -0,0 +1,44 @@ +/** + * @file + * @author Miguel Fernandes + * @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 +#include +#include +#include +#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; +} diff --git a/bacnet-stack/ports/arduino_uno/uart.h b/bacnet-stack/ports/arduino_uno/uart.h new file mode 100644 index 00000000..e503c888 --- /dev/null +++ b/bacnet-stack/ports/arduino_uno/uart.h @@ -0,0 +1,27 @@ +/** + * @file + * @author Miguel Fernandes + * @date 6 de Jun de 2013 + * @brief BACnet Virtual Link Control for Wiznet on Arduino-Uno + */ +#ifndef UART_H_ +#define UART_H_ + +#include +#include +#include +#include + +#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