Improved BACnet Development Kit object handling and storing to SEEPROM and EEPROM. Added device property to check C-Stack size and amount unused.

This commit is contained in:
skarg
2009-05-12 20:25:31 +00:00
parent fa3607d948
commit 9235ebeee2
11 changed files with 256 additions and 45 deletions
+1 -1
View File
@@ -396,7 +396,7 @@ typedef enum {
BINARY_INACTIVE = 0,
BINARY_ACTIVE = 1,
MAX_BINARY_PV = 1, /* for validating incoming values */
BINARY_NULL = 2 /* our homemade way of storing this info */
BINARY_NULL = 255 /* our homemade way of storing this info */
} BACNET_BINARY_PV;
typedef enum {
@@ -40,6 +40,7 @@ BACNET_DEMO = ../../demo
# local files for this project
CSRC = main.c \
init.c \
stack.c \
input.c \
serial.c \
rs485.c \
+1 -1
View File
@@ -33,7 +33,7 @@
#include "bacenum.h"
#include "config.h"
/* Analog Input = Photocell */
/* Analog Input */
#define MAX_ANALOG_INPUTS 2
#if (MAX_ANALOG_INPUTS > 9)
#error Modify the Analog_Input_Name to handle multiple digits
+106 -37
View File
@@ -34,6 +34,7 @@
#include "config.h" /* the custom stuff */
#include "wp.h"
#include "led.h"
#include "nvdata.h"
#define MAX_BINARY_OUTPUTS 2
#if (MAX_BINARY_OUTPUTS > 9)
@@ -44,13 +45,13 @@
/* the Relinquish Default value */
#define RELINQUISH_DEFAULT BINARY_INACTIVE
/* Here is our Priority Array.*/
static BACNET_BINARY_PV
static uint8_t
Binary_Output_Level[MAX_BINARY_OUTPUTS][BACNET_MAX_PRIORITY];
/* Writable out-of-service allows others to play with our Present Value */
/* without changing the physical output */
static bool Binary_Output_Out_Of_Service[MAX_BINARY_OUTPUTS];
static uint8_t Out_Of_Service[MAX_BINARY_OUTPUTS];
/* polarity - normal or inverse */
static BACNET_POLARITY Polarity[MAX_BINARY_OUTPUTS];
static uint8_t Polarity[MAX_BINARY_OUTPUTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Binary_Output_Properties_Required[] = {
@@ -93,24 +94,51 @@ void Binary_Output_Property_Lists(
return;
}
void Binary_Output_Init(
void)
void Binary_Output_Level_Set(
unsigned int object_index,
unsigned int priority,
BACNET_BINARY_PV level)
{
unsigned i, j;
static bool initialized = false;
if (!initialized) {
initialized = true;
/* initialize all the analog output priority arrays to NULL */
for (i = 0; i < MAX_BINARY_OUTPUTS; i++) {
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
Binary_Output_Level[i][j] = BINARY_NULL;
}
if (object_index < MAX_BINARY_OUTPUTS) {
if (priority < BACNET_MAX_PRIORITY) {
Binary_Output_Level[object_index][priority] = (uint8_t)level;
seeprom_bytes_write(
NV_SEEPROM_BINARY_OUTPUT(object_index,
NV_SEEPROM_BO_PRIORITY_ARRAY_1+priority),
&Binary_Output_Level[object_index][priority],
1);
}
}
}
return;
void Binary_Output_Polarity_Set(
unsigned int object_index,
BACNET_POLARITY polarity)
{
if (object_index < MAX_BINARY_OUTPUTS) {
if (polarity < MAX_POLARITY) {
Polarity[object_index] = POLARITY_NORMAL;
seeprom_bytes_write(
NV_SEEPROM_BINARY_OUTPUT(object_index,
NV_SEEPROM_BO_POLARITY),
&Polarity[object_index],
1);
}
}
}
void Binary_Output_Out_Of_Service_Set(
unsigned int object_index,
bool flag)
{
if (object_index < MAX_BINARY_OUTPUTS) {
Out_Of_Service[object_index] = flag;
seeprom_bytes_write(
NV_SEEPROM_BINARY_OUTPUT(object_index,
NV_SEEPROM_BO_OUT_OF_SERVICE),
&Out_Of_Service[object_index],
1);
}
}
/* we simply have 0-n object instances. */
@@ -153,14 +181,15 @@ static BACNET_BINARY_PV Binary_Output_Present_Value(
uint32_t object_instance)
{
BACNET_BINARY_PV value = RELINQUISH_DEFAULT;
BACNET_BINARY_PV current_value = RELINQUISH_DEFAULT;
unsigned index = 0;
unsigned i = 0;
Binary_Output_Init();
index = Binary_Output_Instance_To_Index(object_instance);
if (index < MAX_BINARY_OUTPUTS) {
for (i = 0; i < BACNET_MAX_PRIORITY; i++) {
if (Binary_Output_Level[index][i] != BINARY_NULL) {
current_value = Binary_Output_Level[index][i];
if (current_value != BINARY_NULL) {
value = Binary_Output_Level[index][i];
break;
}
@@ -177,7 +206,7 @@ static void Binary_Output_Sync(
unsigned index = Binary_Output_Instance_To_Index(object_instance);
if (index < MAX_BINARY_OUTPUTS) {
if (Binary_Output_Out_Of_Service[index]) {
if (Out_Of_Service[index]) {
return;
}
if (Polarity[index] == POLARITY_REVERSE) {
@@ -240,7 +269,6 @@ int Binary_Output_Encode_Property_APDU(
unsigned i = 0;
bool state = false;
Binary_Output_Init();
switch (property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len =
@@ -280,7 +308,7 @@ int Binary_Output_Encode_Property_APDU(
break;
case PROP_OUT_OF_SERVICE:
object_index = Binary_Output_Instance_To_Index(object_instance);
state = Binary_Output_Out_Of_Service[object_index];
state = Out_Of_Service[object_index];
apdu_len = encode_application_boolean(&apdu[0], state);
break;
case PROP_POLARITY:
@@ -299,10 +327,10 @@ int Binary_Output_Encode_Property_APDU(
Binary_Output_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 (Binary_Output_Level[object_index][i] == BINARY_NULL)
present_value = Binary_Output_Level[object_index][i];
if (present_value == BINARY_NULL) {
len = encode_application_null(&apdu[apdu_len]);
else {
present_value = Binary_Output_Level[object_index][i];
} else {
len =
encode_application_enumerated(&apdu[apdu_len],
present_value);
@@ -321,12 +349,11 @@ int Binary_Output_Encode_Property_APDU(
object_index =
Binary_Output_Instance_To_Index(object_instance);
if (array_index <= BACNET_MAX_PRIORITY) {
if (Binary_Output_Level[object_index][array_index] ==
BINARY_NULL)
present_value =
Binary_Output_Level[object_index][array_index];
if (present_value == BINARY_NULL) {
len = encode_application_null(&apdu[apdu_len]);
else {
present_value =
Binary_Output_Level[object_index][array_index];
} else {
len =
encode_application_enumerated(&apdu[apdu_len],
present_value);
@@ -400,7 +427,7 @@ bool Binary_Output_Write_Property(
(value.type.Enumerated <= MAX_BINARY_PV)) {
level = (BACNET_BINARY_PV) value.type.Enumerated;
priority--;
Binary_Output_Level[object_index][priority] = level;
Binary_Output_Level_Set(object_index, priority,level);
Binary_Output_Sync(wp_data->object_instance);
status = true;
} else if (priority == 6) {
@@ -418,9 +445,15 @@ bool Binary_Output_Write_Property(
priority = wp_data->priority;
if (priority && (priority <= BACNET_MAX_PRIORITY)) {
priority--;
Binary_Output_Level[object_index][priority] = level;
Binary_Output_Level_Set(object_index, priority,level);
Binary_Output_Sync(wp_data->object_instance);
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. */
*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;
@@ -432,8 +465,8 @@ bool Binary_Output_Write_Property(
break;
case PROP_OUT_OF_SERVICE:
if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) {
Binary_Output_Out_Of_Service[object_index] =
value.type.Boolean;
Binary_Output_Out_Of_Service_Set(object_index,
value.type.Boolean);
Binary_Output_Sync(wp_data->object_instance);
status = true;
} else {
@@ -443,9 +476,11 @@ bool Binary_Output_Write_Property(
break;
case PROP_POLARITY:
if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) {
if (value.type.Enumerated <= MAX_POLARITY) {
Polarity[object_index] =
(BACNET_POLARITY)value.type.Enumerated;
if (value.type.Enumerated < MAX_POLARITY) {
Binary_Output_Polarity_Set(object_index,
value.type.Enumerated);
Binary_Output_Sync(wp_data->object_instance);
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
@@ -463,3 +498,37 @@ bool Binary_Output_Write_Property(
return status;
}
void Binary_Output_Init(
void)
{
unsigned i, j;
/* initialize all the analog output priority arrays to NULL */
for (i = 0; i < MAX_BINARY_OUTPUTS; i++) {
seeprom_bytes_read(
NV_SEEPROM_BINARY_OUTPUT(i,NV_SEEPROM_BO_POLARITY),
&Polarity[i],
1);
if (Polarity[i] >= MAX_POLARITY) {
Binary_Output_Polarity_Set(i, POLARITY_NORMAL);
}
seeprom_bytes_read(
NV_SEEPROM_BINARY_OUTPUT(i,NV_SEEPROM_BO_OUT_OF_SERVICE),
&Out_Of_Service[i],
1);
if (Out_Of_Service[i] > 1) {
Binary_Output_Out_Of_Service_Set(i, false);
}
for (j = 0; j < BACNET_MAX_PRIORITY; j++) {
seeprom_bytes_read(
NV_SEEPROM_BINARY_OUTPUT(i,
NV_SEEPROM_BO_PRIORITY_ARRAY_1+j),
&Binary_Output_Level[i][j],
1);
}
Binary_Output_Sync(i);
}
return;
}
@@ -35,6 +35,7 @@
#include "rs485.h"
#include "version.h"
#include "nvdata.h"
#include "stack.h"
/* objects */
#include "device.h"
#include "ai.h"
@@ -495,6 +496,12 @@ int Device_Encode_Property_APDU(
apdu_len =
encode_application_unsigned(&apdu[0], dlmstp_max_master());
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;
@@ -45,4 +45,11 @@
#include "iar2gcc.h"
#include "bits.h"
/* SEEPROM is 24LC128 */
//#define SEEPROM_PAGE_SIZE 128
//#define SEEPROM_WORD_ADDRESS_16BIT 1
/* SEEPROM is 24C16 */
#define SEEPROM_PAGE_SIZE 16
#define SEEPROM_WORD_ADDRESS_16BIT 0
#endif
+28 -2
View File
@@ -27,10 +27,11 @@
#include <stdint.h>
#include "hardware.h"
#include "init.h"
#include "stack.h"
#include "timer.h"
#include "input.h"
#include "led.h"
#include "seeprom.h"
#include "nvdata.h"
#include "timer.h"
#include "dcc.h"
#include "rs485.h"
@@ -101,16 +102,41 @@ FUSES =
LOCKBITS = LOCKBITS_DEFAULT;
#endif
bool seeprom_version_test(void)
{
uint16_t version = 0;
uint16_t id = 0;
bool status = false;
seeprom_bytes_read(NV_SEEPROM_TYPE_0, (uint8_t *)&id, 2);
seeprom_bytes_read(NV_SEEPROM_VERSION_0, (uint8_t *)&version, 2);
if ((id == SEEPROM_ID) && (version == SEEPROM_VERSION)) {
status = true;
} else {
version = SEEPROM_VERSION;
id = SEEPROM_ID;
seeprom_bytes_write(NV_SEEPROM_TYPE_0, (uint8_t *)&id, 2);
seeprom_bytes_write(NV_SEEPROM_VERSION_0, (uint8_t *)&version, 2);
}
return status;
}
static void bacnet_init(
void)
{
MSTP_MAC_Address = input_address();
dlmstp_set_mac_address(MSTP_MAC_Address);
dlmstp_init(NULL);
if (!seeprom_version_test()) {
/* invalid version data */
}
/* initialize objects */
Device_Init();
Binary_Output_Init();
/* 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. */
@@ -91,6 +91,34 @@
#define NV_EEPROM_DEVICE_NAME_31 41
#define NV_EEPROM_DEVICE_NAME_SIZE 32
/*=============== SEEPROM ================*/
#define NV_SEEPROM_BINARY_OUTPUT_OFFSET 32
#define NV_SEEPROM_BINARY_OUTPUT_0 10
#define NV_SEEPROM_BINARY_OUTPUT(n,p) \
(NV_SEEPROM_BINARY_OUTPUT_0 + \
(NV_SEEPROM_BINARY_OUTPUT_OFFSET * (n)) + (p))
/* BO properties */
#define NV_SEEPROM_BO_POLARITY 0
#define NV_SEEPROM_BO_OUT_OF_SERVICE 1
#define NV_SEEPROM_BO_PRIORITY_ARRAY_1 2
#define NV_SEEPROM_BO_PRIORITY_ARRAY_2 3
#define NV_SEEPROM_BO_PRIORITY_ARRAY_3 4
#define NV_SEEPROM_BO_PRIORITY_ARRAY_4 5
#define NV_SEEPROM_BO_PRIORITY_ARRAY_5 6
#define NV_SEEPROM_BO_PRIORITY_ARRAY_6 7
#define NV_SEEPROM_BO_PRIORITY_ARRAY_7 8
#define NV_SEEPROM_BO_PRIORITY_ARRAY_8 9
#define NV_SEEPROM_BO_PRIORITY_ARRAY_9 10
#define NV_SEEPROM_BO_PRIORITY_ARRAY_10 11
#define NV_SEEPROM_BO_PRIORITY_ARRAY_11 12
#define NV_SEEPROM_BO_PRIORITY_ARRAY_12 13
#define NV_SEEPROM_BO_PRIORITY_ARRAY_13 14
#define NV_SEEPROM_BO_PRIORITY_ARRAY_14 15
#define NV_SEEPROM_BO_PRIORITY_ARRAY_15 16
#define NV_SEEPROM_BO_PRIORITY_ARRAY_16 17
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
+2 -2
View File
@@ -97,7 +97,7 @@
/*************************************************************************
* DESCRIPTION: Return bytes from SEEPROM memory at address
* RETURN: number of bytes read, or -1 on error
* NOTES: The 24LC128 SEEPROM uses a two byte memory address
* NOTES: none
**************************************************************************/
int seeprom_bytes_read(
uint16_t eeaddr, /* SEEPROM starting memory address */
@@ -274,7 +274,7 @@ error:
/*************************************************************************
* DESCRIPTION: Write some data and wait until it is sent
* RETURN: number of bytes written, or -1 on error
* NOTES: The 24LC128 SEEPROM uses a two byte memory address
* NOTES: none
**************************************************************************/
int seeprom_bytes_write(
uint16_t eeaddr, /* SEEPROM starting memory address */
+27 -2
View File
@@ -29,10 +29,10 @@ extern uint8_t _end;
extern uint8_t __stack;
#define STACK_CANARY (0xC5)
void stack_paint(
void stack_init(
void) __attribute__ ((naked)) __attribute__ ((section(".init1")));
void stack_paint(
void stack_init(
void)
{
#if 0
@@ -50,3 +50,28 @@ void stack_paint(
" cpc r31,r25\n" " brlo .loop\n" " breq .loop"::);
#endif
}
unsigned stack_size(void)
{
return (&__stack) - (&_end);
}
uint8_t stack_byte(unsigned offset)
{
return *(&_end + offset);
}
unsigned stack_unused(void)
{
uint8_t *p = &_end;
unsigned count = 0;
while (p <= &__stack) {
if ((*p) != STACK_CANARY) {
count = p - (&_end);
break;
}
p++;
}
return count;
}
+48
View File
@@ -0,0 +1,48 @@
/**************************************************************************
*
* 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