From e70dd3c7ba0dc80ec29b6afc6a1b77993c18a239 Mon Sep 17 00:00:00 2001 From: skarg Date: Thu, 18 Jun 2009 03:58:54 +0000 Subject: [PATCH] Added more objects to BDK port, and connected AI to ADC7, and BI0..BI4 to PINB0..PINB4. Fixed up some other objects and object API (header files). --- bacnet-stack/demo/object/ai.c | 29 +- bacnet-stack/include/ai.h | 7 + bacnet-stack/include/av.h | 4 +- bacnet-stack/include/bi.h | 8 + bacnet-stack/ports/at91sam7s/ai.c | 13 +- bacnet-stack/ports/bdk-atxx4-mstp/Makefile | 2 + bacnet-stack/ports/bdk-atxx4-mstp/adc.c | 94 +++++ bacnet-stack/ports/bdk-atxx4-mstp/adc.h | 40 ++ bacnet-stack/ports/bdk-atxx4-mstp/ai.c | 22 +- bacnet-stack/ports/bdk-atxx4-mstp/av.c | 452 +++++++++++++++++++++ bacnet-stack/ports/bdk-atxx4-mstp/bi.c | 33 +- bacnet-stack/ports/bdk-atxx4-mstp/device.c | 14 + bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c | 9 + bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c | 14 + bacnet-stack/ports/bdk-atxx4-mstp/input.c | 71 +++- bacnet-stack/ports/bdk-atxx4-mstp/input.h | 2 + bacnet-stack/ports/bdk-atxx4-mstp/main.c | 18 + bacnet-stack/ports/pic18f6720/ai.c | 11 +- 18 files changed, 814 insertions(+), 29 deletions(-) create mode 100644 bacnet-stack/ports/bdk-atxx4-mstp/adc.c create mode 100644 bacnet-stack/ports/bdk-atxx4-mstp/adc.h create mode 100644 bacnet-stack/ports/bdk-atxx4-mstp/av.c diff --git a/bacnet-stack/demo/object/ai.c b/bacnet-stack/demo/object/ai.c index 95f758dd..9211ae29 100644 --- a/bacnet-stack/demo/object/ai.c +++ b/bacnet-stack/demo/object/ai.c @@ -33,7 +33,11 @@ #include "bacenum.h" #include "config.h" /* the custom stuff */ +#ifndef MAX_ANALOG_INPUTS #define MAX_ANALOG_INPUTS 7 +#endif + +static float Present_Value[MAX_ANALOG_INPUTS]; /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Analog_Input_Properties_Required[] = { @@ -104,6 +108,27 @@ uint32_t Analog_Input_Index_To_Instance( return index; } +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; + } +} + char *Analog_Input_Name( uint32_t object_instance) { @@ -130,7 +155,6 @@ int Analog_Input_Encode_Property_APDU( int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; - float value = 3.14159F; (void) array_index; switch (property) { @@ -151,7 +175,8 @@ int Analog_Input_Encode_Property_APDU( encode_application_enumerated(&apdu[0], OBJECT_ANALOG_INPUT); break; case PROP_PRESENT_VALUE: - apdu_len = encode_application_real(&apdu[0], value); + apdu_len = encode_application_real(&apdu[0], + Analog_Input_Present_Value(object_instance)); break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); diff --git a/bacnet-stack/include/ai.h b/bacnet-stack/include/ai.h index 11c5a01f..a486146d 100644 --- a/bacnet-stack/include/ai.h +++ b/bacnet-stack/include/ai.h @@ -52,6 +52,13 @@ extern "C" { int32_t array_index, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code); + 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" diff --git a/bacnet-stack/include/av.h b/bacnet-stack/include/av.h index a83e523a..1b2b9fa0 100644 --- a/bacnet-stack/include/av.h +++ b/bacnet-stack/include/av.h @@ -70,7 +70,9 @@ extern "C" { uint8_t priority); float Analog_Value_Present_Value( uint32_t object_instance); - + + void Analog_Value_Init( + void); #ifdef TEST #include "ctest.h" diff --git a/bacnet-stack/include/bi.h b/bacnet-stack/include/bi.h index 6b90856f..5154fdf8 100644 --- a/bacnet-stack/include/bi.h +++ b/bacnet-stack/include/bi.h @@ -67,6 +67,14 @@ extern "C" { BACNET_WRITE_PROPERTY_DATA * wp_data, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code); + void Binary_Input_Init( + void); + BACNET_BINARY_PV Binary_Input_Present_Value( + uint32_t object_instance); + + bool Binary_Input_Present_Value_Set( + uint32_t object_instance, + bool value); #ifdef TEST #include "ctest.h" diff --git a/bacnet-stack/ports/at91sam7s/ai.c b/bacnet-stack/ports/at91sam7s/ai.c index 4d485fe1..91971a6c 100644 --- a/bacnet-stack/ports/at91sam7s/ai.c +++ b/bacnet-stack/ports/at91sam7s/ai.c @@ -39,7 +39,7 @@ #error Modify the Analog_Input_Name to handle multiple digits #endif -static uint8_t Present_Value[MAX_ANALOG_INPUTS]; +static 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 */ @@ -80,7 +80,7 @@ char *Analog_Input_Name( return NULL; } -static float Analog_Input_Present_Value( +float Analog_Input_Present_Value( uint32_t object_instance) { float value = 0.0; @@ -91,6 +91,15 @@ static float Analog_Input_Present_Value( 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_Encode_Property_APDU( diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/Makefile b/bacnet-stack/ports/bdk-atxx4-mstp/Makefile index 9eea250c..687ef6cc 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/Makefile +++ b/bacnet-stack/ports/bdk-atxx4-mstp/Makefile @@ -42,6 +42,7 @@ BACNET_DEMO = ../../demo CSRC = main.c \ init.c \ stack.c \ + adc.c \ input.c \ serial.c \ rs485.c \ @@ -56,6 +57,7 @@ CSRC = main.c \ h_rd.c \ device.c \ ai.c \ + av.c \ bi.c \ bo.c diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/adc.c b/bacnet-stack/ports/bdk-atxx4-mstp/adc.c new file mode 100644 index 00000000..adffa440 --- /dev/null +++ b/bacnet-stack/ports/bdk-atxx4-mstp/adc.c @@ -0,0 +1,94 @@ +/************************************************************************** +* +* Copyright (C) 2009 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 "hardware.h" + +/* prescale select bits */ +#if (F_CPU >> 1) < 1000000 + #define ADPS_8BIT (1) + #define ADPS_10BIT (3) +#elif (F_CPU >> 2) < 1000000 + #define ADPS_8BIT (2) + #define ADPS_10BIT (4) +#elif (F_CPU >> 3) < 1000000 + #define ADPS_8BIT (3) + #define ADPS_10BIT (5) +#elif (F_CPU >> 4) < 1000000 + #define ADPS_8BIT (4) + #define ADPS_10BIT (6) +#elif (F_CPU >> 5) < 1000000 + #define ADPS_8BIT (5) + #define ADPS_10BIT (7) +#else + #error "ADC: F_CPU too large for accuracy." +#endif + +/* we could have array of ADC results */ +static volatile uint8_t Sample_Result; + +ISR(ADC_vect) +{ + /* since we configured as ADLAR=1, get value from ADCH */ + Sample_Result = ADCH; +} + +uint8_t adc_result( + uint8_t channel) /* 0..7 = ADC0..ADC7, respectively */ +{ + return Sample_Result; +} + +void adc_init(void) +{ + /* set prescaler */ + ADCSRA |= ADPS_8BIT; + /* Initial channel selection */ + /* ADLAR = Left Adjust Result + REFSx = hardware setup: cap on AREF + */ + ADMUX = 7 /* channel */ | (1 << ADLAR) | (0 << REFS1) | (1 << REFS0); + /* ADEN = Enable + ADSC = Start conversion + ADIF = Interrupt Flag + ADIE = Interrupt Enable + ADATE = Auto Trigger Enable + */ + ADCSRA |= (1 << ADEN) | (1 << ADIE) | (1 << ADIF) | (1 << ADATE); + /* trigger selection bits + 0 0 0 Free Running mode + 0 0 1 Analog Comparator + 0 1 0 External Interrupt Request 0 + 0 1 1 Timer/Counter0 Compare Match + 1 0 0 Timer/Counter0 Overflow + 1 0 1 Timer/Counter1 Compare Match B + 1 1 0 Timer/Counter1 Overflow + 1 1 1 Timer/Counter1 Capture Event + */ + ADCSRB |= (0 << ADTS2) | (0 << ADTS1) | (0 << ADTS0); + /* start the conversions */ + ADCSRA |= (1 << ADSC); + /* Clear the Power Reduction bit */ + BIT_CLEAR(PRR, PRADC); +} diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/adc.h b/bacnet-stack/ports/bdk-atxx4-mstp/adc.h new file mode 100644 index 00000000..75b1827f --- /dev/null +++ b/bacnet-stack/ports/bdk-atxx4-mstp/adc.h @@ -0,0 +1,40 @@ +/************************************************************************** +* +* Copyright (C) 2009 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 ADC_H +#define ADC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +uint8_t adc_result(uint8_t channel); +void adc_init(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/ai.c b/bacnet-stack/ports/bdk-atxx4-mstp/ai.c index 4edda3a2..bfda6977 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/ai.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/ai.c @@ -39,6 +39,8 @@ #error Modify the Analog_Input_Name to handle multiple digits #endif +static uint8_t Present_Value[MAX_ANALOG_INPUTS]; + /* These three arrays are used by the ReadPropertyMultiple handler */ static const int Analog_Input_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, @@ -76,7 +78,11 @@ void Analog_Input_Property_Lists( return; } -static uint8_t Present_Value[MAX_ANALOG_INPUTS]; +void Analog_Input_Init( + void) +{ + return; +} /* we simply have 0-n object instances. Yours might be */ /* more complex, and then you need validate that the */ @@ -117,17 +123,27 @@ char *Analog_Input_Name( return NULL; } -static float Analog_Input_Present_Value( +float Analog_Input_Present_Value( uint32_t object_instance) { float value = 0.0; - if (object_instance < MAX_ANALOG_INPUTS) + 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_Encode_Property_APDU( diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/av.c b/bacnet-stack/ports/bdk-atxx4-mstp/av.c new file mode 100644 index 00000000..634bf8f9 --- /dev/null +++ b/bacnet-stack/ports/bdk-atxx4-mstp/av.c @@ -0,0 +1,452 @@ +/************************************************************************** +* +* Copyright (C) 2006 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. +* +*********************************************************************/ + +/* Analog Value Objects - customize for your use */ + +#include +#include +#include +#include /* for NAN */ +#include "bacdef.h" +#include "bacdcode.h" +#include "bacenum.h" +#include "bacapp.h" +#include "config.h" /* the custom stuff */ +#include "wp.h" + +#ifndef MAX_ANALOG_VALUES +#define MAX_ANALOG_VALUES 4 +#endif + +static float Present_Value[MAX_ANALOG_VALUES]; + +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Analog_Value_Properties_Required[] = { + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_UNITS, + -1 +}; + +static const int Analog_Value_Properties_Optional[] = { + PROP_DESCRIPTION, + PROP_PRIORITY_ARRAY, + PROP_RELINQUISH_DEFAULT, + -1 +}; + +static const int Analog_Value_Properties_Proprietary[] = { + -1 +}; + +void Analog_Value_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (pRequired) + *pRequired = Analog_Value_Properties_Required; + if (pOptional) + *pOptional = Analog_Value_Properties_Optional; + if (pProprietary) + *pProprietary = Analog_Value_Properties_Proprietary; + + return; +} + +void Analog_Value_Init( + void) +{ + return; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need validate that the */ +/* given instance exists */ +bool Analog_Value_Valid_Instance( + uint32_t object_instance) +{ + if (object_instance < MAX_ANALOG_VALUES) + return true; + + return false; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then count how many you have */ +unsigned Analog_Value_Count( + void) +{ + return MAX_ANALOG_VALUES; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the instance */ +/* that correlates to the correct index */ +uint32_t Analog_Value_Index_To_Instance( + unsigned index) +{ + return index; +} + +/* we simply have 0-n object instances. Yours might be */ +/* more complex, and then you need to return the index */ +/* that correlates to the correct instance number */ +unsigned Analog_Value_Instance_To_Index( + uint32_t object_instance) +{ + unsigned index = MAX_ANALOG_VALUES; + + if (object_instance < MAX_ANALOG_VALUES) + index = object_instance; + + return index; +} + +float Analog_Value_Present_Value( + uint32_t object_instance) +{ + float value = NAN; + unsigned index = 0; + + index = Analog_Value_Instance_To_Index(object_instance); + if (index < MAX_ANALOG_VALUES) { + value = Present_Value[index]; + } + + return value; +} + +bool Analog_Value_Present_Value_Set( + uint32_t object_instance, + float value, + uint8_t priority) +{ + unsigned index = 0; + bool status = false; + + priority = priority; + index = Analog_Value_Instance_To_Index(object_instance); + if (index < MAX_ANALOG_VALUES) { + if (priority && (priority <= BACNET_MAX_PRIORITY) && + (priority != 6 /* reserved */ ) && + (value >= 0.0) && (value <= 100.0)) { + Present_Value[index] = value; + /* Note: you could set the physical output here if we + are the highest priority. + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the + main loop (i.e. check out of service before changing output) */ + status = true; + } + } + return status; +} + +/* note: the object name must be unique within this device */ +char *Analog_Value_Name( + uint32_t object_instance) +{ + static char text_string[32] = ""; /* okay for single thread */ + unsigned index = 0; + + index = Analog_Value_Instance_To_Index(object_instance); + if (index < MAX_ANALOG_VALUES) { + sprintf(text_string, "AV-%lu", object_instance); + return text_string; + } + + return NULL; +} + +/* return apdu len, or -1 on error */ +int Analog_Value_Encode_Property_APDU( + uint8_t * apdu, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_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; + float real_value = 1.414F; +#if 0 + unsigned object_index = 0; + unsigned i = 0; + bool state = false; +#endif + + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = + encode_application_object_id(&apdu[0], OBJECT_ANALOG_VALUE, + object_instance); + break; + case PROP_OBJECT_NAME: + case PROP_DESCRIPTION: + 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: + real_value = Analog_Value_Present_Value(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(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 (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 (array_index == BACNET_ARRAY_ALL) { + object_index = Analog_Value_Instance_To_Index(object_instance); + for (i = 0; i < BACNET_MAX_PRIORITY; i++) { + /* FIXME: check if we have room before adding it to APDU */ + if (Present_Value[object_index][i] == ANALOG_LEVEL_NULL) + len = encode_application_null(&apdu[apdu_len]); + else { + real_value = Present_Value[object_index][i]; + len = + encode_application_real(&apdu[apdu_len], + real_value); + } + /* add it if we have room */ + if ((apdu_len + len) < MAX_APDU) + apdu_len += len; + else { + *error_class = ERROR_CLASS_SERVICES; + *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; + apdu_len = -1; + break; + } + } + } else { + object_index = Analog_Value_Instance_To_Index(object_instance); + if (array_index <= BACNET_MAX_PRIORITY) { + if (Present_Value[object_index][array_index - 1] == + ANALOG_LEVEL_NULL) + apdu_len = encode_application_null(&apdu[0]); + else { + real_value = + Present_Value[object_index][array_index - 1]; + apdu_len = + encode_application_real(&apdu[0], real_value); + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = -1; + } + } + + break; + case PROP_RELINQUISH_DEFAULT: + real_value = ANALOG_RELINQUISH_DEFAULT; + apdu_len = encode_application_real(&apdu[0], real_value); + break; +#endif + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + 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 */ +#if 0 + unsigned int object_index = 0; + unsigned int priority = 0; +#endif + 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? */ + /* FIXME: len == 0: unable to decode? */ + switch (wp_data->object_property) { + case PROP_PRESENT_VALUE: + if (value.tag == BACNET_APPLICATION_TAG_REAL) { + if (Analog_Value_Present_Value_Set( + wp_data->object_instance, + value.type.Real, + wp_data->priority)) { + status = true; + } else if (wp_data->priority == 6) { + /* Command priority 6 is reserved for use by Minimum On/Off + algorithm and may not be used for other purposes in any + object. */ + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } +#if 0 + } else if (value.tag == BACNET_APPLICATION_TAG_NULL) { + if (Analog_Value_Present_Value_Set( + wp_data->object_instance, + NAN, + wp_data->priority)) { + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } +#endif + } 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 = + Analog_Value_Instance_To_Index(wp_data->object_instance); + Analog_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 +#include +#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 */ diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/bi.c b/bacnet-stack/ports/bdk-atxx4-mstp/bi.c index 876996bb..71dd69e2 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/bi.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/bi.c @@ -80,17 +80,13 @@ void Binary_Input_Property_Lists( return; } -static void Binary_Input_Initialize( +void Binary_Input_Init( void) { - static bool initialized = false; unsigned i; - if (!initialized) { - initialized = true; - for (i = 0; i < MAX_BINARY_INPUTS; i++) { - Present_Value[i] = BINARY_INACTIVE; - } + for (i = 0; i < MAX_BINARY_INPUTS; i++) { + Present_Value[i] = BINARY_INACTIVE; } } @@ -132,13 +128,12 @@ unsigned Binary_Input_Instance_To_Index( return index; } -static BACNET_BINARY_PV Binary_Input_Present_Value( +BACNET_BINARY_PV Binary_Input_Present_Value( uint32_t object_instance) { BACNET_BINARY_PV value = BINARY_INACTIVE; unsigned index = 0; - Binary_Input_Initialize(); index = Binary_Input_Instance_To_Index(object_instance); if (index < MAX_BINARY_INPUTS) { value = Present_Value[index]; @@ -147,6 +142,25 @@ static BACNET_BINARY_PV Binary_Input_Present_Value( return value; } +bool Binary_Input_Present_Value_Set( + uint32_t object_instance, + bool value) +{ + unsigned index = 0; + + index = Binary_Input_Instance_To_Index(object_instance); + if (index < MAX_BINARY_INPUTS) { + if (value) { + Present_Value[index] = BINARY_ACTIVE; + } else { + Present_Value[index] = BINARY_INACTIVE; + } + return true; + } + + return false; +} + char *Binary_Input_Name( uint32_t object_instance) { @@ -178,7 +192,6 @@ int Binary_Input_Encode_Property_APDU( (void) array_index; - Binary_Input_Initialize(); switch (property) { case PROP_OBJECT_IDENTIFIER: apdu_len = diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/device.c b/bacnet-stack/ports/bdk-atxx4-mstp/device.c index cd9a3586..73b2b653 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/device.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/device.c @@ -39,6 +39,7 @@ /* objects */ #include "device.h" #include "ai.h" +#include "av.h" #include "bi.h" #include "bo.h" @@ -229,6 +230,7 @@ unsigned Device_Object_List_Count( count += Binary_Input_Count(); count += Binary_Output_Count(); count += Analog_Input_Count(); + count += Analog_Value_Count(); return count; } @@ -290,6 +292,17 @@ bool Device_Object_List_Identifier( status = true; } } + /* 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; + } + } return status; } @@ -398,6 +411,7 @@ int Device_Encode_Property_APDU( /* FIXME: indicate the objects that YOU support */ bitstring_set_bit(&bit_string, OBJECT_DEVICE, true); bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true); + bitstring_set_bit(&bit_string, OBJECT_ANALOG_VALUE, true); bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true); bitstring_set_bit(&bit_string, OBJECT_BINARY_OUTPUT, true); apdu_len = encode_application_bitstring(&apdu[0], &bit_string); diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c b/bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c index 4bf50ef1..abec7608 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/h_rp.c @@ -39,6 +39,7 @@ /* demo objects */ #include "device.h" #include "ai.h" +#include "av.h" #include "bi.h" #include "bo.h" @@ -77,6 +78,14 @@ int Encode_Property_APDU( error_code); } break; + case OBJECT_ANALOG_VALUE: + if (Analog_Value_Valid_Instance(object_instance)) { + apdu_len = + Analog_Value_Encode_Property_APDU(&apdu[0], + object_instance, property, array_index, error_class, + error_code); + } + break; case OBJECT_BINARY_INPUT: if (Binary_Input_Valid_Instance(object_instance)) { apdu_len = diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c b/bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c index 98a67308..be338d44 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/h_wp.c @@ -39,6 +39,7 @@ /* demo objects */ #include "device.h" #include "ai.h" +#include "av.h" #include "bi.h" #include "bo.h" @@ -117,6 +118,19 @@ void handler_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; default: len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/input.c b/bacnet-stack/ports/bdk-atxx4-mstp/input.c index 1a85cb71..86d14409 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/input.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/input.c @@ -22,22 +22,36 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * *********************************************************************/ +#include +#include #include "hardware.h" static uint8_t Address_Switch; +static uint8_t Buttons; +/* debounce the inputs */ void input_task( void) { uint8_t value; - static uint8_t old_value = 0; + static uint8_t old_address = 0; + static uint8_t old_buttons = 0; value = BITMASK_CHECK(PINA, 0x7F); - if (value != old_value) { - old_value = value; + if (value != old_address) { + old_address = value; } else { - if (old_value != Address_Switch) { - Address_Switch = old_value; + if (old_address != Address_Switch) { + Address_Switch = old_address; + } + } + /* pins used are PB4, PB3, PB2, PB1, PB0 */ + value = BITMASK_CHECK(PINB, 0x1F); + if (value != old_buttons) { + old_buttons = value; + } else { + if (old_buttons != Buttons) { + Buttons = old_buttons; } } } @@ -48,12 +62,49 @@ uint8_t input_address( return Address_Switch; } +bool input_button_value( + uint8_t index) +{ + bool value = false; + + switch (index) { + case 0: + value = BIT_CHECK(Buttons, 0); + break; + case 1: + value = BIT_CHECK(Buttons, 1); + break; + case 2: + value = BIT_CHECK(Buttons, 2); + break; + case 3: + value = BIT_CHECK(Buttons, 3); + break; + case 4: + value = BIT_CHECK(Buttons, 4); + break; + default: + break; + } + + return value; +} + + void input_init( void) { - /* configure the port pins */ - BITMASK_CLEAR(DDRA, - _BV(DDA0) | _BV(DDA1) | _BV(DDA2) | _BV(DDA3) | _BV(DDA4) | _BV(DDA5) | - _BV(DDA6) - ); + /* configure the port pins for the switch */ + BIT_CLEAR(DDRA, DDA0); + BIT_CLEAR(DDRA, DDA1); + BIT_CLEAR(DDRA, DDA2); + BIT_CLEAR(DDRA, DDA3); + BIT_CLEAR(DDRA, DDA4); + BIT_CLEAR(DDRA, DDA5); + BIT_CLEAR(DDRA, DDA6); + /* configure the port pins for binary inputs */ + BIT_CLEAR(DDRB, DDB1); + BIT_CLEAR(DDRB, DDB2); + BIT_CLEAR(DDRB, DDB3); + BIT_CLEAR(DDRB, DDB4); } diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/input.h b/bacnet-stack/ports/bdk-atxx4-mstp/input.h index 89008ca1..bb8ba7d5 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/input.h +++ b/bacnet-stack/ports/bdk-atxx4-mstp/input.h @@ -36,6 +36,8 @@ extern "C" { void); uint8_t input_address( void); + bool input_button_value( + uint8_t index); #ifdef __cplusplus } diff --git a/bacnet-stack/ports/bdk-atxx4-mstp/main.c b/bacnet-stack/ports/bdk-atxx4-mstp/main.c index 8aff7a82..94a78c30 100644 --- a/bacnet-stack/ports/bdk-atxx4-mstp/main.c +++ b/bacnet-stack/ports/bdk-atxx4-mstp/main.c @@ -31,6 +31,7 @@ #include "timer.h" #include "input.h" #include "led.h" +#include "adc.h" #include "nvdata.h" #include "timer.h" #include "dcc.h" @@ -44,6 +45,7 @@ #include "iam.h" #include "device.h" #include "ai.h" +#include "av.h" #include "bi.h" #include "bo.h" @@ -128,6 +130,9 @@ static void bacnet_init( /* initialize objects */ Device_Init(); Binary_Output_Init(); + Analog_Input_Init(); + Binary_Input_Init(); + Analog_Value_Init(); /* we need to handle who-is to support dynamic device binding */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); @@ -155,6 +160,9 @@ static void bacnet_task( uint8_t mstp_mac_address = 0; uint16_t pdu_len = 0; BACNET_ADDRESS src; /* source address */ + uint8_t value = 0; + bool button_value = false; + uint8_t i = 0; mstp_mac_address = input_address(); if (MSTP_MAC_Address != mstp_mac_address) { @@ -162,9 +170,18 @@ static void bacnet_task( dlmstp_set_mac_address(MSTP_MAC_Address); Send_I_Am(&Handler_Transmit_Buffer[0]); } + /* handle the inputs */ + value = adc_result(7); + Analog_Input_Present_Value_Set(0, value); + for (i = 0; i < 5; i++) { + button_value = input_button_value(i); + Binary_Input_Present_Value_Set(i, button_value); + } + /* handle the communication timer */ if (timer_elapsed_seconds(TIMER_DCC, 1)) { dcc_timer_seconds(1); } + /* handle the messaging */ pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0); if (pdu_len) { npdu_handler(&src, &PDUBuffer[0], pdu_len); @@ -198,6 +215,7 @@ int main( void) { init(); + adc_init(); led_init(); input_init(); timer_init(); diff --git a/bacnet-stack/ports/pic18f6720/ai.c b/bacnet-stack/ports/pic18f6720/ai.c index 44598774..ecd743f8 100644 --- a/bacnet-stack/ports/pic18f6720/ai.c +++ b/bacnet-stack/ports/pic18f6720/ai.c @@ -77,7 +77,7 @@ char *Analog_Input_Name( return NULL; } -static float Analog_Input_Present_Value( +float Analog_Input_Present_Value( uint32_t object_instance) { float value = 0.0; @@ -88,6 +88,15 @@ static float Analog_Input_Present_Value( 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_Encode_Property_APDU(