Tuned the ATmega168 port demo project that runs a Device Object and 9 Analog Inputs, and uses ReadProperty service. Uses 16158 bytes of flash, 624 bytes of RAM with an APDU of 128.
This commit is contained in:
@@ -91,7 +91,7 @@ OPTIMIZATION = -Os -mcall-prologues
|
|||||||
|
|
||||||
## Compile options common for all C compilation units.
|
## Compile options common for all C compilation units.
|
||||||
BFLAGS = -DBACDL_MSTP
|
BFLAGS = -DBACDL_MSTP
|
||||||
BFLAGS += -DMAX_APDU=50
|
BFLAGS += -DMAX_APDU=128
|
||||||
BFLAGS += -DBIG_ENDIAN=0
|
BFLAGS += -DBIG_ENDIAN=0
|
||||||
BFLAGS += -DMAX_TSM_TRANSACTIONS=0
|
BFLAGS += -DMAX_TSM_TRANSACTIONS=0
|
||||||
#BFLAGS += -DCRC_USE_TABLE
|
#BFLAGS += -DCRC_USE_TABLE
|
||||||
|
|||||||
@@ -34,12 +34,12 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
/* Analog Input = Photocell */
|
/* Analog Input = Photocell */
|
||||||
#define MAX_ANALOG_INPUTS 2
|
#define MAX_ANALOG_INPUTS 9
|
||||||
#if (MAX_ANALOG_INPUTS > 9)
|
#if (MAX_ANALOG_INPUTS > 9)
|
||||||
#error Modify the Analog_Input_Name to handle multiple digits
|
#error Modify the Analog_Input_Name to handle multiple digits
|
||||||
#endif
|
#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 */
|
/* we simply have 0-n object instances. Yours might be */
|
||||||
/* more complex, and then you need validate that the */
|
/* more complex, and then you need validate that the */
|
||||||
@@ -76,16 +76,6 @@ char *Analog_Input_Name(uint32_t object_instance)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return apdu length, or -1 on error */
|
/* return apdu length, or -1 on error */
|
||||||
/* assumption - object has already exists */
|
/* assumption - object has already exists */
|
||||||
int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
||||||
@@ -105,7 +95,8 @@ int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
|||||||
object_instance);
|
object_instance);
|
||||||
break;
|
break;
|
||||||
/* note: Name and Description don't have to be the same.
|
/* note: Name and Description don't have to be the same.
|
||||||
You could make Description writable and different */
|
You could make Description writable and different.
|
||||||
|
Note that Object-Name must be unique in this device */
|
||||||
case PROP_OBJECT_NAME:
|
case PROP_OBJECT_NAME:
|
||||||
case PROP_DESCRIPTION:
|
case PROP_DESCRIPTION:
|
||||||
characterstring_init_ansi(&char_string,
|
characterstring_init_ansi(&char_string,
|
||||||
@@ -118,7 +109,7 @@ int Analog_Input_Encode_Property_APDU(uint8_t * apdu,
|
|||||||
break;
|
break;
|
||||||
case PROP_PRESENT_VALUE:
|
case PROP_PRESENT_VALUE:
|
||||||
apdu_len = encode_application_real(&apdu[0],
|
apdu_len = encode_application_real(&apdu[0],
|
||||||
Analog_Input_Present_Value(object_instance));
|
Present_Value[object_instance]);
|
||||||
break;
|
break;
|
||||||
case PROP_STATUS_FLAGS:
|
case PROP_STATUS_FLAGS:
|
||||||
bitstring_init(&bit_string);
|
bitstring_init(&bit_string);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -49,8 +49,8 @@
|
|||||||
properties that are writable or that may change.
|
properties that are writable or that may change.
|
||||||
The properties that are constant can be hard coded
|
The properties that are constant can be hard coded
|
||||||
into the read-property encoding. */
|
into the read-property encoding. */
|
||||||
static uint32_t Object_Instance_Number = 12345;
|
static uint32_t Object_Instance_Number = 260001;
|
||||||
static char Object_Name[32] = "ATmega Device";
|
static char Object_Name[32] = "ATmega168 Device";
|
||||||
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL;
|
||||||
|
|
||||||
void Device_Init(void)
|
void Device_Init(void)
|
||||||
@@ -203,8 +203,6 @@ int Device_Encode_Property_APDU(uint8_t * apdu,
|
|||||||
int object_type = 0;
|
int object_type = 0;
|
||||||
uint32_t instance = 0;
|
uint32_t instance = 0;
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
BACNET_TIME local_time;
|
|
||||||
BACNET_DATE local_date;
|
|
||||||
|
|
||||||
/* FIXME: change the hardcoded names to suit your application */
|
/* FIXME: change the hardcoded names to suit your application */
|
||||||
switch (property) {
|
switch (property) {
|
||||||
@@ -213,16 +211,13 @@ int Device_Encode_Property_APDU(uint8_t * apdu,
|
|||||||
Object_Instance_Number);
|
Object_Instance_Number);
|
||||||
break;
|
break;
|
||||||
case PROP_OBJECT_NAME:
|
case PROP_OBJECT_NAME:
|
||||||
|
case PROP_DESCRIPTION:
|
||||||
characterstring_init_ansi(&char_string, Object_Name);
|
characterstring_init_ansi(&char_string, Object_Name);
|
||||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||||
break;
|
break;
|
||||||
case PROP_OBJECT_TYPE:
|
case PROP_OBJECT_TYPE:
|
||||||
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
apdu_len = encode_application_enumerated(&apdu[0], OBJECT_DEVICE);
|
||||||
break;
|
break;
|
||||||
case PROP_DESCRIPTION:
|
|
||||||
characterstring_init_ansi(&char_string, "BACnet Demo");
|
|
||||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
|
||||||
break;
|
|
||||||
case PROP_SYSTEM_STATUS:
|
case PROP_SYSTEM_STATUS:
|
||||||
apdu_len =
|
apdu_len =
|
||||||
encode_application_enumerated(&apdu[0], System_Status);
|
encode_application_enumerated(&apdu[0], System_Status);
|
||||||
@@ -247,21 +242,11 @@ int Device_Encode_Property_APDU(uint8_t * apdu,
|
|||||||
characterstring_init_ansi(&char_string, "1.0");
|
characterstring_init_ansi(&char_string, "1.0");
|
||||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
||||||
break;
|
break;
|
||||||
case PROP_LOCATION:
|
|
||||||
characterstring_init_ansi(&char_string, "USA");
|
|
||||||
apdu_len = encode_application_character_string(&apdu[0], &char_string);
|
|
||||||
break;
|
|
||||||
case PROP_PROTOCOL_VERSION:
|
case PROP_PROTOCOL_VERSION:
|
||||||
apdu_len =
|
apdu_len = encode_application_unsigned(&apdu[0], 1);
|
||||||
encode_application_unsigned(&apdu[0], 1);
|
|
||||||
break;
|
break;
|
||||||
case PROP_PROTOCOL_REVISION:
|
case PROP_PROTOCOL_REVISION:
|
||||||
apdu_len =
|
apdu_len = encode_application_unsigned(&apdu[0], 5);
|
||||||
encode_application_unsigned(&apdu[0], 5);
|
|
||||||
break;
|
|
||||||
/* BACnet Legacy Support */
|
|
||||||
case PROP_PROTOCOL_CONFORMANCE_CLASS:
|
|
||||||
apdu_len = encode_application_unsigned(&apdu[0], 1);
|
|
||||||
break;
|
break;
|
||||||
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
case PROP_PROTOCOL_SERVICES_SUPPORTED:
|
||||||
/* Note: list of services that are executed, not initiated. */
|
/* Note: list of services that are executed, not initiated. */
|
||||||
@@ -277,11 +262,6 @@ int Device_Encode_Property_APDU(uint8_t * apdu,
|
|||||||
/* Note: this is the list of objects that can be in this device,
|
/* Note: this is the list of objects that can be in this device,
|
||||||
not a list of objects that this device can access */
|
not a list of objects that this device can access */
|
||||||
bitstring_init(&bit_string);
|
bitstring_init(&bit_string);
|
||||||
for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) {
|
|
||||||
/* FIXME: if ReadProperty used an array of Functions... */
|
|
||||||
/* initialize all the object types to not-supported */
|
|
||||||
bitstring_set_bit(&bit_string, (uint8_t) i, false);
|
|
||||||
}
|
|
||||||
/* FIXME: indicate the objects that YOU support */
|
/* FIXME: indicate the objects that YOU support */
|
||||||
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
bitstring_set_bit(&bit_string, OBJECT_DEVICE, true);
|
||||||
bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true);
|
bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true);
|
||||||
@@ -367,30 +347,6 @@ int Device_Encode_Property_APDU(uint8_t * apdu,
|
|||||||
case PROP_MAX_MASTER:
|
case PROP_MAX_MASTER:
|
||||||
apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
apdu_len = encode_application_unsigned(&apdu[0], dlmstp_max_master());
|
||||||
break;
|
break;
|
||||||
case PROP_LOCAL_TIME:
|
|
||||||
/* FIXME: if you support time */
|
|
||||||
local_time.hour = 0;
|
|
||||||
local_time.min = 0;
|
|
||||||
local_time.sec = 0;
|
|
||||||
local_time.hundredths = 0;
|
|
||||||
apdu_len = encode_application_time(&apdu[0], &local_time);
|
|
||||||
break;
|
|
||||||
case PROP_UTC_OFFSET:
|
|
||||||
/* Note: BACnet Time Zone is inverse of everybody else */
|
|
||||||
apdu_len = encode_application_signed(&apdu[0], 5 /* EST */ );
|
|
||||||
break;
|
|
||||||
case PROP_LOCAL_DATE:
|
|
||||||
/* FIXME: if you support date */
|
|
||||||
local_date.year = 2006; /* AD */
|
|
||||||
local_date.month = 4; /* Jan=1..Dec=12 */
|
|
||||||
local_date.day = 11; /* 1..31 */
|
|
||||||
local_date.wday = 0; /* 1=Mon..7=Sun */
|
|
||||||
apdu_len = encode_application_date(&apdu[0], &local_date);
|
|
||||||
break;
|
|
||||||
case PROP_DAYLIGHT_SAVINGS_STATUS:
|
|
||||||
/* FIXME: if you support time/date */
|
|
||||||
apdu_len = encode_application_boolean(&apdu[0], false);
|
|
||||||
break;
|
|
||||||
case 9600:
|
case 9600:
|
||||||
apdu_len = encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
apdu_len = encode_application_unsigned(&apdu[0], RS485_Get_Baud_Rate());
|
||||||
break;
|
break;
|
||||||
@@ -519,4 +475,4 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -402,7 +402,8 @@ static void MSTP_Send_Frame(
|
|||||||
{ /* number of bytes of data (up to 501) */
|
{ /* number of bytes of data (up to 501) */
|
||||||
uint8_t crc8 = 0xFF; /* used to calculate the crc value */
|
uint8_t crc8 = 0xFF; /* used to calculate the crc value */
|
||||||
uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */
|
uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */
|
||||||
uint8_t buffer[8]; /* stores the header and data crc */
|
uint8_t buffer[8]; /* stores the header and crc */
|
||||||
|
uint8_t datacrc[2]; /* stores the data crc */
|
||||||
uint16_t i = 0; /* used to calculate CRC for data */
|
uint16_t i = 0; /* used to calculate CRC for data */
|
||||||
|
|
||||||
/* create the MS/TP header */
|
/* create the MS/TP header */
|
||||||
@@ -419,10 +420,6 @@ static void MSTP_Send_Frame(
|
|||||||
buffer[6] = data_len % 256;
|
buffer[6] = data_len % 256;
|
||||||
crc8 = CRC_Calc_Header(buffer[6], crc8);
|
crc8 = CRC_Calc_Header(buffer[6], crc8);
|
||||||
buffer[7] = ~crc8;
|
buffer[7] = ~crc8;
|
||||||
RS485_Turnaround_Delay();
|
|
||||||
RS485_Transmitter_Enable(true);
|
|
||||||
RS485_Send_Data(buffer,8);
|
|
||||||
/* send any data */
|
|
||||||
if (data_len) {
|
if (data_len) {
|
||||||
/* calculate CRC for any data */
|
/* calculate CRC for any data */
|
||||||
for (i = 0; i < data_len; i++)
|
for (i = 0; i < data_len; i++)
|
||||||
@@ -430,10 +427,17 @@ static void MSTP_Send_Frame(
|
|||||||
crc16 = CRC_Calc_Data(data[i], crc16);
|
crc16 = CRC_Calc_Data(data[i], crc16);
|
||||||
}
|
}
|
||||||
crc16 = ~crc16;
|
crc16 = ~crc16;
|
||||||
buffer[0] = (crc16 & 0x00FF);
|
datacrc[0] = (crc16 & 0x00FF);
|
||||||
buffer[1] = ((crc16 & 0xFF00) >> 8);
|
datacrc[1] = ((crc16 & 0xFF00) >> 8);
|
||||||
|
}
|
||||||
|
/* now transmit the frame */
|
||||||
|
RS485_Turnaround_Delay();
|
||||||
|
RS485_Transmitter_Enable(true);
|
||||||
|
RS485_Send_Data(buffer,8);
|
||||||
|
/* send any data */
|
||||||
|
if (data_len) {
|
||||||
RS485_Send_Data(data, data_len);
|
RS485_Send_Data(data, data_len);
|
||||||
RS485_Send_Data(buffer, 2);
|
RS485_Send_Data(datacrc, 2);
|
||||||
}
|
}
|
||||||
RS485_Transmitter_Enable(false);
|
RS485_Transmitter_Enable(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,16 +45,18 @@ void handler_who_is(uint8_t * service_request,
|
|||||||
int len = 0;
|
int len = 0;
|
||||||
int32_t low_limit = 0;
|
int32_t low_limit = 0;
|
||||||
int32_t high_limit = 0;
|
int32_t high_limit = 0;
|
||||||
|
int32_t target_device;
|
||||||
|
|
||||||
(void) src;
|
(void) src;
|
||||||
len = whois_decode_service_request(service_request,
|
len = whois_decode_service_request(service_request,
|
||||||
service_len, &low_limit, &high_limit);
|
service_len, &low_limit, &high_limit);
|
||||||
if (len == 0)
|
if (len == 0) {
|
||||||
iam_send(&Handler_Transmit_Buffer[0]);
|
Send_I_Am = true;
|
||||||
else if (len != -1) {
|
} else if (len != -1) {
|
||||||
/* is my device id within the limits? */
|
/* is my device id within the limits? */
|
||||||
if (((Device_Object_Instance_Number() >= (uint32_t) low_limit) &&
|
target_device = Device_Object_Instance_Number();
|
||||||
(Device_Object_Instance_Number() <= (uint32_t) high_limit))
|
if (((target_device >= low_limit) &&
|
||||||
|
(target_device <= high_limit))
|
||||||
||
|
||
|
||||||
/* BACnet wildcard is the max instance number - everyone responds */
|
/* BACnet wildcard is the max instance number - everyone responds */
|
||||||
((BACNET_MAX_INSTANCE >= (uint32_t) low_limit) &&
|
((BACNET_MAX_INSTANCE >= (uint32_t) low_limit) &&
|
||||||
|
|||||||
@@ -152,23 +152,23 @@ int main(void)
|
|||||||
|
|
||||||
init();
|
init();
|
||||||
#if defined(BACDL_MSTP)
|
#if defined(BACDL_MSTP)
|
||||||
//RS485_Set_Baud_Rate(38400);
|
RS485_Set_Baud_Rate(38400);
|
||||||
dlmstp_set_max_master(127);
|
dlmstp_set_max_master(127);
|
||||||
dlmstp_set_max_info_frames(1);
|
dlmstp_set_max_info_frames(1);
|
||||||
#endif
|
#endif
|
||||||
datalink_init(NULL);
|
datalink_init(NULL);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (Send_I_Am)
|
if (Send_I_Am) {
|
||||||
|
Send_I_Am = false;
|
||||||
iam_send(&Handler_Transmit_Buffer[0]);
|
iam_send(&Handler_Transmit_Buffer[0]);
|
||||||
|
}
|
||||||
input_switch_read();
|
input_switch_read();
|
||||||
task_milliseconds();
|
task_milliseconds();
|
||||||
/* other tasks */
|
/* other tasks */
|
||||||
/* BACnet handling */
|
/* BACnet handling */
|
||||||
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
|
pdu_len = datalink_receive(&src, &PDUBuffer[0], sizeof(PDUBuffer), 0);
|
||||||
if (pdu_len) {
|
if (pdu_len) {
|
||||||
#if !defined(TEST_MSTP)
|
|
||||||
npdu_handler(&src, &PDUBuffer[0], pdu_len);
|
npdu_handler(&src, &PDUBuffer[0], pdu_len);
|
||||||
#endif
|
|
||||||
NPDU_LED_On();
|
NPDU_LED_On();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user