diff --git a/ports/at91sam7s/Makefile b/ports/at91sam7s/Makefile index 9a9c5cd3..c207e07d 100644 --- a/ports/at91sam7s/Makefile +++ b/ports/at91sam7s/Makefile @@ -61,6 +61,7 @@ DEMOSRC = ai.c \ bi.c \ bv.c \ device.c \ + netport.c \ $(BACNET_BASIC)/tsm/tsm.c \ $(BACNET_BASIC)/sys/ringbuf.c \ $(BACNET_BASIC)/npdu/h_npdu.c \ diff --git a/ports/at91sam7s/bacnet.ewp b/ports/at91sam7s/bacnet.ewp index 0bc6556b..1ff4a2a6 100644 --- a/ports/at91sam7s/bacnet.ewp +++ b/ports/at91sam7s/bacnet.ewp @@ -1108,6 +1108,9 @@ $PROJ_DIR$\device.c + + $PROJ_DIR$\netport.c + $PROJ_DIR$\dlmstp.c diff --git a/ports/at91sam7s/device.c b/ports/at91sam7s/device.c index 26dc3fed..26200817 100644 --- a/ports/at91sam7s/device.c +++ b/ports/at91sam7s/device.c @@ -39,6 +39,9 @@ #include "bacnet/basic/services.h" #include "bacnet/proplist.h" /* objects */ +#if (BACNET_PROTOCOL_REVISION >= 17) +#include "bacnet/basic/object/netport.h" +#endif #include "bacnet/basic/object/device.h" #include "bacnet/basic/object/ai.h" #include "bacnet/basic/object/av.h" @@ -64,11 +67,12 @@ static struct my_object_functions { 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_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, @@ -85,6 +89,12 @@ static struct my_object_functions { 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 }, +#if (BACNET_PROTOCOL_REVISION >= 17) + { OBJECT_NETWORK_PORT, Network_Port_Init, Network_Port_Count, + Network_Port_Index_To_Instance, Network_Port_Valid_Instance, + Network_Port_Object_Name, Network_Port_Read_Property, + Network_Port_Write_Property, Network_Port_Property_Lists }, +#endif { MAX_BACNET_OBJECT_TYPE, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; /* note: you really only need to define variables for @@ -769,7 +779,7 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata) break; case 9600: apdu_len = - encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate()); + encode_application_unsigned(&apdu[0], rs485_baud_rate()); break; default: rpdata->error_class = ERROR_CLASS_PROPERTY; @@ -896,9 +906,9 @@ bool Device_Write_Property_Local(BACNET_WRITE_PROPERTY_DATA *wp_data) 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 { + status = rs485_baud_rate_set(value.type.Unsigned_Int); + } + if (!status) { wp_data->error_class = ERROR_CLASS_PROPERTY; wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; } diff --git a/ports/at91sam7s/dlmstp.c b/ports/at91sam7s/dlmstp.c index 8af419b6..f9a85aea 100644 --- a/ports/at91sam7s/dlmstp.c +++ b/ports/at91sam7s/dlmstp.c @@ -1396,3 +1396,13 @@ void dlmstp_get_broadcast_address(BACNET_ADDRESS *dest) return; } + +uint8_t dlmstp_max_info_frames_limit(void) +{ + return MSTP_PDU_PACKET_COUNT; +} + +uint8_t dlmstp_max_master_limit(void) +{ + return 127; +} diff --git a/ports/at91sam7s/init.c b/ports/at91sam7s/init.c index b50aac11..0778ef3b 100644 --- a/ports/at91sam7s/init.c +++ b/ports/at91sam7s/init.c @@ -21,12 +21,32 @@ /* Include the board file description */ #include "board.h" +#if defined(__ICCARM__) +//------------------------------------------------------------------------------ +// Internal functions +//------------------------------------------------------------------------------ +static void AT91F_Spurious_handler( void ) +{ + while (1); +} + +static void AT91F_Default_FIQ_handler( void ) +{ + while (1); +} + +static void AT91F_Default_IRQ_handler( void ) +{ + while (1); +} +#else /* 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); +#endif /**---------------------------------------------------------------------------- */ diff --git a/ports/at91sam7s/isr.c b/ports/at91sam7s/isr.c index 9781354a..cd882c67 100644 --- a/ports/at91sam7s/isr.c +++ b/ports/at91sam7s/isr.c @@ -23,6 +23,8 @@ #include "at91sam7s256.h" #include "isr.h" +#if defined(__GNUC__) +/* GCC */ #define IRQ_MASK 0x00000080 #define FIQ_MASK 0x00000040 #define INT_MASK (IRQ_MASK | FIQ_MASK) @@ -91,3 +93,4 @@ unsigned enableFIQ(void) __set_cpsr(_cpsr & ~FIQ_MASK); return _cpsr; } +#endif diff --git a/ports/at91sam7s/isr.h b/ports/at91sam7s/isr.h index b8d89dfb..554894a2 100644 --- a/ports/at91sam7s/isr.h +++ b/ports/at91sam7s/isr.h @@ -32,6 +32,8 @@ #include #define isr_enable() __enable_interrupt() #define isr_disable() __disable_interrupt() +#define __get_cpsr __get_CPSR +#define __set_cpsr __set_CPSR #endif #if defined(__GNUC__) #define isr_enable() enableIRQ();enableFIQ(); diff --git a/ports/at91sam7s/main.c b/ports/at91sam7s/main.c index 9b67ccf7..4da0b38c 100644 --- a/ports/at91sam7s/main.c +++ b/ports/at91sam7s/main.c @@ -133,7 +133,7 @@ static inline void bacnet_init(void) #if defined(BACDL_MSTP) uint8_t MAC_Address = 0x55; - RS485_Set_Baud_Rate(38400); + rs485_baud_rate_set(38400); dlmstp_set_mac_address(MAC_Address); dlmstp_set_max_master(127); dlmstp_set_max_info_frames(1); diff --git a/ports/at91sam7s/netport.c b/ports/at91sam7s/netport.c new file mode 100644 index 00000000..3a2899a6 --- /dev/null +++ b/ports/at91sam7s/netport.c @@ -0,0 +1,748 @@ +/** + * @file + * @author Steve Karg + * @date 2016 + * @brief Network port objects, customize for your use + * + * @section DESCRIPTION + * + * The Network Port object provides access to the configuration + * and properties of network ports of a device. + * + * @section LICENSE + * + * 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 +#include "bacnet/config.h" +#include "bacnet/basic/binding/address.h" +#include "bacnet/bacdef.h" +#include "bacnet/bacapp.h" +#include "bacnet/bacdcode.h" +#include "bacnet/npdu.h" +#include "bacnet/apdu.h" +#include "bacnet/basic/object/device.h" +/* MS/TP specific */ +#include "bacnet/datalink/dlmstp.h" +#include "rs485.h" +//#include "nvdata.h" +/* me */ +#include "bacnet/basic/object/netport.h" + +/* our local object data */ +struct object_data { + bool Changes_Pending : 1; + uint8_t MAC_Address[1]; + uint8_t Max_Master; + uint8_t Max_Info_Frames; + float Link_Speed; +}; + +/* this object example only supports 1 instance */ +#define BACNET_NETWORK_PORTS_MAX 1 +struct object_data Object_List[BACNET_NETWORK_PORTS_MAX]; +/* instance number - can be overridden */ +#ifndef BACNET_NETWORK_PORT_INSTANCE +#define BACNET_NETWORK_PORT_INSTANCE 1 +#endif + +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Network_Port_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_STATUS_FLAGS, PROP_RELIABILITY, + PROP_OUT_OF_SERVICE, PROP_NETWORK_TYPE, PROP_PROTOCOL_LEVEL, + PROP_NETWORK_NUMBER, PROP_NETWORK_NUMBER_QUALITY, PROP_CHANGES_PENDING, + PROP_APDU_LENGTH, PROP_LINK_SPEED, -1 }; + +static const int Network_Port_Properties_Optional[] = { PROP_MAC_ADDRESS, + PROP_MAX_MASTER, PROP_MAX_INFO_FRAMES, -1 }; + +static const int Network_Port_Properties_Proprietary[] = { -1 }; + +/** + * Returns the list of required, optional, and proprietary properties. + * Used by ReadPropertyMultiple service. + * + * @param object_instance - object-instance number of the object + * @param pRequired - pointer to list of int terminated by -1, of + * BACnet required properties for this object. + * @param pOptional - pointer to list of int terminated by -1, of + * BACnet optkional properties for this object. + * @param pProprietary - pointer to list of int terminated by -1, of + * BACnet proprietary properties for this object. + */ +void Network_Port_Property_List(uint32_t object_instance, + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + (void)object_instance; + if (pRequired) { + *pRequired = Network_Port_Properties_Required; + } + if (pOptional) { + *pOptional = Network_Port_Properties_Optional; + } + if (pProprietary) { + *pProprietary = Network_Port_Properties_Proprietary; + } + + return; +} + +/** + * Returns the list of required, optional, and proprietary properties. + * Used by ReadPropertyMultiple service. + * + * @param pRequired - pointer to list of int terminated by -1, of + * BACnet required properties for this object. + * @param pOptional - pointer to list of int terminated by -1, of + * BACnet optkional properties for this object. + * @param pProprietary - pointer to list of int terminated by -1, of + * BACnet proprietary properties for this object. + */ +void Network_Port_Property_Lists( + const int **pRequired, const int **pOptional, const int **pProprietary) +{ + Network_Port_Property_List( + BACNET_NETWORK_PORT_INSTANCE, pRequired, pOptional, pProprietary); +} + +/** + * For a given object instance-number, loads the object-name into + * a characterstring. Note that the object name must be unique + * within this device. + * + * @param object_instance - object-instance number of the object + * @param object_name - holds the object-name retrieved + * + * @return true if object-name was retrieved + */ +bool Network_Port_Object_Name( + uint32_t object_instance, BACNET_CHARACTER_STRING *object_name) +{ + bool status = false; + + if (object_instance == BACNET_NETWORK_PORT_INSTANCE) { + status = characterstring_init_ansi(object_name, "NP-1"); + } + + return status; +} + +/** + * Determines if a given Network Port instance is valid + * + * @param object_instance - object-instance number of the object + * + * @return true if the instance is valid, and false if not + */ +bool Network_Port_Valid_Instance(uint32_t object_instance) +{ + if (object_instance == BACNET_NETWORK_PORT_INSTANCE) { + return true; + } + + return false; +} + +/** + * Determines the number of Network Port objects + * + * @return Number of Network Port objects + */ +unsigned Network_Port_Count(void) +{ + return BACNET_NETWORK_PORTS_MAX; +} + +/** + * Determines the object instance-number for a given 0..N index + * of Network Port objects where N is Network_Port_Count(). + * + * @param index - 0..BACNET_NETWORK_PORTS_MAX value + * + * @return object instance-number for the given index, or BACNET_MAX_INSTANCE + * for an invalid index. + */ +uint32_t Network_Port_Index_To_Instance(unsigned index) +{ + if (index < BACNET_NETWORK_PORTS_MAX) { + return BACNET_NETWORK_PORT_INSTANCE; + } + + return BACNET_MAX_INSTANCE; +} + +/** + * For a given object instance-number, determines a 0..N index + * of Network Port objects where N is Network_Port_Count(). + * + * @param object_instance - object-instance number of the object + * + * @return index for the given instance-number, or BACNET_NETWORK_PORTS_MAX + * if not valid. + */ +unsigned Network_Port_Instance_To_Index(uint32_t object_instance) +{ + if (object_instance == BACNET_NETWORK_PORT_INSTANCE) { + return 0; + } + + return BACNET_NETWORK_PORTS_MAX; +} + +/** + * For a given object instance-number, returns the out-of-service + * property value + * + * @param object_instance - object-instance number of the object + * + * @return out-of-service property value + */ +bool Network_Port_Out_Of_Service(uint32_t object_instance) +{ + (void)object_instance; + return false; +} + +/** + * For a given object instance-number, gets the reliability. + * + * @param object_instance - object-instance number of the object + * + * @return reliability value + */ +BACNET_RELIABILITY Network_Port_Reliability(uint32_t object_instance) +{ + (void)object_instance; + return RELIABILITY_NO_FAULT_DETECTED; +} + +/** + * For a given object instance-number, gets the BACnet Network Type. + * + * @param object_instance - object-instance number of the object + * + * @return BACnet network type value + */ +uint8_t Network_Port_Type(uint32_t object_instance) +{ + (void)object_instance; + return PORT_TYPE_MSTP; +} + +/** + * For a given object instance-number, gets the BACnet Network Number. + * + * @param object_instance - object-instance number of the object + * + * @return BACnet network type value + */ +uint16_t Network_Port_Network_Number(uint32_t object_instance) +{ + (void)object_instance; + /* A Network_Number of 0 indicates that the Network_Number + is not known or cannot be determined. */ + return 0; +} + +/** + * For a given object instance-number, gets the quality property + * + * @param object_instance - object-instance number of the object + * + * @return quality property value + */ +BACNET_PORT_QUALITY Network_Port_Quality(uint32_t object_instance) +{ + (void)object_instance; + return PORT_QUALITY_CONFIGURED; +} + +/** + * For a given object instance-number, loads the mac-address into + * an octet string. + * + * @param object_instance - object-instance number of the object + * @param mac_address - holds the mac-address retrieved + * + * @return true if mac-address was retrieved + */ +bool Network_Port_MAC_Address( + uint32_t object_instance, BACNET_OCTET_STRING *mac_address) +{ + (void)object_instance; + Object_List[0].MAC_Address[0] = dlmstp_mac_address(); + + return octetstring_init(mac_address, Object_List[0].MAC_Address, 1); +} + +/** + * @brief For a given object instance-number, set the mac-address and length + * @param object_instance - object-instance number of the object + * @param mac_src - holds the MAC address to be written + * @param mac_len - number of bytes in the MAC address + * @return true if object-name was set + */ +bool Network_Port_MAC_Address_Set( + uint32_t object_instance, uint8_t *mac_src, uint8_t mac_len) +{ + if (mac_len == 1) { + Object_List[0].MAC_Address[0] = mac_src[0]; + Object_List[0].Changes_Pending = true; + return true; + } + + return false; +} + +/** + * For a given object instance-number, gets the BACnet Network Number. + * + * @param object_instance - object-instance number of the object + * + * @return APDU length for this network port + */ +uint16_t Network_Port_APDU_Length(uint32_t object_instance) +{ + (void)object_instance; + return MAX_APDU; +} + +/** + * For a given object instance-number, gets the network communication rate + * as the number of bits per second. A value of 0 indicates an unknown + * communication rate. + * + * @param object_instance - object-instance number of the object + * + * @return Link_Speed for this network port, or 0 if unknown + */ +float Network_Port_Link_Speed(uint32_t object_instance) +{ + (void)object_instance; + Object_List[0].Link_Speed = rs485_baud_rate(); + + return Object_List[0].Link_Speed; +} + +/** + * @brief Set the device link speed (baud rate) + * @param object_instance The object instance number of the object + * @param value The new link speed value + * @return true if value was set + */ +bool Network_Port_Link_Speed_Set(uint32_t object_instance, float value) +{ + bool status = false; + uint32_t baud = (uint32_t)value; + + switch (baud) { + case 9600: + case 19200: + case 38400: + case 57600: + case 76800: + case 115200: + Object_List[0].Link_Speed = value; + Object_List[0].Changes_Pending = true; + status = true; + break; + } + + return status; +} + +/** + * @brief For a given object instance-number, returns the changes-pending flag + * @param object_instance - object-instance number of the object + * @return changes-pending property value + */ +bool Network_Port_Changes_Pending(uint32_t object_instance) +{ + bool flag = false; + unsigned index = 0; + + index = Network_Port_Instance_To_Index(object_instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + flag = Object_List[index].Changes_Pending; + } + + return flag; +} + +/** + * @brief For a given object instance-number, sets the changes-pending flag + * @param object_instance - object-instance number of the object + * @param flag - true=changes pending, false=no changes pending + * @return true if flag was set + */ +bool Network_Port_Changes_Pending_Set(uint32_t instance, bool flag) +{ + unsigned index = 0; + + index = Network_Port_Instance_To_Index(instance); + if (index < BACNET_NETWORK_PORTS_MAX) { + Object_List[index].Changes_Pending = flag; + } else + return false; + + return true; +} + +/** + * @brief For a given object instance-number, gets the MS/TP Max_Master value + * @param object_instance - object-instance number of the object + * @return MS/TP Max_Master value + */ +uint8_t Network_Port_MSTP_Max_Master(uint32_t object_instance) +{ + (void)object_instance; + Object_List[0].Max_Master = dlmstp_max_master(); + + return Object_List[0].Max_Master; +} + +/** + * For a given object instance-number, sets the MS/TP Max_Master value + * + * @param object_instance - object-instance number of the object + * @param value - MS/TP Max_Master value 0..127 + * + * @return true if values are within range and property is set. + */ +bool Network_Port_MSTP_Max_Master_Set(uint32_t object_instance, uint8_t value) +{ + bool status = false; + + (void)object_instance; + if (value <= dlmstp_max_master_limit()) { + Object_List[0].Max_Master = value; + Object_List[0].Changes_Pending = true; + status = true; + } + + return status; +} + +/** + * For a given object instance-number, gets the MS/TP Max_Info_Frames value + * + * @param object_instance - object-instance number of the object + * + * @return MS/TP Max_Info_Frames value + */ +uint8_t Network_Port_MSTP_Max_Info_Frames(uint32_t object_instance) +{ + (void)object_instance; + Object_List[0].Max_Info_Frames = dlmstp_max_info_frames(); + + return Object_List[0].Max_Info_Frames; +} + +/** + * For a given object instance-number, sets the MS/TP Max_Info_Frames value + * + * @param object_instance - object-instance number of the object + * @param value - MS/TP Max_Info_Frames value 0..255 + * + * @return true if values are within range and property is set. + */ +bool Network_Port_MSTP_Max_Info_Frames_Set( + uint32_t object_instance, uint8_t value) +{ + bool status = false; + + (void)object_instance; + if (value <= dlmstp_max_info_frames_limit()) { + Object_List[0].Max_Info_Frames = value; + Object_List[0].Changes_Pending = true; + status = true; + } + + return status; +} + +/** + * ReadProperty handler for this object. For the given ReadProperty + * data, the application_data is loaded or the error flags are set. + * + * @param rpdata - BACNET_READ_PROPERTY_DATA data, including + * requested data and space for the reply, or error response. + * + * @return number of APDU bytes in the response, or + * BACNET_STATUS_ERROR on error. + */ +int Network_Port_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) +{ + int apdu_len = 0; + BACNET_BIT_STRING bit_string; + BACNET_OCTET_STRING octet_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_NETWORK_PORT, rpdata->object_instance); + break; + case PROP_OBJECT_NAME: + Network_Port_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_NETWORK_PORT); + break; + case PROP_STATUS_FLAGS: + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + if (Network_Port_Reliability(rpdata->object_instance) == + RELIABILITY_NO_FAULT_DETECTED) { + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + } else { + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, true); + } + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + if (Network_Port_Out_Of_Service(rpdata->object_instance)) { + bitstring_set_bit( + &bit_string, STATUS_FLAG_OUT_OF_SERVICE, true); + } else { + bitstring_set_bit( + &bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); + } + apdu_len = encode_application_bitstring(&apdu[0], &bit_string); + break; + case PROP_RELIABILITY: + apdu_len = encode_application_enumerated( + &apdu[0], Network_Port_Reliability(rpdata->object_instance)); + break; + case PROP_OUT_OF_SERVICE: + apdu_len = encode_application_boolean( + &apdu[0], Network_Port_Out_Of_Service(rpdata->object_instance)); + break; + case PROP_NETWORK_TYPE: + apdu_len = encode_application_enumerated( + &apdu[0], Network_Port_Type(rpdata->object_instance)); + break; + case PROP_PROTOCOL_LEVEL: + apdu_len = encode_application_enumerated( + &apdu[0], BACNET_PROTOCOL_LEVEL_PHYSICAL); + break; + case PROP_NETWORK_NUMBER: + apdu_len = encode_application_unsigned( + &apdu[0], Network_Port_Network_Number(rpdata->object_instance)); + break; + case PROP_NETWORK_NUMBER_QUALITY: + apdu_len = encode_application_enumerated( + &apdu[0], Network_Port_Quality(rpdata->object_instance)); + break; + case PROP_MAC_ADDRESS: + Network_Port_MAC_Address(rpdata->object_instance, &octet_string); + apdu_len = encode_application_octet_string(&apdu[0], &octet_string); + break; + case PROP_MAX_APDU_LENGTH_ACCEPTED: + apdu_len = encode_application_unsigned( + &apdu[0], Network_Port_APDU_Length(rpdata->object_instance)); + break; + case PROP_LINK_SPEED: + apdu_len = encode_application_real( + &apdu[0], Network_Port_Link_Speed(rpdata->object_instance)); + break; + case PROP_CHANGES_PENDING: + apdu_len = encode_application_boolean(&apdu[0], + Network_Port_Changes_Pending(rpdata->object_instance)); + break; + case PROP_APDU_LENGTH: + apdu_len = encode_application_unsigned( + &apdu[0], Network_Port_APDU_Length(rpdata->object_instance)); + break; + case PROP_MAX_MASTER: + apdu_len = encode_application_unsigned(&apdu[0], + Network_Port_MSTP_Max_Master(rpdata->object_instance)); + break; + case PROP_MAX_INFO_FRAMES: + apdu_len = encode_application_unsigned(&apdu[0], + Network_Port_MSTP_Max_Info_Frames(rpdata->object_instance)); + break; + default: + rpdata->error_class = ERROR_CLASS_PROPERTY; + rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = BACNET_STATUS_ERROR; + break; + } + + return apdu_len; +} + +/** + * WriteProperty handler for this object. For the given WriteProperty + * data, the application_data is loaded or the error flags are set. + * + * @param wp_data - BACNET_WRITE_PROPERTY_DATA data, including + * requested data and space for the reply, or error response. + * + * @return false if an error is loaded, true if no errors + */ +bool Network_Port_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data) +{ + bool status = false; /* return value */ + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + + if (!Network_Port_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); + 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_LINK_SPEEDS) && + (wp_data->object_property != PROP_IP_DNS_SERVER) && + (wp_data->object_property != PROP_IPV6_DNS_SERVER) && + (wp_data->object_property != PROP_EVENT_MESSAGE_TEXTS) && + (wp_data->object_property != PROP_EVENT_MESSAGE_TEXTS_CONFIG) && + (wp_data->object_property != PROP_TAGS) && + (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; + } + /* FIXME: len < application_data_len: more data? */ + switch (wp_data->object_property) { + case PROP_MAX_MASTER: + if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { + if (value.type.Unsigned_Int <= 255) { + status = Network_Port_MSTP_Max_Master_Set( + wp_data->object_instance, value.type.Unsigned_Int); + if (!status) { + 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_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) { + status = Network_Port_MSTP_Max_Info_Frames_Set( + wp_data->object_instance, value.type.Unsigned_Int); + if (!status) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + 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_LINK_SPEED: + if (value.tag == BACNET_APPLICATION_TAG_REAL) { + if (!Network_Port_Link_Speed_Set( + wp_data->object_instance, value.type.Real)) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + status = true; + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_MAC_ADDRESS: + if (value.tag == BACNET_APPLICATION_TAG_OCTET_STRING) { + if (!Network_Port_MAC_Address_Set(wp_data->object_instance, + value.type.Octet_String.value, + value.type.Octet_String.length)) { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + status = true; + } else { + wp_data->error_class = ERROR_CLASS_PROPERTY; + wp_data->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_RELIABILITY: + case PROP_OUT_OF_SERVICE: + case PROP_NETWORK_TYPE: + case PROP_PROTOCOL_LEVEL: + case PROP_NETWORK_NUMBER: + case PROP_NETWORK_NUMBER_QUALITY: + case PROP_MAX_APDU_LENGTH_ACCEPTED: + case PROP_CHANGES_PENDING: + case PROP_APDU_LENGTH: + 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; +} + +/** + * Initializes the Network Port object data + */ +void Network_Port_Init(void) +{ + Object_List[0].Changes_Pending = false; + Object_List[0].MAC_Address[0] = dlmstp_mac_address(); + Object_List[0].Max_Master = dlmstp_max_master(); + Object_List[0].Max_Info_Frames = dlmstp_max_info_frames(); + Object_List[0].Link_Speed = rs485_baud_rate(); +} diff --git a/ports/at91sam7s/rs485.c b/ports/at91sam7s/rs485.c index b7d35063..9f37b621 100644 --- a/ports/at91sam7s/rs485.c +++ b/ports/at91sam7s/rs485.c @@ -118,7 +118,7 @@ void RS485_Cleanup(void) * ALGORITHM: none * NOTES: none *****************************************************************************/ -uint32_t RS485_Get_Baud_Rate(void) +uint32_t rs485_baud_rate(void) { return RS485_Baud; } @@ -129,7 +129,7 @@ uint32_t RS485_Get_Baud_Rate(void) * ALGORITHM: none * NOTES: none *****************************************************************************/ -bool RS485_Set_Baud_Rate(uint32_t baud) +bool rs485_baud_rate_set(uint32_t baud) { bool valid = true; @@ -266,7 +266,7 @@ int main(void) unsigned i = 0; uint8_t DataRegister; - RS485_Set_Baud_Rate(38400); + rs485_baud_rate_set(38400); RS485_Initialize(); /* receive task */ for (;;) { diff --git a/ports/at91sam7s/rs485.h b/ports/at91sam7s/rs485.h index ae622daa..a69b4e28 100644 --- a/ports/at91sam7s/rs485.h +++ b/ports/at91sam7s/rs485.h @@ -49,9 +49,9 @@ extern "C" { void RS485_Turnaround_Delay( void); - uint32_t RS485_Get_Baud_Rate( + uint32_t rs485_baud_rate( void); - bool RS485_Set_Baud_Rate( + bool rs485_baud_rate_set( uint32_t baud); #ifdef __cplusplus diff --git a/ports/bdk-atxx4-mstp/Makefile b/ports/bdk-atxx4-mstp/Makefile index debf1628..33e1f505 100644 --- a/ports/bdk-atxx4-mstp/Makefile +++ b/ports/bdk-atxx4-mstp/Makefile @@ -91,6 +91,7 @@ HALSRC = main.c \ bacnet.c \ bname.c \ device.c \ + netport.c \ ai.c \ av.c \ bi.c \ @@ -218,6 +219,7 @@ BFLAGS += -DBACAPP_OBJECT_ID BFLAGS += -DBACAPP_UNSIGNED BFLAGS += -DBACAPP_ENUMERATED BFLAGS += -DBACAPP_CHARACTER_STRING +BFLAGS += -DBACAPP_OCTET_STRING BFLAGS += -DWRITE_PROPERTY ## Compile options for C files diff --git a/ports/bdk-atxx4-mstp/bacnet.ewp b/ports/bdk-atxx4-mstp/bacnet.ewp index 718ac496..19c85171 100644 --- a/ports/bdk-atxx4-mstp/bacnet.ewp +++ b/ports/bdk-atxx4-mstp/bacnet.ewp @@ -266,6 +266,7 @@ BACAPP_UNSIGNED BACAPP_ENUMERATED BACAPP_CHARACTER_STRING + BACAPP_OCTET_STRING WRITE_PROPERTY