From 71d59fbb8b1111427afce59298e32aa92ca5ced2 Mon Sep 17 00:00:00 2001 From: skarg Date: Fri, 2 Feb 2007 02:25:15 +0000 Subject: [PATCH] Standardized the comments and indentation using the comment.sh and indent.sh scripts. --- bacnet-stack/bacapp.c | 189 +- bacnet-stack/bacapp.h | 4 +- bacnet-stack/bacdcode.c | 5 +- bacnet-stack/bacenum.h | 4 +- bacnet-stack/bactext.c | 180 +- bacnet-stack/cov.c | 66 +- bacnet-stack/cov.h | 26 +- bacnet-stack/datalink.h | 20 +- bacnet-stack/datetime.c | 1330 +++++---- bacnet-stack/datetime.h | 200 +- bacnet-stack/demo/handler/h_rp.c | 3 +- bacnet-stack/demo/handler/h_rp_a.c | 4 +- bacnet-stack/demo/handler/h_wp.c | 3 +- bacnet-stack/demo/handler/s_rp.c | 3 +- bacnet-stack/demo/handler/s_wp.c | 7 +- bacnet-stack/demo/object/ai.c | 4 +- bacnet-stack/demo/object/ao.c | 15 +- bacnet-stack/demo/object/av.c | 28 +- bacnet-stack/demo/object/bacfile.c | 6 +- bacnet-stack/demo/object/bo.c | 16 +- bacnet-stack/demo/object/bv.c | 19 +- bacnet-stack/demo/object/device.c | 22 +- bacnet-stack/demo/object/lc.c | 640 ++-- bacnet-stack/demo/object/lsp.c | 16 +- bacnet-stack/demo/object/mso.c | 35 +- bacnet-stack/demo/writeprop/writeprop.c | 133 +- bacnet-stack/iam.c | 9 +- bacnet-stack/npdu.c | 3 +- bacnet-stack/ports/pic18f6720/device.c | 1134 +++---- bacnet-stack/ports/pic18f6720/dlmstp.c | 731 +++-- bacnet-stack/ports/pic18f6720/dlmstp.h | 220 +- bacnet-stack/ports/pic18f6720/hardware.h | 530 ++-- bacnet-stack/ports/pic18f6720/isr.c | 402 ++- bacnet-stack/ports/pic18f6720/main.c | 330 +-- bacnet-stack/ports/pic18f6720/mstp.c | 3408 +++++++++++----------- bacnet-stack/ports/pic18f6720/mstp.h | 492 ++-- bacnet-stack/ports/pic18f6720/rs485.c | 762 +++-- bacnet-stack/ports/pic18f6720/rs485.h | 169 +- bacnet-stack/ports/pic18f6720/stdbool.h | 56 +- bacnet-stack/ports/pic18f6720/stdint.h | 36 +- bacnet-stack/tsm.c | 11 +- bacnet-stack/wp.c | 42 +- 42 files changed, 5623 insertions(+), 5690 deletions(-) diff --git a/bacnet-stack/bacapp.c b/bacnet-stack/bacapp.c index 7dd66470..713be6ac 100644 --- a/bacnet-stack/bacapp.c +++ b/bacnet-stack/bacapp.c @@ -173,31 +173,29 @@ int bacapp_decode_application_data(uint8_t * apdu, } int bacapp_encode_context_data(uint8_t * apdu, - BACNET_APPLICATION_DATA_VALUE * value, - BACNET_PROPERTY_ID property) + BACNET_APPLICATION_DATA_VALUE * value, BACNET_PROPERTY_ID property) { int apdu_len = 0; /* total length of the apdu, return value */ if (value && apdu) { switch (property) { - case PROP_REQUESTED_SHED_LEVEL: - switch (value->tag) { - case 0: - case 1: - apdu_len = encode_tagged_unsigned(&apdu[0], - value->type.Unsigned_Int); - break; - case 2: - apdu_len = encode_tagged_real(&apdu[0], - value->type.Real); - break; - default: - apdu_len = 0; - break; - } + case PROP_REQUESTED_SHED_LEVEL: + switch (value->tag) { + case 0: + case 1: + apdu_len = encode_tagged_unsigned(&apdu[0], + value->type.Unsigned_Int); + break; + case 2: + apdu_len = encode_tagged_real(&apdu[0], value->type.Real); break; default: + apdu_len = 0; break; + } + break; + default: + break; } } return apdu_len; @@ -221,25 +219,23 @@ int bacapp_decode_context_data(uint8_t * apdu, len += tag_len; value->tag = tag_number; switch (property) { - case PROP_REQUESTED_SHED_LEVEL: - switch (tag_number) { - case 0: - case 1: - len += decode_unsigned(&apdu[len], - len_value_type, - &(value->type.Unsigned_Int)); - break; - case 2: - len += decode_real(&apdu[len], - &(value->type.Real)); - break; - default: - len = 0; - break; - } + case PROP_REQUESTED_SHED_LEVEL: + switch (tag_number) { + case 0: + case 1: + len += decode_unsigned(&apdu[len], + len_value_type, &(value->type.Unsigned_Int)); + break; + case 2: + len += decode_real(&apdu[len], &(value->type.Real)); break; default: + len = 0; break; + } + break; + default: + break; } } } @@ -277,10 +273,12 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value, dest_value->type.Enumerated = src_value->type.Enumerated; break; case BACNET_APPLICATION_TAG_DATE: - datetime_copy_date(&dest_value->type.Date, &src_value->type.Date); + datetime_copy_date(&dest_value->type.Date, + &src_value->type.Date); break; case BACNET_APPLICATION_TAG_TIME: - datetime_copy_time(&dest_value->type.Time, &src_value->type.Time); + datetime_copy_time(&dest_value->type.Time, + &src_value->type.Time); break; case BACNET_APPLICATION_TAG_OBJECT_ID: dest_value->type.Object_Id.type = @@ -310,57 +308,56 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value, Expects that the first octet contain the opening tag. Include a value property identifier for context specific data such as the value received in a WriteProperty request */ -int bacapp_data_len(uint8_t *apdu, int max_apdu_len, +int bacapp_data_len(uint8_t * apdu, int max_apdu_len, BACNET_PROPERTY_ID property) { - int len = 0; - int total_len = 0; - int apdu_len = 0; - uint8_t tag_number = 0; - uint8_t opening_tag_number = 0; - uint8_t opening_tag_number_counter = 0; - uint32_t value = 0; - BACNET_APPLICATION_DATA_VALUE application_value; + int len = 0; + int total_len = 0; + int apdu_len = 0; + uint8_t tag_number = 0; + uint8_t opening_tag_number = 0; + uint8_t opening_tag_number_counter = 0; + uint32_t value = 0; + BACNET_APPLICATION_DATA_VALUE application_value; - if (decode_is_opening_tag(&apdu[0])) { - len = decode_tag_number_and_value(&apdu[apdu_len], - &tag_number, &value); - apdu_len += len; - opening_tag_number = tag_number; - opening_tag_number_counter = 1; - while (opening_tag_number_counter) { - if (decode_is_opening_tag(&apdu[apdu_len])) { - len = decode_tag_number_and_value(&apdu[apdu_len], - &tag_number, &value); - if (tag_number == opening_tag_number) - opening_tag_number_counter++; - } else if (decode_is_closing_tag(&apdu[apdu_len])) { - len = decode_tag_number_and_value(&apdu[apdu_len], - &tag_number, &value); - if (tag_number == opening_tag_number) - opening_tag_number_counter--; - } else if (decode_is_context_specific(&apdu[apdu_len])) { - /* context-specific tagged data */ - len = bacapp_decode_context_data(&apdu[apdu_len], - max_apdu_len - apdu_len, &application_value, property); - } else { - /* application tagged data */ - len = bacapp_decode_application_data(&apdu[apdu_len], - max_apdu_len - apdu_len, &application_value); - } - apdu_len += len; - if (opening_tag_number_counter) - total_len += len; - /* ERROR! */ - if (apdu_len > max_apdu_len) - { - total_len = -1; - break; - } - } - } + if (decode_is_opening_tag(&apdu[0])) { + len = decode_tag_number_and_value(&apdu[apdu_len], + &tag_number, &value); + apdu_len += len; + opening_tag_number = tag_number; + opening_tag_number_counter = 1; + while (opening_tag_number_counter) { + if (decode_is_opening_tag(&apdu[apdu_len])) { + len = decode_tag_number_and_value(&apdu[apdu_len], + &tag_number, &value); + if (tag_number == opening_tag_number) + opening_tag_number_counter++; + } else if (decode_is_closing_tag(&apdu[apdu_len])) { + len = decode_tag_number_and_value(&apdu[apdu_len], + &tag_number, &value); + if (tag_number == opening_tag_number) + opening_tag_number_counter--; + } else if (decode_is_context_specific(&apdu[apdu_len])) { + /* context-specific tagged data */ + len = bacapp_decode_context_data(&apdu[apdu_len], + max_apdu_len - apdu_len, &application_value, property); + } else { + /* application tagged data */ + len = bacapp_decode_application_data(&apdu[apdu_len], + max_apdu_len - apdu_len, &application_value); + } + apdu_len += len; + if (opening_tag_number_counter) + total_len += len; + /* ERROR! */ + if (apdu_len > max_apdu_len) { + total_len = -1; + break; + } + } + } - return total_len; + return total_len; } #ifdef BACAPP_PRINT_ENABLED @@ -475,7 +472,7 @@ bool bacapp_print_value(FILE * stream, for (i = 0; i < len; i++) { fprintf(stream, "%s", bitstring_bit(&value->type.Bit_String, - (uint8_t)i) ? "true" : "false"); + (uint8_t) i) ? "true" : "false"); if (i < len - 1) fprintf(stream, ","); } @@ -580,7 +577,7 @@ void testBACnetApplicationDataLength(Test * pTest) { int apdu_len = 0; /* total length of the apdu, return value */ int len = 0; /* total length of the apdu, return value */ - int test_len = 0; /* length of the data */ + int test_len = 0; /* length of the data */ uint8_t apdu[480] = { 0 }; BACNET_TIME local_time; BACNET_DATE local_date; @@ -609,8 +606,7 @@ void testBACnetApplicationDataLength(Test * pTest) len = encode_closing_tag(&apdu[apdu_len], 3); apdu_len += len; /* verify the length of the data inside the opening/closing tags */ - len = bacapp_data_len(&apdu[0], apdu_len, - PROP_OBJECT_IDENTIFIER); + len = bacapp_data_len(&apdu[0], apdu_len, PROP_OBJECT_IDENTIFIER); ct_test(pTest, test_len == len); /* 3. application tagged data, multiple elements */ @@ -669,8 +665,7 @@ void testBACnetApplicationDataLength(Test * pTest) len = encode_closing_tag(&apdu[apdu_len], 3); apdu_len += len; /* verify the length of the data inside the opening/closing tags */ - len = bacapp_data_len(&apdu[0], apdu_len, - PROP_PRIORITY_ARRAY); + len = bacapp_data_len(&apdu[0], apdu_len, PROP_PRIORITY_ARRAY); ct_test(pTest, test_len == len); /* 4. complex datatype - one element */ @@ -681,10 +676,10 @@ void testBACnetApplicationDataLength(Test * pTest) len = encode_opening_tag(&apdu[apdu_len], 3); test_len += len; apdu_len += len; - local_date.year = 2006; /* AD */ - local_date.month = 4; /* 1=Jan */ - local_date.day = 1; /* 1..31 */ - local_date.wday = 6; /* 1=Monday */ + local_date.year = 2006; /* AD */ + local_date.month = 4; /* 1=Jan */ + local_date.day = 1; /* 1..31 */ + local_date.wday = 6; /* 1=Monday */ len = encode_tagged_date(&apdu[apdu_len], &local_date); test_len += len; apdu_len += len; @@ -701,8 +696,7 @@ void testBACnetApplicationDataLength(Test * pTest) len = encode_closing_tag(&apdu[apdu_len], 3); apdu_len += len; /* verify the length of the data inside the opening/closing tags */ - len = bacapp_data_len(&apdu[0], apdu_len, - PROP_START_TIME); + len = bacapp_data_len(&apdu[0], apdu_len, PROP_START_TIME); ct_test(pTest, test_len == len); /* 5. complex datatype - multiple elements */ @@ -720,8 +714,7 @@ void testBACnetApplicationDataLength(Test * pTest) len = encode_closing_tag(&apdu[apdu_len], 3); apdu_len += len; /* verify the length of the data inside the opening/closing tags */ - len = bacapp_data_len(&apdu[0], apdu_len, - PROP_REQUESTED_SHED_LEVEL); + len = bacapp_data_len(&apdu[0], apdu_len, PROP_REQUESTED_SHED_LEVEL); ct_test(pTest, test_len == len); } @@ -766,12 +759,12 @@ bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE * value, break; case BACNET_APPLICATION_TAG_DATE: if (datetime_compare_date(&test_value->type.Date, - &value->type.Date) != 0) + &value->type.Date) != 0) status = false; break; case BACNET_APPLICATION_TAG_TIME: if (datetime_compare_time(&test_value->type.Time, - &value->type.Time) != 0) + &value->type.Time) != 0) status = false; break; case BACNET_APPLICATION_TAG_OBJECT_ID: diff --git a/bacnet-stack/bacapp.h b/bacnet-stack/bacapp.h index 7e6fa88a..88ed4dc3 100644 --- a/bacnet-stack/bacapp.h +++ b/bacnet-stack/bacapp.h @@ -42,7 +42,7 @@ #include "datetime.h" typedef struct BACnet_Application_Data_Value { - uint8_t tag; /* application or context-specific number */ + uint8_t tag; /* application or context-specific number */ union { /* NULL - not needed as it is encoded in the tag alone */ bool Boolean; @@ -85,7 +85,7 @@ extern "C" { Expects that the first octet contain the opening tag. Include a value property identifier for context specific data such as the value received in a WriteProperty request */ - int bacapp_data_len(uint8_t *apdu, int max_apdu_len, + int bacapp_data_len(uint8_t * apdu, int max_apdu_len, BACNET_PROPERTY_ID property); #if PRINT_ENABLED diff --git a/bacnet-stack/bacdcode.c b/bacnet-stack/bacdcode.c index 0cbccfb4..463de8c2 100644 --- a/bacnet-stack/bacdcode.c +++ b/bacnet-stack/bacdcode.c @@ -731,9 +731,10 @@ int encode_tagged_boolean(uint8_t * apdu, bool boolean_value) } /* context tagged is encoded differently */ -int encode_context_boolean(uint8_t * apdu, int tag_number, bool boolean_value) +int encode_context_boolean(uint8_t * apdu, int tag_number, + bool boolean_value) { - int len = 1; /* return value */ + int len = 1; /* return value */ apdu[1] = boolean_value ? 1 : 0; /* we only reserved 1 byte for encoding the tag - check the limits */ diff --git a/bacnet-stack/bacenum.h b/bacnet-stack/bacenum.h index 2ea2464f..fb50dfe7 100644 --- a/bacnet-stack/bacenum.h +++ b/bacnet-stack/bacenum.h @@ -243,7 +243,7 @@ typedef enum { PROP_RESTART_NOTIFICATION_RECIPIENTS = 202, PROP_TIME_OF_DEVICE_RESTART = 203, PROP_TIME_SYNCHRONIZATION_INTERVAL = 204, - PROP_TRIGGER = 205, + PROP_TRIGGER = 205, PROP_UTC_TIME_SYNCHRONIZATION_RECIPIENTS = 206, /* enumerations 207-211 are used in Addendum d to ANSI/ASHRAE 135-2004 */ @@ -1186,7 +1186,7 @@ typedef enum { typedef enum BACnetNodeType { BACNET_NODE_UNKNOWN = 0, - BACNET_NODE_SYSTEM = 1, + BACNET_NODE_SYSTEM = 1, BACNET_NODE_NETWORK = 2, BACNET_NODE_DEVICE = 3, BACNET_NODE_ORGANIZATIONAL = 4, diff --git a/bacnet-stack/bactext.c b/bacnet-stack/bactext.c index 9d85278a..911e033e 100644 --- a/bacnet-stack/bactext.c +++ b/bacnet-stack/bactext.c @@ -203,14 +203,20 @@ INDTEXT_DATA bacnet_object_type_names[] = { , {OBJECT_ACCUMULATOR, "Accumulator"} , - {OBJECT_PULSE_CONVERTER, "Pulse-Converter"}, - - {OBJECT_EVENT_LOG, "Event-Log"}, - {OBJECT_GLOBAL_GROUP, "Global-Group"}, - {OBJECT_TREND_LOG_MULTIPLE, "Trend-Log-Multiple"}, - {OBJECT_LOAD_CONTROL, "Load-Control"}, - {OBJECT_STRUCTURED_VIEW, "Structured-View"}, - + {OBJECT_PULSE_CONVERTER, "Pulse-Converter"} + , + + {OBJECT_EVENT_LOG, "Event-Log"} + , + {OBJECT_GLOBAL_GROUP, "Global-Group"} + , + {OBJECT_TREND_LOG_MULTIPLE, "Trend-Log-Multiple"} + , + {OBJECT_LOAD_CONTROL, "Load-Control"} + , + {OBJECT_STRUCTURED_VIEW, "Structured-View"} + , + {0, NULL} /* Enumerated values 0-127 are reserved for definition by ASHRAE. Enumerated values 128-1023 may be used by others subject to @@ -566,58 +572,112 @@ INDTEXT_DATA bacnet_property_names[] = { , {PROP_PROFILE_NAME, "profile-name"} , - {PROP_AUTO_SLAVE_DISCOVERY, "auto-slave-discovery"}, - {PROP_MANUAL_SLAVE_ADDRESS_BINDING, "manual-slave-address-binding"}, - {PROP_SLAVE_ADDRESS_BINDING, "slave-address-binding"}, - {PROP_SLAVE_PROXY_ENABLE, "slave-proxy-enable"}, - {PROP_LAST_NOTIFY_TIME, "last-notify-time"}, - {PROP_SCHEDULE_DEFAULT, "schedule-default"}, - {PROP_ACCEPTED_MODES, "accepted-modes"}, - {PROP_ADJUST_VALUE, "adjust-value"}, - {PROP_COUNT, "count"}, - {PROP_COUNT_BEFORE_CHANGE, "count-before-change"}, - {PROP_COUNT_CHANGE_TIME, "count-change-time"}, - {PROP_COV_PERIOD, "COV-period"}, - {PROP_INPUT_REFERENCE, "input-reference"}, - {PROP_LIMIT_MONITORING_INTERVAL, "limit-monitoring-interval"}, - {PROP_LOGGING_DEVICE, "logging-device"}, - {PROP_LOGGING_RECORD, "logging-record"}, - {PROP_PRESCALE, "prescale"}, - {PROP_PULSE_RATE, "pulse-rate"}, - {PROP_SCALE, "scale"}, - {PROP_SCALE_FACTOR, "scale-factor"}, - {PROP_UPDATE_TIME, "update-time"}, - {PROP_VALUE_BEFORE_CHANGE, "value-before-change"}, - {PROP_VALUE_SET, "value-set"}, - {PROP_VALUE_CHANGE_TIME, "value-change-time"}, - {PROP_ALIGN_INTERVALS, "align-intervals"}, - {PROP_GROUP_MEMBER_NAMES, "group-member-names"}, - {PROP_INTERVAL_OFFSET, "interval-offset"}, - {PROP_LAST_RESTART_REASON, "last-restart-reason"}, - {PROP_LOGGING_TYPE, "logging-type"}, - {PROP_MEMBER_STATUS_FLAGS, "member-status-flags"}, - {PROP_NOTIFICATION_PERIOD, "notification-period"}, - {PROP_PREVIOUS_NOTIFY_RECORD, "previous-notify-record"}, - {PROP_REQUESTED_UPDATE_INTERVAL, "requested-update-interval"}, - {PROP_RESTART_NOTIFICATION_RECIPIENTS, "restart-notification-recipients"}, - {PROP_TIME_OF_DEVICE_RESTART, "time-of-device-restart"}, - {PROP_TIME_SYNCHRONIZATION_INTERVAL, "time-synchronization-interval"}, - {PROP_TRIGGER, "trigger"}, - {PROP_UTC_TIME_SYNCHRONIZATION_RECIPIENTS, "UTC-time-synchronization-recipients"}, - {PROP_NODE_SUBTYPE, "node-subtype"}, - {PROP_NODE_TYPE, "node-type"}, - {PROP_STRUCTURED_OBJECT_LIST, "structured-object-list"}, - {PROP_SUBORDINATE_ANNOTATIONS, "subordinate-annotations"}, - {PROP_SUBORDINATE_LIST, "subordinate-list"}, - {PROP_ACTUAL_SHED_LEVEL, "actual-shed-level"}, - {PROP_DUTY_WINDOW, "duty-window"}, - {PROP_EXPECTED_SHED_LEVEL, "expected-shed-level"}, - {PROP_FULL_DUTY_BASELINE, "full-duty-baseline"}, - {PROP_REQUESTED_SHED_LEVEL, "requested-shed-level"}, - {PROP_SHED_DURATION, "shed-duration"}, - {PROP_SHED_LEVEL_DESCRIPTIONS, "shed-level-descriptions"}, - {PROP_SHED_LEVELS, "shed-levels"}, - {PROP_STATE_DESCRIPTION, "state-descriptions"}, + {PROP_AUTO_SLAVE_DISCOVERY, "auto-slave-discovery"} + , + {PROP_MANUAL_SLAVE_ADDRESS_BINDING, "manual-slave-address-binding"} + , + {PROP_SLAVE_ADDRESS_BINDING, "slave-address-binding"} + , + {PROP_SLAVE_PROXY_ENABLE, "slave-proxy-enable"} + , + {PROP_LAST_NOTIFY_TIME, "last-notify-time"} + , + {PROP_SCHEDULE_DEFAULT, "schedule-default"} + , + {PROP_ACCEPTED_MODES, "accepted-modes"} + , + {PROP_ADJUST_VALUE, "adjust-value"} + , + {PROP_COUNT, "count"} + , + {PROP_COUNT_BEFORE_CHANGE, "count-before-change"} + , + {PROP_COUNT_CHANGE_TIME, "count-change-time"} + , + {PROP_COV_PERIOD, "COV-period"} + , + {PROP_INPUT_REFERENCE, "input-reference"} + , + {PROP_LIMIT_MONITORING_INTERVAL, "limit-monitoring-interval"} + , + {PROP_LOGGING_DEVICE, "logging-device"} + , + {PROP_LOGGING_RECORD, "logging-record"} + , + {PROP_PRESCALE, "prescale"} + , + {PROP_PULSE_RATE, "pulse-rate"} + , + {PROP_SCALE, "scale"} + , + {PROP_SCALE_FACTOR, "scale-factor"} + , + {PROP_UPDATE_TIME, "update-time"} + , + {PROP_VALUE_BEFORE_CHANGE, "value-before-change"} + , + {PROP_VALUE_SET, "value-set"} + , + {PROP_VALUE_CHANGE_TIME, "value-change-time"} + , + {PROP_ALIGN_INTERVALS, "align-intervals"} + , + {PROP_GROUP_MEMBER_NAMES, "group-member-names"} + , + {PROP_INTERVAL_OFFSET, "interval-offset"} + , + {PROP_LAST_RESTART_REASON, "last-restart-reason"} + , + {PROP_LOGGING_TYPE, "logging-type"} + , + {PROP_MEMBER_STATUS_FLAGS, "member-status-flags"} + , + {PROP_NOTIFICATION_PERIOD, "notification-period"} + , + {PROP_PREVIOUS_NOTIFY_RECORD, "previous-notify-record"} + , + {PROP_REQUESTED_UPDATE_INTERVAL, "requested-update-interval"} + , + {PROP_RESTART_NOTIFICATION_RECIPIENTS, + "restart-notification-recipients"} + , + {PROP_TIME_OF_DEVICE_RESTART, "time-of-device-restart"} + , + {PROP_TIME_SYNCHRONIZATION_INTERVAL, "time-synchronization-interval"} + , + {PROP_TRIGGER, "trigger"} + , + {PROP_UTC_TIME_SYNCHRONIZATION_RECIPIENTS, + "UTC-time-synchronization-recipients"} + , + {PROP_NODE_SUBTYPE, "node-subtype"} + , + {PROP_NODE_TYPE, "node-type"} + , + {PROP_STRUCTURED_OBJECT_LIST, "structured-object-list"} + , + {PROP_SUBORDINATE_ANNOTATIONS, "subordinate-annotations"} + , + {PROP_SUBORDINATE_LIST, "subordinate-list"} + , + {PROP_ACTUAL_SHED_LEVEL, "actual-shed-level"} + , + {PROP_DUTY_WINDOW, "duty-window"} + , + {PROP_EXPECTED_SHED_LEVEL, "expected-shed-level"} + , + {PROP_FULL_DUTY_BASELINE, "full-duty-baseline"} + , + {PROP_REQUESTED_SHED_LEVEL, "requested-shed-level"} + , + {PROP_SHED_DURATION, "shed-duration"} + , + {PROP_SHED_LEVEL_DESCRIPTIONS, "shed-level-descriptions"} + , + {PROP_SHED_LEVELS, "shed-levels"} + , + {PROP_STATE_DESCRIPTION, "state-descriptions"} + , {0, NULL} /* Enumerated values 0-511 are reserved for definition by ASHRAE. diff --git a/bacnet-stack/cov.c b/bacnet-stack/cov.c index 4ccbe59d..8aad9590 100644 --- a/bacnet-stack/cov.c +++ b/bacnet-stack/cov.c @@ -273,6 +273,7 @@ int cov_notify_decode_service_request(uint8_t * apdu, return len; } + /* 12.11.38Active_COV_Subscriptions The Active_COV_Subscriptions property is a List of BACnetCOVSubscription, each of which consists of a Recipient, a @@ -291,10 +292,8 @@ SubscribeCOV-Request ::= SEQUENCE { } */ -int cov_subscribe_encode_adpu( - uint8_t * apdu, - uint8_t invoke_id, - BACNET_SUBSCRIBE_COV_DATA * data) +int cov_subscribe_encode_adpu(uint8_t * apdu, + uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA * data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ @@ -317,10 +316,10 @@ int cov_subscribe_encode_adpu( data->monitoredObjectIdentifier.instance); apdu_len += len; /* - If both the 'Issue Confirmed Notifications' and - 'Lifetime' parameters are absent, then this shall - indicate a cancellation request. - */ + If both the 'Issue Confirmed Notifications' and + 'Lifetime' parameters are absent, then this shall + indicate a cancellation request. + */ if (!data->cancellationRequest) { /* tag 2 - issueConfirmedNotifications */ len = encode_context_boolean(&apdu[apdu_len], @@ -412,10 +411,8 @@ BACnetPropertyReference ::= SEQUENCE { */ -int cov_subscribe_property_encode_adpu( - uint8_t * apdu, - uint8_t invoke_id, - BACNET_SUBSCRIBE_COV_DATA * data) +int cov_subscribe_property_encode_adpu(uint8_t * apdu, + uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA * data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ @@ -455,7 +452,7 @@ int cov_subscribe_property_encode_adpu( apdu_len += len; if (data->monitoredProperty.propertyArrayIndex != BACNET_ARRAY_ALL) { len = encode_context_unsigned(&apdu[apdu_len], - 1, data->monitoredProperty.propertyArrayIndex); + 1, data->monitoredProperty.propertyArrayIndex); apdu_len += len; } @@ -549,7 +546,7 @@ int cov_subscribe_property_decode_service_request(uint8_t * apdu, } else { data->monitoredProperty.propertyArrayIndex = BACNET_ARRAY_ALL; } - + if (!decode_is_closing_tag_number(&apdu[len], 4)) return -5; /* a tag number of 4 is not extended so only one octet */ @@ -648,7 +645,8 @@ int ucov_notify_decode_apdu(uint8_t * apdu, } int cov_subscribe_decode_apdu(uint8_t * apdu, - unsigned apdu_len, uint8_t * invoke_id, BACNET_SUBSCRIBE_COV_DATA * data) + unsigned apdu_len, uint8_t * invoke_id, + BACNET_SUBSCRIBE_COV_DATA * data) { int len = 0; unsigned offset = 0; @@ -675,7 +673,8 @@ int cov_subscribe_decode_apdu(uint8_t * apdu, } int cov_subscribe_property_decode_apdu(uint8_t * apdu, - unsigned apdu_len, uint8_t * invoke_id, BACNET_SUBSCRIBE_COV_DATA * data) + unsigned apdu_len, uint8_t * invoke_id, + BACNET_SUBSCRIBE_COV_DATA * data) { int len = 0; unsigned offset = 0; @@ -716,12 +715,9 @@ void npdu_encode_npdu_data(BACNET_NPDU_DATA * npdu, } /* dummy function stubs */ -int datalink_send_pdu( - BACNET_ADDRESS * dest, - BACNET_NPDU_DATA * npdu_data, - uint8_t * pdu, - unsigned pdu_len) -{ +int datalink_send_pdu(BACNET_ADDRESS * dest, + BACNET_NPDU_DATA * npdu_data, uint8_t * pdu, unsigned pdu_len) +{ (void) dest; (void) npdu_data; (void) pdu; @@ -733,7 +729,7 @@ int datalink_send_pdu( /* dummy function stubs */ void datalink_get_broadcast_address(BACNET_ADDRESS * dest) { - (void)dest; + (void) dest; } /* dummy function stubs */ @@ -825,7 +821,8 @@ void testCOVNotify(Test * pTest) } void testCOVSubscribeData(Test * pTest, - BACNET_SUBSCRIBE_COV_DATA * data, BACNET_SUBSCRIBE_COV_DATA * test_data) + BACNET_SUBSCRIBE_COV_DATA * data, + BACNET_SUBSCRIBE_COV_DATA * test_data) { ct_test(pTest, test_data->subscriberProcessIdentifier == @@ -836,20 +833,29 @@ void testCOVSubscribeData(Test * pTest, ct_test(pTest, test_data->monitoredObjectIdentifier.instance == data->monitoredObjectIdentifier.instance); - ct_test(pTest, test_data->cancellationRequest == data->cancellationRequest); + ct_test(pTest, + test_data->cancellationRequest == data->cancellationRequest); if (!test_data->cancellationRequest) { - ct_test(pTest, test_data->issueConfirmedNotifications == data->issueConfirmedNotifications); + ct_test(pTest, + test_data->issueConfirmedNotifications == + data->issueConfirmedNotifications); ct_test(pTest, test_data->lifetime == data->lifetime); } } void testCOVSubscribePropertyData(Test * pTest, - BACNET_SUBSCRIBE_COV_DATA * data, BACNET_SUBSCRIBE_COV_DATA * test_data) + BACNET_SUBSCRIBE_COV_DATA * data, + BACNET_SUBSCRIBE_COV_DATA * test_data) { testCOVSubscribeData(pTest, data, test_data); - ct_test(pTest, test_data->monitoredProperty.propertyIdentifier == data->monitoredProperty.propertyIdentifier); - ct_test(pTest, test_data->monitoredProperty.propertyArrayIndex == data->monitoredProperty.propertyArrayIndex); - ct_test(pTest, test_data->covIncrementPresent == data->covIncrementPresent); + ct_test(pTest, + test_data->monitoredProperty.propertyIdentifier == + data->monitoredProperty.propertyIdentifier); + ct_test(pTest, + test_data->monitoredProperty.propertyArrayIndex == + data->monitoredProperty.propertyArrayIndex); + ct_test(pTest, + test_data->covIncrementPresent == data->covIncrementPresent); if (test_data->covIncrementPresent) { ct_test(pTest, test_data->covIncrement == data->covIncrement); } diff --git a/bacnet-stack/cov.h b/bacnet-stack/cov.h index 281a0044..f70e3372 100644 --- a/bacnet-stack/cov.h +++ b/bacnet-stack/cov.h @@ -58,19 +58,19 @@ typedef struct BACnet_COV_Data { } BACNET_COV_DATA; typedef struct BACnet_Property_Reference { - BACNET_PROPERTY_ID propertyIdentifier; - unsigned propertyArrayIndex; /* optional */ + BACNET_PROPERTY_ID propertyIdentifier; + unsigned propertyArrayIndex; /* optional */ } BACNET_PROPERTY_REFERENCE; typedef struct BACnet_Subscribe_COV_Data { uint32_t subscriberProcessIdentifier; BACNET_OBJECT_ID monitoredObjectIdentifier; - bool cancellationRequest; /* true if this is a cancellation request */ - bool issueConfirmedNotifications; /* optional */ - unsigned lifetime; /* optional */ + bool cancellationRequest; /* true if this is a cancellation request */ + bool issueConfirmedNotifications; /* optional */ + unsigned lifetime; /* optional */ BACNET_PROPERTY_REFERENCE monitoredProperty; - bool covIncrementPresent; /* true if present */ - float covIncrement; /* optional */ + bool covIncrementPresent; /* true if present */ + float covIncrement; /* optional */ } BACNET_SUBSCRIBE_COV_DATA; #ifdef __cplusplus @@ -97,18 +97,14 @@ extern "C" { int cov_subscribe_property_decode_service_request(uint8_t * apdu, unsigned apdu_len, BACNET_SUBSCRIBE_COV_DATA * data); - int cov_subscribe_property_encode_adpu( - uint8_t * apdu, - uint8_t invoke_id, - BACNET_SUBSCRIBE_COV_DATA * data); + int cov_subscribe_property_encode_adpu(uint8_t * apdu, + uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA * data); int cov_subscribe_decode_service_request(uint8_t * apdu, unsigned apdu_len, BACNET_SUBSCRIBE_COV_DATA * data); - int cov_subscribe_encode_adpu( - uint8_t * apdu, - uint8_t invoke_id, - BACNET_SUBSCRIBE_COV_DATA * data); + int cov_subscribe_encode_adpu(uint8_t * apdu, + uint8_t invoke_id, BACNET_SUBSCRIBE_COV_DATA * data); #ifdef TEST diff --git a/bacnet-stack/datalink.h b/bacnet-stack/datalink.h index 7515a19c..7ce29f1f 100644 --- a/bacnet-stack/datalink.h +++ b/bacnet-stack/datalink.h @@ -73,19 +73,13 @@ #elif defined(BACDL_TEST) #include "npdu.h" - extern int datalink_send_pdu( - BACNET_ADDRESS * dest, - BACNET_NPDU_DATA * npdu_data, - uint8_t * pdu, - unsigned pdu_len); - extern uint16_t datalink_receive( - BACNET_ADDRESS * src, - uint8_t * pdu, - uint16_t max_pdu, - unsigned timeout); - extern void datalink_cleanup(void); - extern void datalink_get_broadcast_address(BACNET_ADDRESS * dest); - extern void bip_get_my_address(BACNET_ADDRESS * my_address); +extern int datalink_send_pdu(BACNET_ADDRESS * dest, + BACNET_NPDU_DATA * npdu_data, uint8_t * pdu, unsigned pdu_len); +extern uint16_t datalink_receive(BACNET_ADDRESS * src, + uint8_t * pdu, uint16_t max_pdu, unsigned timeout); +extern void datalink_cleanup(void); +extern void datalink_get_broadcast_address(BACNET_ADDRESS * dest); +extern void bip_get_my_address(BACNET_ADDRESS * my_address); #endif diff --git a/bacnet-stack/datetime.c b/bacnet-stack/datetime.c index 9d23448e..a324b57b 100644 --- a/bacnet-stack/datetime.c +++ b/bacnet-stack/datetime.c @@ -1,675 +1,655 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2007 Steve Karg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ -#include -#include -#include -#include -#include -#include -#include "datetime.h" - -/* BACnet Date */ -/* year = years since 1900 */ -/* month 1=Jan */ -/* day = day of month 1..31 */ -/* wday 1=Monday...7=Sunday */ - -static bool is_leap_year(uint16_t year) -{ - if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) - return (true); - else - return (false); -} - -static uint8_t month_days(uint16_t year, uint8_t month) -{ - /* note: start with a zero in the first element to save us from a - month - 1 calculation in the lookup */ - int month_days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - - /* February */ - if ((month == 2) && is_leap_year(year)) - return 29; - else if (month >= 1 && month <= 12) - return month_days[month]; - else - return 0; -} - -static uint32_t days_since_epoch(uint16_t year, uint8_t month, uint8_t day) -{ - uint32_t days = 0; /* return value */ - uint8_t monthdays; /* days in a month */ - uint16_t years = 0; /* loop counter for years */ - uint8_t months = 0; /* loop counter for months */ - - monthdays = month_days(year, month); - if ((year >= 1900) && (monthdays) && - (day >= 1) && (day <= monthdays)) - { - for (years = 1900; years < year; years++) - { - days += 365; - if (is_leap_year(years)) - days++; - } - for (months = 1; months < month; months++) - { - days += month_days(years, months); - } - days += (day - 1); - } - - return (days); -} - -static void days_since_epoch_into_ymd( - uint32_t days, - uint16_t *pYear, - uint8_t *pMonth, - uint8_t *pDay) -{ - int year = 1900; - int month = 1; - int day = 1; - - while (days >= 365) - { - if ((is_leap_year(year)) && days == 365) - break; - days -= 365; - if (is_leap_year(year)) - --days; - year++; - } - - while (days >= month_days(year, month)) - { - days -= month_days(year, month); - month++; - } - - day += days; - - if (pYear) - *pYear = year; - if (pMonth) - *pMonth = month; - if (pDay) - *pDay = day; - - return; -} - - -/* Jan 1, 1900 is a Monday */ -/* wday 1=Monday...7=Sunday */ -static uint8_t day_of_week(uint16_t year, uint8_t month, uint8_t day) -{ - return ((days_since_epoch(year, month, day)%7)+1); -} - -/* if the date1 is the same as date2, return is 0 - if date1 is after date2, returns positive - if date1 is before date2, returns negative */ -int datetime_compare_date(BACNET_DATE * date1, BACNET_DATE * date2) -{ - int diff = 0; - - if (date1 && date2) { - diff = (int)date1->year - (int)date2->year; - if (diff == 0) { - diff = (int)date1->month - (int)date2->month; - if (diff == 0) { - diff = (int)date1->day - (int)date2->day; - } - } - } - - return diff; -} - -/* if the time1 is the same as time2, return is 0 - if time1 is after time2, returns positive - if time1 is before time2, returns negative */ -int datetime_compare_time(BACNET_TIME * time1, BACNET_TIME * time2) -{ - int diff = 0; - - if (time1 && time2) { - diff = (int)time1->hour - (int)time2->hour; - if (diff == 0) { - diff = (int)time1->min - (int)time2->min; - if (diff == 0) { - diff = (int)time1->sec - (int)time2->sec; - if (diff == 0) { - diff = (int)time1->hundredths - (int)time2->hundredths; - } - } - } - } - - return diff; -} - -/* if the datetime1 is the same as datetime2, return is 0 - if datetime1 is before datetime2, returns negative - if datetime1 is after datetime2, returns positive */ -int datetime_compare(BACNET_DATE_TIME * datetime1, - BACNET_DATE_TIME * datetime2) -{ - int diff = 0; - - diff = datetime_compare_date(&datetime1->date,&datetime2->date); - if (diff == 0) { - diff = datetime_compare_time(&datetime1->time,&datetime2->time); - } - - return diff; -} - -void datetime_copy_date(BACNET_DATE * dest_date, BACNET_DATE * src_date) -{ - if (dest_date && src_date) { - dest_date->year = src_date->year; - dest_date->month = src_date->month; - dest_date->day = src_date->day; - dest_date->wday = src_date->wday; - } -} - -void datetime_copy_time(BACNET_TIME * dest_time, BACNET_TIME * src_time) -{ - if (dest_time && src_time) { - dest_time->hour = src_time->hour; - dest_time->min = src_time->min; - dest_time->sec = src_time->sec; - dest_time->hundredths = src_time->hundredths; - } -} - -void datetime_copy( - BACNET_DATE_TIME * dest_datetime, - BACNET_DATE_TIME * src_datetime) -{ - datetime_copy_time(&dest_datetime->time,&src_datetime->time); - datetime_copy_date(&dest_datetime->date,&src_datetime->date); -} - -void datetime_set_date(BACNET_DATE * bdate, - uint16_t year, uint8_t month, uint8_t day) -{ - if (bdate) { - bdate->year = year; - bdate->month = month; - bdate->day = day; - bdate->wday = day_of_week(year,month,day); - } -} - -void datetime_set_time(BACNET_TIME * btime, - uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths) -{ - if (btime) { - btime->hour = hour; - btime->min = minute; - btime->sec = seconds; - btime->hundredths = hundredths; - } -} - -void datetime_set(BACNET_DATE_TIME * bdatetime, - BACNET_DATE * bdate, - BACNET_TIME * btime) -{ - if (bdate && btime && bdatetime) { - bdatetime->time.hour = btime->hour; - bdatetime->time.min = btime->min; - bdatetime->time.sec = btime->sec; - bdatetime->time.hundredths = btime->hundredths; - bdatetime->date.year = bdate->year; - bdatetime->date.month = bdate->month; - bdatetime->date.day = bdate->day; - bdatetime->date.wday = bdate->wday; - } -} - -void datetime_set_values(BACNET_DATE_TIME * bdatetime, - uint16_t year, uint8_t month, uint8_t day, - uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths) -{ - if (bdatetime) { - bdatetime->date.year = year; - bdatetime->date.month = month; - bdatetime->date.day = day; - bdatetime->date.wday = day_of_week(year,month,day); - bdatetime->time.hour = hour; - bdatetime->time.min = minute; - bdatetime->time.sec = seconds; - bdatetime->time.hundredths = hundredths; - } -} - -static uint32_t seconds_since_midnight(uint8_t hours, uint8_t minutes, - uint8_t seconds) -{ - return ((hours * 60 * 60) + (minutes * 60) + seconds); -} - -static void seconds_since_midnight_into_hms(uint32_t seconds, - uint8_t * pHours, - uint8_t *pMinutes, - uint8_t *pSeconds) -{ - uint8_t hour = 0; - uint8_t minute = 0; - - hour = seconds / (60 * 60); - seconds -= (hour * 60 * 60); - minute = seconds / 60; - seconds -= (minute * 60); - - if (pHours) - *pHours = hour; - if (pMinutes) - *pMinutes = minute; - if (pSeconds) - *pSeconds = seconds; -} - -void datetime_add_minutes(BACNET_DATE_TIME * bdatetime, uint32_t minutes) -{ - uint32_t bdatetime_minutes = 0; - uint32_t bdatetime_days = 0; - uint32_t days = 0; - - /* convert bdatetime to seconds and days */ - bdatetime_minutes = seconds_since_midnight( - bdatetime->time.hour, - bdatetime->time.min, - bdatetime->time.sec) / 60; - bdatetime_days = days_since_epoch( - bdatetime->date.year, - bdatetime->date.month, - bdatetime->date.day); - - /* add */ - days = minutes / (24*60); - bdatetime_days += days; - minutes -= (days * 24 * 60); - bdatetime_minutes += minutes; - days = bdatetime_minutes / (24*60); - bdatetime_days += days; - - /* convert bdatetime from seconds and days */ - seconds_since_midnight_into_hms(bdatetime_minutes * 60, - &bdatetime->time.hour, - &bdatetime->time.min, - &bdatetime->time.sec); - days_since_epoch_into_ymd( - bdatetime_days, - &bdatetime->date.year, - &bdatetime->date.month, - &bdatetime->date.day); - bdatetime->date.wday = day_of_week( - bdatetime->date.year, - bdatetime->date.month, - bdatetime->date.day); -} - -#ifdef TEST -#include -#include -#include "ctest.h" - -void testBACnetDateTimeAdd(Test * pTest) -{ - BACNET_DATE_TIME bdatetime, test_bdatetime; - uint32_t minutes = 0; - int diff = 0; - - datetime_set_values(&bdatetime, 1900,1,1,0,0,0,0); - datetime_copy(&test_bdatetime,&bdatetime); - datetime_add_minutes(&bdatetime, minutes); - diff = datetime_compare(&test_bdatetime, &bdatetime); - ct_test(pTest, diff == 0); - - datetime_set_values(&bdatetime, 1900,1,1,0,0,0,0); - datetime_add_minutes(&bdatetime, 60); - datetime_set_values(&test_bdatetime, 1900,1,1,1,0,0,0); - diff = datetime_compare(&test_bdatetime, &bdatetime); - ct_test(pTest, diff == 0); - - datetime_set_values(&bdatetime, 1900,1,1,0,0,0,0); - datetime_add_minutes(&bdatetime, (24*60)); - datetime_set_values(&test_bdatetime, 1900,1,2,0,0,0,0); - diff = datetime_compare(&test_bdatetime, &bdatetime); - ct_test(pTest, diff == 0); - - datetime_set_values(&bdatetime, 1900,1,1,0,0,0,0); - datetime_add_minutes(&bdatetime, (31*24*60)); - datetime_set_values(&test_bdatetime, 1900,2,1,0,0,0,0); - diff = datetime_compare(&test_bdatetime, &bdatetime); - ct_test(pTest, diff == 0); -} - - - -void testBACnetDateTimeSeconds(Test * pTest) -{ - uint8_t hour = 0, minute = 0, second = 0; - uint8_t test_hour = 0, test_minute = 0, test_second = 0; - uint32_t seconds = 0, test_seconds; - - for (hour = 0; hour < 24; hour++) { - for (minute = 0; minute < 60; minute+=3) { - for (second = 0; second < 60; second+=17) { - seconds = seconds_since_midnight(hour, minute, second); - seconds_since_midnight_into_hms(seconds, - &test_hour, &test_minute, &test_second); - test_seconds = seconds_since_midnight( - test_hour, test_minute, test_second); - ct_test(pTest, seconds == test_seconds); - } - } - } -} - -void testBACnetDate(Test * pTest) -{ - BACNET_DATE bdate1, bdate2; - int diff = 0; - - datetime_set_date(&bdate1, 1900,1,1); - datetime_copy_date(&bdate2, &bdate1); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff == 0); - datetime_set_date(&bdate2, 1900,1,2); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff < 0); - datetime_set_date(&bdate2, 1900,2,1); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff < 0); - datetime_set_date(&bdate2, 1901,1,1); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff < 0); - - /* midpoint */ - datetime_set_date(&bdate1, 2007,7,15); - datetime_copy_date(&bdate2, &bdate1); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff == 0); - datetime_set_date(&bdate2, 2007,7,14); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff > 0); - datetime_set_date(&bdate2, 2007,7,1); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff > 0); - datetime_set_date(&bdate2, 2007,7,31); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff < 0); - datetime_set_date(&bdate2, 2007,8,15); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff < 0); - datetime_set_date(&bdate2, 2007,12,15); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff < 0); - datetime_set_date(&bdate2, 2007,6,15); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff > 0); - datetime_set_date(&bdate2, 2007,1,15); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff > 0); - datetime_set_date(&bdate2, 2006,7,15); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff > 0); - datetime_set_date(&bdate2, 1900,7,15); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff > 0); - datetime_set_date(&bdate2, 2008,7,15); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff < 0); - datetime_set_date(&bdate2, 2154,7,15); - diff = datetime_compare_date(&bdate1, &bdate2); - ct_test(pTest, diff < 0); - - return; -} - -void testBACnetTime(Test * pTest) -{ - BACNET_TIME btime1, btime2; - int diff = 0; - - datetime_set_time(&btime1, 0,0,0,0); - datetime_copy_time(&btime2, &btime1); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff == 0); - - datetime_set_time(&btime1, 23,59,59,99); - datetime_copy_time(&btime2, &btime1); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff == 0); - - /* midpoint */ - datetime_set_time(&btime1, 12,30,30,50); - datetime_copy_time(&btime2, &btime1); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff == 0); - datetime_set_time(&btime2, 12,30,30,51); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff < 0); - datetime_set_time(&btime2, 12,30,31,50); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff < 0); - datetime_set_time(&btime2, 12,31,30,50); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff < 0); - datetime_set_time(&btime2, 13,30,30,50); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff < 0); - - datetime_set_time(&btime2, 12,30,30,49); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff > 0); - datetime_set_time(&btime2, 12,30,29,50); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff > 0); - datetime_set_time(&btime2, 12,29,30,50); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff > 0); - datetime_set_time(&btime2, 11,30,30,50); - diff = datetime_compare_time(&btime1, &btime2); - ct_test(pTest, diff > 0); - - return; -} - -void testBACnetDateTime(Test * pTest) -{ - BACNET_DATE_TIME bdatetime1, bdatetime2; - BACNET_DATE bdate; - BACNET_TIME btime; - int diff = 0; - - datetime_set_values(&bdatetime1, 1900,1,1,0,0,0,0); - datetime_copy(&bdatetime2, &bdatetime1); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff == 0); - datetime_set_time(&btime, 0,0,0,0); - datetime_set_date(&bdate, 1900,1,1); - datetime_set(&bdatetime1, &bdate, &btime); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff == 0); - - /* midpoint */ - /* if datetime1 is before datetime2, returns negative */ - datetime_set_values(&bdatetime1, 2000,7,15,12,30,30,50); - datetime_set_values(&bdatetime2, 2000,7,15,12,30,30,51); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff < 0); - datetime_set_values(&bdatetime2, 2000,7,15,12,30,31,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff < 0); - datetime_set_values(&bdatetime2, 2000,7,15,12,31,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff < 0); - datetime_set_values(&bdatetime2, 2000,7,15,13,30,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff < 0); - datetime_set_values(&bdatetime2, 2000,7,16,12,30,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff < 0); - datetime_set_values(&bdatetime2, 2000,8,15,12,30,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff < 0); - datetime_set_values(&bdatetime2, 2001,7,15,12,30,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff < 0); - datetime_set_values(&bdatetime2, 2000,7,15,12,30,30,49); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff > 0); - datetime_set_values(&bdatetime2, 2000,7,15,12,30,29,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff > 0); - datetime_set_values(&bdatetime2, 2000,7,15,12,29,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff > 0); - datetime_set_values(&bdatetime2, 2000,7,15,11,30,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff > 0); - datetime_set_values(&bdatetime2, 2000,7,14,12,30,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff > 0); - datetime_set_values(&bdatetime2, 2000,6,15,12,30,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff > 0); - datetime_set_values(&bdatetime2, 1999,7,15,12,30,30,50); - diff = datetime_compare(&bdatetime1, &bdatetime2); - ct_test(pTest, diff > 0); - - - return; -} - -void testDateEpoch(Test * pTest) -{ - uint32_t days = 0; - uint16_t year = 0, test_year = 0; - uint8_t month = 0, test_month = 0; - uint8_t day = 0, test_day = 0; - - days = days_since_epoch(1900,1,1); - ct_test(pTest, days == 0); - days_since_epoch_into_ymd(days, &year, &month, &day); - ct_test(pTest, year == 1900); - ct_test(pTest, month == 1); - ct_test(pTest, day == 1); - - - for (year = 1900; year <= 2154; year++) { - for (month = 1; month <= 12; month++) { - for (day = 1; day <= month_days(year, month); day++) { - days = days_since_epoch(year, month, day); - days_since_epoch_into_ymd(days, - &test_year, &test_month, &test_day); - ct_test(pTest, year == test_year); - ct_test(pTest, month == test_month); - ct_test(pTest, day == test_day); - } - } - } -} - -void testBACnetDayOfWeek(Test * pTest) -{ - uint8_t dow = 0; - - /* 1/1/1900 is a Monday */ - dow = day_of_week(1900, 1, 1); - ct_test(pTest, dow == 1); - - /* 1/1/2007 is a Monday */ - dow = day_of_week(2007, 1, 1); - ct_test(pTest, dow == 1); - dow = day_of_week(2007, 1, 2); - ct_test(pTest, dow == 2); - dow = day_of_week(2007, 1, 3); - ct_test(pTest, dow == 3); - dow = day_of_week(2007, 1, 4); - ct_test(pTest, dow == 4); - dow = day_of_week(2007, 1, 5); - ct_test(pTest, dow == 5); - dow = day_of_week(2007, 1, 6); - ct_test(pTest, dow == 6); - dow = day_of_week(2007, 1, 7); - ct_test(pTest, dow == 7); - - dow = day_of_week(2007, 1, 31); - ct_test(pTest, dow == 3); -} - -#ifdef TEST_DATE_TIME -int main(void) -{ - Test *pTest; - bool rc; - - pTest = ct_create("BACnet Date Time", NULL); - /* individual tests */ - rc = ct_addTestFunction(pTest, testBACnetDate); - assert(rc); - rc = ct_addTestFunction(pTest, testBACnetTime); - assert(rc); - rc = ct_addTestFunction(pTest, testBACnetDateTime); - assert(rc); - rc = ct_addTestFunction(pTest, testBACnetDayOfWeek); - assert(rc); - rc = ct_addTestFunction(pTest, testDateEpoch); - assert(rc); - rc = ct_addTestFunction(pTest, testBACnetDateTimeSeconds); - assert(rc); - rc = ct_addTestFunction(pTest, testBACnetDateTimeAdd); - assert(rc); - - ct_setStream(pTest, stdout); - ct_run(pTest); - (void) ct_report(pTest); - ct_destroy(pTest); - - return 0; -} -#endif /* TEST_DATE_TIME */ -#endif /* TEST */ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2007 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ +#include +#include +#include +#include +#include +#include +#include "datetime.h" + +/* BACnet Date */ +/* year = years since 1900 */ +/* month 1=Jan */ +/* day = day of month 1..31 */ +/* wday 1=Monday...7=Sunday */ + +static bool is_leap_year(uint16_t year) +{ + if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) + return (true); + else + return (false); +} + +static uint8_t month_days(uint16_t year, uint8_t month) +{ + /* note: start with a zero in the first element to save us from a + month - 1 calculation in the lookup */ + int month_days[13] = + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + /* February */ + if ((month == 2) && is_leap_year(year)) + return 29; + else if (month >= 1 && month <= 12) + return month_days[month]; + else + return 0; +} + +static uint32_t days_since_epoch(uint16_t year, uint8_t month, uint8_t day) +{ + uint32_t days = 0; /* return value */ + uint8_t monthdays; /* days in a month */ + uint16_t years = 0; /* loop counter for years */ + uint8_t months = 0; /* loop counter for months */ + + monthdays = month_days(year, month); + if ((year >= 1900) && (monthdays) && (day >= 1) && (day <= monthdays)) { + for (years = 1900; years < year; years++) { + days += 365; + if (is_leap_year(years)) + days++; + } + for (months = 1; months < month; months++) { + days += month_days(years, months); + } + days += (day - 1); + } + + return (days); +} + +static void days_since_epoch_into_ymd(uint32_t days, + uint16_t * pYear, uint8_t * pMonth, uint8_t * pDay) +{ + int year = 1900; + int month = 1; + int day = 1; + + while (days >= 365) { + if ((is_leap_year(year)) && days == 365) + break; + days -= 365; + if (is_leap_year(year)) + --days; + year++; + } + + while (days >= month_days(year, month)) { + days -= month_days(year, month); + month++; + } + + day += days; + + if (pYear) + *pYear = year; + if (pMonth) + *pMonth = month; + if (pDay) + *pDay = day; + + return; +} + + +/* Jan 1, 1900 is a Monday */ +/* wday 1=Monday...7=Sunday */ +static uint8_t day_of_week(uint16_t year, uint8_t month, uint8_t day) +{ + return ((days_since_epoch(year, month, day) % 7) + 1); +} + +/* if the date1 is the same as date2, return is 0 + if date1 is after date2, returns positive + if date1 is before date2, returns negative */ +int datetime_compare_date(BACNET_DATE * date1, BACNET_DATE * date2) +{ + int diff = 0; + + if (date1 && date2) { + diff = (int) date1->year - (int) date2->year; + if (diff == 0) { + diff = (int) date1->month - (int) date2->month; + if (diff == 0) { + diff = (int) date1->day - (int) date2->day; + } + } + } + + return diff; +} + +/* if the time1 is the same as time2, return is 0 + if time1 is after time2, returns positive + if time1 is before time2, returns negative */ +int datetime_compare_time(BACNET_TIME * time1, BACNET_TIME * time2) +{ + int diff = 0; + + if (time1 && time2) { + diff = (int) time1->hour - (int) time2->hour; + if (diff == 0) { + diff = (int) time1->min - (int) time2->min; + if (diff == 0) { + diff = (int) time1->sec - (int) time2->sec; + if (diff == 0) { + diff = + (int) time1->hundredths - (int) time2->hundredths; + } + } + } + } + + return diff; +} + +/* if the datetime1 is the same as datetime2, return is 0 + if datetime1 is before datetime2, returns negative + if datetime1 is after datetime2, returns positive */ +int datetime_compare(BACNET_DATE_TIME * datetime1, + BACNET_DATE_TIME * datetime2) +{ + int diff = 0; + + diff = datetime_compare_date(&datetime1->date, &datetime2->date); + if (diff == 0) { + diff = datetime_compare_time(&datetime1->time, &datetime2->time); + } + + return diff; +} + +void datetime_copy_date(BACNET_DATE * dest_date, BACNET_DATE * src_date) +{ + if (dest_date && src_date) { + dest_date->year = src_date->year; + dest_date->month = src_date->month; + dest_date->day = src_date->day; + dest_date->wday = src_date->wday; + } +} + +void datetime_copy_time(BACNET_TIME * dest_time, BACNET_TIME * src_time) +{ + if (dest_time && src_time) { + dest_time->hour = src_time->hour; + dest_time->min = src_time->min; + dest_time->sec = src_time->sec; + dest_time->hundredths = src_time->hundredths; + } +} + +void datetime_copy(BACNET_DATE_TIME * dest_datetime, + BACNET_DATE_TIME * src_datetime) +{ + datetime_copy_time(&dest_datetime->time, &src_datetime->time); + datetime_copy_date(&dest_datetime->date, &src_datetime->date); +} + +void datetime_set_date(BACNET_DATE * bdate, + uint16_t year, uint8_t month, uint8_t day) +{ + if (bdate) { + bdate->year = year; + bdate->month = month; + bdate->day = day; + bdate->wday = day_of_week(year, month, day); + } +} + +void datetime_set_time(BACNET_TIME * btime, + uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths) +{ + if (btime) { + btime->hour = hour; + btime->min = minute; + btime->sec = seconds; + btime->hundredths = hundredths; + } +} + +void datetime_set(BACNET_DATE_TIME * bdatetime, + BACNET_DATE * bdate, BACNET_TIME * btime) +{ + if (bdate && btime && bdatetime) { + bdatetime->time.hour = btime->hour; + bdatetime->time.min = btime->min; + bdatetime->time.sec = btime->sec; + bdatetime->time.hundredths = btime->hundredths; + bdatetime->date.year = bdate->year; + bdatetime->date.month = bdate->month; + bdatetime->date.day = bdate->day; + bdatetime->date.wday = bdate->wday; + } +} + +void datetime_set_values(BACNET_DATE_TIME * bdatetime, + uint16_t year, uint8_t month, uint8_t day, + uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths) +{ + if (bdatetime) { + bdatetime->date.year = year; + bdatetime->date.month = month; + bdatetime->date.day = day; + bdatetime->date.wday = day_of_week(year, month, day); + bdatetime->time.hour = hour; + bdatetime->time.min = minute; + bdatetime->time.sec = seconds; + bdatetime->time.hundredths = hundredths; + } +} + +static uint32_t seconds_since_midnight(uint8_t hours, uint8_t minutes, + uint8_t seconds) +{ + return ((hours * 60 * 60) + (minutes * 60) + seconds); +} + +static void seconds_since_midnight_into_hms(uint32_t seconds, + uint8_t * pHours, uint8_t * pMinutes, uint8_t * pSeconds) +{ + uint8_t hour = 0; + uint8_t minute = 0; + + hour = seconds / (60 * 60); + seconds -= (hour * 60 * 60); + minute = seconds / 60; + seconds -= (minute * 60); + + if (pHours) + *pHours = hour; + if (pMinutes) + *pMinutes = minute; + if (pSeconds) + *pSeconds = seconds; +} + +void datetime_add_minutes(BACNET_DATE_TIME * bdatetime, uint32_t minutes) +{ + uint32_t bdatetime_minutes = 0; + uint32_t bdatetime_days = 0; + uint32_t days = 0; + + /* convert bdatetime to seconds and days */ + bdatetime_minutes = seconds_since_midnight(bdatetime->time.hour, + bdatetime->time.min, bdatetime->time.sec) / 60; + bdatetime_days = days_since_epoch(bdatetime->date.year, + bdatetime->date.month, bdatetime->date.day); + + /* add */ + days = minutes / (24 * 60); + bdatetime_days += days; + minutes -= (days * 24 * 60); + bdatetime_minutes += minutes; + days = bdatetime_minutes / (24 * 60); + bdatetime_days += days; + + /* convert bdatetime from seconds and days */ + seconds_since_midnight_into_hms(bdatetime_minutes * 60, + &bdatetime->time.hour, &bdatetime->time.min, &bdatetime->time.sec); + days_since_epoch_into_ymd(bdatetime_days, + &bdatetime->date.year, + &bdatetime->date.month, &bdatetime->date.day); + bdatetime->date.wday = day_of_week(bdatetime->date.year, + bdatetime->date.month, bdatetime->date.day); +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +void testBACnetDateTimeAdd(Test * pTest) +{ + BACNET_DATE_TIME bdatetime, test_bdatetime; + uint32_t minutes = 0; + int diff = 0; + + datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0); + datetime_copy(&test_bdatetime, &bdatetime); + datetime_add_minutes(&bdatetime, minutes); + diff = datetime_compare(&test_bdatetime, &bdatetime); + ct_test(pTest, diff == 0); + + datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0); + datetime_add_minutes(&bdatetime, 60); + datetime_set_values(&test_bdatetime, 1900, 1, 1, 1, 0, 0, 0); + diff = datetime_compare(&test_bdatetime, &bdatetime); + ct_test(pTest, diff == 0); + + datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0); + datetime_add_minutes(&bdatetime, (24 * 60)); + datetime_set_values(&test_bdatetime, 1900, 1, 2, 0, 0, 0, 0); + diff = datetime_compare(&test_bdatetime, &bdatetime); + ct_test(pTest, diff == 0); + + datetime_set_values(&bdatetime, 1900, 1, 1, 0, 0, 0, 0); + datetime_add_minutes(&bdatetime, (31 * 24 * 60)); + datetime_set_values(&test_bdatetime, 1900, 2, 1, 0, 0, 0, 0); + diff = datetime_compare(&test_bdatetime, &bdatetime); + ct_test(pTest, diff == 0); +} + + + +void testBACnetDateTimeSeconds(Test * pTest) +{ + uint8_t hour = 0, minute = 0, second = 0; + uint8_t test_hour = 0, test_minute = 0, test_second = 0; + uint32_t seconds = 0, test_seconds; + + for (hour = 0; hour < 24; hour++) { + for (minute = 0; minute < 60; minute += 3) { + for (second = 0; second < 60; second += 17) { + seconds = seconds_since_midnight(hour, minute, second); + seconds_since_midnight_into_hms(seconds, + &test_hour, &test_minute, &test_second); + test_seconds = + seconds_since_midnight(test_hour, test_minute, + test_second); + ct_test(pTest, seconds == test_seconds); + } + } + } +} + +void testBACnetDate(Test * pTest) +{ + BACNET_DATE bdate1, bdate2; + int diff = 0; + + datetime_set_date(&bdate1, 1900, 1, 1); + datetime_copy_date(&bdate2, &bdate1); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff == 0); + datetime_set_date(&bdate2, 1900, 1, 2); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff < 0); + datetime_set_date(&bdate2, 1900, 2, 1); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff < 0); + datetime_set_date(&bdate2, 1901, 1, 1); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff < 0); + + /* midpoint */ + datetime_set_date(&bdate1, 2007, 7, 15); + datetime_copy_date(&bdate2, &bdate1); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff == 0); + datetime_set_date(&bdate2, 2007, 7, 14); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff > 0); + datetime_set_date(&bdate2, 2007, 7, 1); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff > 0); + datetime_set_date(&bdate2, 2007, 7, 31); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff < 0); + datetime_set_date(&bdate2, 2007, 8, 15); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff < 0); + datetime_set_date(&bdate2, 2007, 12, 15); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff < 0); + datetime_set_date(&bdate2, 2007, 6, 15); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff > 0); + datetime_set_date(&bdate2, 2007, 1, 15); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff > 0); + datetime_set_date(&bdate2, 2006, 7, 15); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff > 0); + datetime_set_date(&bdate2, 1900, 7, 15); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff > 0); + datetime_set_date(&bdate2, 2008, 7, 15); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff < 0); + datetime_set_date(&bdate2, 2154, 7, 15); + diff = datetime_compare_date(&bdate1, &bdate2); + ct_test(pTest, diff < 0); + + return; +} + +void testBACnetTime(Test * pTest) +{ + BACNET_TIME btime1, btime2; + int diff = 0; + + datetime_set_time(&btime1, 0, 0, 0, 0); + datetime_copy_time(&btime2, &btime1); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff == 0); + + datetime_set_time(&btime1, 23, 59, 59, 99); + datetime_copy_time(&btime2, &btime1); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff == 0); + + /* midpoint */ + datetime_set_time(&btime1, 12, 30, 30, 50); + datetime_copy_time(&btime2, &btime1); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff == 0); + datetime_set_time(&btime2, 12, 30, 30, 51); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff < 0); + datetime_set_time(&btime2, 12, 30, 31, 50); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff < 0); + datetime_set_time(&btime2, 12, 31, 30, 50); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff < 0); + datetime_set_time(&btime2, 13, 30, 30, 50); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff < 0); + + datetime_set_time(&btime2, 12, 30, 30, 49); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff > 0); + datetime_set_time(&btime2, 12, 30, 29, 50); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff > 0); + datetime_set_time(&btime2, 12, 29, 30, 50); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff > 0); + datetime_set_time(&btime2, 11, 30, 30, 50); + diff = datetime_compare_time(&btime1, &btime2); + ct_test(pTest, diff > 0); + + return; +} + +void testBACnetDateTime(Test * pTest) +{ + BACNET_DATE_TIME bdatetime1, bdatetime2; + BACNET_DATE bdate; + BACNET_TIME btime; + int diff = 0; + + datetime_set_values(&bdatetime1, 1900, 1, 1, 0, 0, 0, 0); + datetime_copy(&bdatetime2, &bdatetime1); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff == 0); + datetime_set_time(&btime, 0, 0, 0, 0); + datetime_set_date(&bdate, 1900, 1, 1); + datetime_set(&bdatetime1, &bdate, &btime); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff == 0); + + /* midpoint */ + /* if datetime1 is before datetime2, returns negative */ + datetime_set_values(&bdatetime1, 2000, 7, 15, 12, 30, 30, 50); + datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 30, 30, 51); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff < 0); + datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 30, 31, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff < 0); + datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 31, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff < 0); + datetime_set_values(&bdatetime2, 2000, 7, 15, 13, 30, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff < 0); + datetime_set_values(&bdatetime2, 2000, 7, 16, 12, 30, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff < 0); + datetime_set_values(&bdatetime2, 2000, 8, 15, 12, 30, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff < 0); + datetime_set_values(&bdatetime2, 2001, 7, 15, 12, 30, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff < 0); + datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 30, 30, 49); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff > 0); + datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 30, 29, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff > 0); + datetime_set_values(&bdatetime2, 2000, 7, 15, 12, 29, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff > 0); + datetime_set_values(&bdatetime2, 2000, 7, 15, 11, 30, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff > 0); + datetime_set_values(&bdatetime2, 2000, 7, 14, 12, 30, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff > 0); + datetime_set_values(&bdatetime2, 2000, 6, 15, 12, 30, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff > 0); + datetime_set_values(&bdatetime2, 1999, 7, 15, 12, 30, 30, 50); + diff = datetime_compare(&bdatetime1, &bdatetime2); + ct_test(pTest, diff > 0); + + + return; +} + +void testDateEpoch(Test * pTest) +{ + uint32_t days = 0; + uint16_t year = 0, test_year = 0; + uint8_t month = 0, test_month = 0; + uint8_t day = 0, test_day = 0; + + days = days_since_epoch(1900, 1, 1); + ct_test(pTest, days == 0); + days_since_epoch_into_ymd(days, &year, &month, &day); + ct_test(pTest, year == 1900); + ct_test(pTest, month == 1); + ct_test(pTest, day == 1); + + + for (year = 1900; year <= 2154; year++) { + for (month = 1; month <= 12; month++) { + for (day = 1; day <= month_days(year, month); day++) { + days = days_since_epoch(year, month, day); + days_since_epoch_into_ymd(days, + &test_year, &test_month, &test_day); + ct_test(pTest, year == test_year); + ct_test(pTest, month == test_month); + ct_test(pTest, day == test_day); + } + } + } +} + +void testBACnetDayOfWeek(Test * pTest) +{ + uint8_t dow = 0; + + /* 1/1/1900 is a Monday */ + dow = day_of_week(1900, 1, 1); + ct_test(pTest, dow == 1); + + /* 1/1/2007 is a Monday */ + dow = day_of_week(2007, 1, 1); + ct_test(pTest, dow == 1); + dow = day_of_week(2007, 1, 2); + ct_test(pTest, dow == 2); + dow = day_of_week(2007, 1, 3); + ct_test(pTest, dow == 3); + dow = day_of_week(2007, 1, 4); + ct_test(pTest, dow == 4); + dow = day_of_week(2007, 1, 5); + ct_test(pTest, dow == 5); + dow = day_of_week(2007, 1, 6); + ct_test(pTest, dow == 6); + dow = day_of_week(2007, 1, 7); + ct_test(pTest, dow == 7); + + dow = day_of_week(2007, 1, 31); + ct_test(pTest, dow == 3); +} + +#ifdef TEST_DATE_TIME +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("BACnet Date Time", NULL); + /* individual tests */ + rc = ct_addTestFunction(pTest, testBACnetDate); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetTime); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetDateTime); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetDayOfWeek); + assert(rc); + rc = ct_addTestFunction(pTest, testDateEpoch); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetDateTimeSeconds); + assert(rc); + rc = ct_addTestFunction(pTest, testBACnetDateTimeAdd); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + ct_destroy(pTest); + + return 0; +} +#endif /* TEST_DATE_TIME */ +#endif /* TEST */ diff --git a/bacnet-stack/datetime.h b/bacnet-stack/datetime.h index b091aafa..8cb86c4e 100644 --- a/bacnet-stack/datetime.h +++ b/bacnet-stack/datetime.h @@ -1,102 +1,98 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2007 Steve Karg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ -#ifndef DATE_TIME_H -#define DATE_TIME_H - -#include -#include - -/* date */ -typedef struct BACnet_Date { - uint16_t year; /* AD */ - uint8_t month; /* 1=Jan */ - uint8_t day; /* 1..31 */ - uint8_t wday; /* 1=Monday-7=Sunday */ -} BACNET_DATE; - -/* time */ -typedef struct BACnet_Time { - uint8_t hour; - uint8_t min; - uint8_t sec; - uint8_t hundredths; -} BACNET_TIME; - -typedef struct BACnet_DateTime { - BACNET_DATE date; - BACNET_TIME time; -} BACNET_DATE_TIME; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - /* utility initialization functions */ - void datetime_set_date(BACNET_DATE * bdate, - uint16_t year, uint8_t month, uint8_t day); - void datetime_set_time(BACNET_TIME * btime, - uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths); - void datetime_set(BACNET_DATE_TIME * bdatetime, - BACNET_DATE * bdate, - BACNET_TIME * btime); - void datetime_set_values(BACNET_DATE_TIME * bdatetime, - uint16_t year, uint8_t month, uint8_t day, - uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths); - - /* utility comparison functions: - if the date/times are the same, return is 0 - if date1 is before date2, returns negative - if date1 is after date2, returns positive */ - int datetime_compare_date(BACNET_DATE * date1, BACNET_DATE * date2); - int datetime_compare_time(BACNET_TIME * time1, BACNET_TIME * time2); - int datetime_compare( - BACNET_DATE_TIME * datetime1, - BACNET_DATE_TIME * datetime2); - - /* utility copy functions */ - void datetime_copy_date(BACNET_DATE * date1, BACNET_DATE * date2); - void datetime_copy_time(BACNET_TIME * time1, BACNET_TIME * time2); - void datetime_copy( - BACNET_DATE_TIME * datetime1, - BACNET_DATE_TIME * datetime2); - - /* utility add function */ - void datetime_add_minutes(BACNET_DATE_TIME * bdatetime, uint32_t minutes); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* DATE_TIME_H */ - +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2007 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ +#ifndef DATE_TIME_H +#define DATE_TIME_H + +#include +#include + +/* date */ +typedef struct BACnet_Date { + uint16_t year; /* AD */ + uint8_t month; /* 1=Jan */ + uint8_t day; /* 1..31 */ + uint8_t wday; /* 1=Monday-7=Sunday */ +} BACNET_DATE; + +/* time */ +typedef struct BACnet_Time { + uint8_t hour; + uint8_t min; + uint8_t sec; + uint8_t hundredths; +} BACNET_TIME; + +typedef struct BACnet_DateTime { + BACNET_DATE date; + BACNET_TIME time; +} BACNET_DATE_TIME; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + /* utility initialization functions */ + void datetime_set_date(BACNET_DATE * bdate, + uint16_t year, uint8_t month, uint8_t day); + void datetime_set_time(BACNET_TIME * btime, + uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths); + void datetime_set(BACNET_DATE_TIME * bdatetime, + BACNET_DATE * bdate, BACNET_TIME * btime); + void datetime_set_values(BACNET_DATE_TIME * bdatetime, + uint16_t year, uint8_t month, uint8_t day, + uint8_t hour, uint8_t minute, uint8_t seconds, uint8_t hundredths); + + /* utility comparison functions: + if the date/times are the same, return is 0 + if date1 is before date2, returns negative + if date1 is after date2, returns positive */ + int datetime_compare_date(BACNET_DATE * date1, BACNET_DATE * date2); + int datetime_compare_time(BACNET_TIME * time1, BACNET_TIME * time2); + int datetime_compare(BACNET_DATE_TIME * datetime1, + BACNET_DATE_TIME * datetime2); + + /* utility copy functions */ + void datetime_copy_date(BACNET_DATE * date1, BACNET_DATE * date2); + void datetime_copy_time(BACNET_TIME * time1, BACNET_TIME * time2); + void datetime_copy(BACNET_DATE_TIME * datetime1, + BACNET_DATE_TIME * datetime2); + + /* utility add function */ + void datetime_add_minutes(BACNET_DATE_TIME * bdatetime, + uint32_t minutes); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DATE_TIME_H */ diff --git a/bacnet-stack/demo/handler/h_rp.c b/bacnet-stack/demo/handler/h_rp.c index b73496a5..8662b4ef 100644 --- a/bacnet-stack/demo/handler/h_rp.c +++ b/bacnet-stack/demo/handler/h_rp.c @@ -54,8 +54,7 @@ static uint8_t Temp_Buf[MAX_APDU] = { 0 }; void handler_read_property(uint8_t * service_request, uint16_t service_len, - BACNET_ADDRESS * src, - BACNET_CONFIRMED_SERVICE_DATA * service_data) + BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_READ_PROPERTY_DATA data; int len = 0; diff --git a/bacnet-stack/demo/handler/h_rp_a.c b/bacnet-stack/demo/handler/h_rp_a.c index d6e18698..617229ef 100644 --- a/bacnet-stack/demo/handler/h_rp_a.c +++ b/bacnet-stack/demo/handler/h_rp_a.c @@ -67,11 +67,11 @@ static void PrintReadPropertyData(BACNET_READ_PROPERTY_DATA * data) #endif application_data = data->application_data; application_data_len = data->application_data_len; - /* FIXME: what if application_data_len is bigger than 255? */ + /* FIXME: what if application_data_len is bigger than 255? */ /* value? need to loop until all of the len is gone... */ for (;;) { len = bacapp_decode_application_data(application_data, - (uint8_t)application_data_len, &value); + (uint8_t) application_data_len, &value); if (first_value && (len < application_data_len)) { first_value = false; fprintf(stdout, "{"); diff --git a/bacnet-stack/demo/handler/h_wp.c b/bacnet-stack/demo/handler/h_wp.c index dea3ec6b..4f9c2f09 100644 --- a/bacnet-stack/demo/handler/h_wp.c +++ b/bacnet-stack/demo/handler/h_wp.c @@ -259,7 +259,8 @@ void handler_write_property(uint8_t * service_request, SERVICE_CONFIRMED_WRITE_PROPERTY, error_class, error_code); #if PRINT_ENABLED - fprintf(stderr, "Sending Write Access Error for Load Control!\n"); + fprintf(stderr, + "Sending Write Access Error for Load Control!\n"); #endif } break; diff --git a/bacnet-stack/demo/handler/s_rp.c b/bacnet-stack/demo/handler/s_rp.c index f73ce331..3a5c1f2f 100644 --- a/bacnet-stack/demo/handler/s_rp.c +++ b/bacnet-stack/demo/handler/s_rp.c @@ -89,7 +89,8 @@ uint8_t Send_Read_Property_Request(uint32_t device_id, /* destination device */ max_apdu in the address binding table. */ if ((unsigned) pdu_len < max_apdu) { tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest, - &npdu_data, &Handler_Transmit_Buffer[0], (uint16_t)pdu_len); + &npdu_data, &Handler_Transmit_Buffer[0], + (uint16_t) pdu_len); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); diff --git a/bacnet-stack/demo/handler/s_wp.c b/bacnet-stack/demo/handler/s_wp.c index 3586b7d5..461c7ade 100644 --- a/bacnet-stack/demo/handler/s_wp.c +++ b/bacnet-stack/demo/handler/s_wp.c @@ -81,8 +81,8 @@ uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */ data.object_property = object_property; data.array_index = array_index; data.application_data_len = - bacapp_encode_application_data( - &data.application_data[0],object_value); + bacapp_encode_application_data(&data.application_data[0], + object_value); data.priority = priority; len = wp_encode_apdu(&Handler_Transmit_Buffer[pdu_len], invoke_id, &data); @@ -94,7 +94,8 @@ uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */ max_apdu in the address binding table. */ if ((unsigned) pdu_len < max_apdu) { tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest, - &npdu_data, &Handler_Transmit_Buffer[0], (uint16_t)pdu_len); + &npdu_data, &Handler_Transmit_Buffer[0], + (uint16_t) pdu_len); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); diff --git a/bacnet-stack/demo/object/ai.c b/bacnet-stack/demo/object/ai.c index 24359472..35d5197d 100644 --- a/bacnet-stack/demo/object/ai.c +++ b/bacnet-stack/demo/object/ai.c @@ -84,7 +84,7 @@ int Analog_Input_Encode_Property_APDU(uint8_t * apdu, int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; - float value = (float)3.14; + float value = (float) 3.14; (void) array_index; switch (property) { @@ -122,7 +122,7 @@ int Analog_Input_Encode_Property_APDU(uint8_t * apdu, apdu_len = encode_tagged_enumerated(&apdu[0], UNITS_PERCENT); break; case 9997: - apdu_len = encode_tagged_real(&apdu[0], (float)90.510); + apdu_len = encode_tagged_real(&apdu[0], (float) 90.510); break; case 9998: apdu_len = encode_tagged_unsigned(&apdu[0], 90); diff --git a/bacnet-stack/demo/object/ao.c b/bacnet-stack/demo/object/ao.c index 98ecfb7f..29546f5d 100644 --- a/bacnet-stack/demo/object/ao.c +++ b/bacnet-stack/demo/object/ao.c @@ -161,7 +161,7 @@ int Analog_Output_Encode_Property_APDU(uint8_t * apdu, int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; - float real_value = (float)1.414; + float real_value = (float) 1.414; unsigned object_index = 0; unsigned i = 0; bool state = false; @@ -237,12 +237,12 @@ int Analog_Output_Encode_Property_APDU(uint8_t * apdu, object_index = Analog_Output_Instance_To_Index(object_instance); if (array_index <= BACNET_MAX_PRIORITY) { - if (Analog_Output_Level[object_index][array_index-1] == + if (Analog_Output_Level[object_index][array_index - 1] == AO_LEVEL_NULL) apdu_len = encode_tagged_null(&apdu[0]); else { real_value = - Analog_Output_Level[object_index][array_index-1]; + Analog_Output_Level[object_index][array_index - 1]; apdu_len = encode_tagged_real(&apdu[0], real_value); } } else { @@ -285,10 +285,8 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, return false; } /* decode the some of the request */ - len = bacapp_decode_application_data( - wp_data->application_data, - wp_data->application_data_len, - &value); + 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) { @@ -300,8 +298,7 @@ bool Analog_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, object. */ if (priority && (priority <= BACNET_MAX_PRIORITY) && (priority != 6 /* reserved */ ) && - (value.type.Real >= 0.0) && - (value.type.Real <= 100.0)) { + (value.type.Real >= 0.0) && (value.type.Real <= 100.0)) { level = (uint8_t) value.type.Real; object_index = Analog_Output_Instance_To_Index(wp_data-> diff --git a/bacnet-stack/demo/object/av.c b/bacnet-stack/demo/object/av.c index 841c8ae8..4eaaa8a6 100644 --- a/bacnet-stack/demo/object/av.c +++ b/bacnet-stack/demo/object/av.c @@ -31,7 +31,7 @@ #include "bacdef.h" #include "bacdcode.h" #include "bacenum.h" -#include "bacapp.h" +#include "bacapp.h" #include "config.h" /* the custom stuff */ #include "wp.h" @@ -160,7 +160,7 @@ int Analog_Value_Encode_Property_APDU(uint8_t * apdu, int apdu_len = 0; /* return value */ BACNET_BIT_STRING bit_string; BACNET_CHARACTER_STRING char_string; - float real_value = (float)1.414; + float real_value = (float) 1.414; unsigned object_index = 0; unsigned i = 0; bool state = false; @@ -234,12 +234,12 @@ int Analog_Value_Encode_Property_APDU(uint8_t * apdu, } else { object_index = Analog_Value_Instance_To_Index(object_instance); if (array_index <= BACNET_MAX_PRIORITY) { - if (Analog_Value_Level[object_index][array_index-1] == + if (Analog_Value_Level[object_index][array_index - 1] == ANALOG_LEVEL_NULL) apdu_len = encode_tagged_null(&apdu[0]); else { real_value = - Analog_Value_Level[object_index][array_index-1]; + Analog_Value_Level[object_index][array_index - 1]; apdu_len = encode_tagged_real(&apdu[0], real_value); } } else { @@ -272,8 +272,8 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, unsigned int object_index = 0; unsigned int priority = 0; uint8_t level = ANALOG_LEVEL_NULL; - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; Analog_Value_Init(); if (!Analog_Value_Valid_Instance(wp_data->object_instance)) { @@ -282,12 +282,10 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, 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? */ + 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) { @@ -297,8 +295,7 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, object. */ if (priority && (priority <= BACNET_MAX_PRIORITY) && (priority != 6 /* reserved */ ) && - (value.type.Real >= 0.0) && - (value.type.Real <= 100.0)) { + (value.type.Real >= 0.0) && (value.type.Real <= 100.0)) { level = (uint8_t) value.type.Real; object_index = Analog_Value_Instance_To_Index(wp_data-> @@ -349,8 +346,7 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, 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; + Analog_Value_Out_Of_Service[object_index] = value.type.Boolean; status = true; } else { *error_class = ERROR_CLASS_PROPERTY; diff --git a/bacnet-stack/demo/object/bacfile.c b/bacnet-stack/demo/object/bacfile.c index 3f7324f3..4e00f8cd 100644 --- a/bacnet-stack/demo/object/bacfile.c +++ b/bacnet-stack/demo/object/bacfile.c @@ -232,10 +232,8 @@ bool bacfile_write_property(BACNET_WRITE_PROPERTY_DATA * wp_data, } /* decode the some of the request */ - len = bacapp_decode_application_data( - wp_data->application_data, - wp_data->application_data_len, - &value); + 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) { diff --git a/bacnet-stack/demo/object/bo.c b/bacnet-stack/demo/object/bo.c index 27dac229..67fe8ed7 100644 --- a/bacnet-stack/demo/object/bo.c +++ b/bacnet-stack/demo/object/bo.c @@ -30,7 +30,7 @@ #include #include "bacdef.h" #include "bacdcode.h" -#include "bacenum.h" +#include "bacenum.h" #include "bacapp.h" #include "config.h" /* the custom stuff */ #include "wp.h" @@ -273,8 +273,8 @@ bool Binary_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, unsigned int object_index = 0; unsigned int priority = 0; BACNET_BINARY_PV level = BINARY_NULL; - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; Binary_Output_Init(); if (!Binary_Output_Valid_Instance(wp_data->object_instance)) { @@ -283,12 +283,10 @@ bool Binary_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, 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? */ + 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_ENUMERATED) { diff --git a/bacnet-stack/demo/object/bv.c b/bacnet-stack/demo/object/bv.c index ac2c526a..deb25273 100644 --- a/bacnet-stack/demo/object/bv.c +++ b/bacnet-stack/demo/object/bv.c @@ -30,7 +30,7 @@ #include #include "bacdef.h" #include "bacdcode.h" -#include "bacenum.h" +#include "bacenum.h" #include "bacapp.h" #include "config.h" /* the custom stuff */ #include "wp.h" @@ -270,8 +270,8 @@ bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, unsigned int object_index = 0; unsigned int priority = 0; BACNET_BINARY_PV level = BINARY_NULL; - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; Binary_Value_Init(); if (!Binary_Value_Valid_Instance(wp_data->object_instance)) { @@ -280,12 +280,10 @@ bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, 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? */ + 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_ENUMERATED) { @@ -347,8 +345,7 @@ bool Binary_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { object_index = Binary_Value_Instance_To_Index(wp_data->object_instance); - Binary_Value_Out_Of_Service[object_index] = - value.type.Boolean; + Binary_Value_Out_Of_Service[object_index] = value.type.Boolean; status = true; } else { *error_class = ERROR_CLASS_PROPERTY; diff --git a/bacnet-stack/demo/object/device.c b/bacnet-stack/demo/object/device.c index e9be5624..9d46114f 100644 --- a/bacnet-stack/demo/object/device.c +++ b/bacnet-stack/demo/object/device.c @@ -796,18 +796,16 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, return false; } /* decode the some of the request */ - len = bacapp_decode_application_data( - wp_data->application_data, - wp_data->application_data_len, - &value); + 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_OBJECT_IDENTIFIER: if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) { if ((value.type.Object_Id.type == OBJECT_DEVICE) && - (Device_Set_Object_Instance_Number( - value.type.Object_Id.instance))) { + (Device_Set_Object_Instance_Number(value.type.Object_Id. + instance))) { /* FIXME: we could send an I-Am broadcast to let the world know */ status = true; } else { @@ -835,8 +833,7 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, case PROP_APDU_TIMEOUT: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { /* FIXME: bounds check? */ - Device_Set_APDU_Timeout((uint16_t) value.type. - Unsigned_Int); + Device_Set_APDU_Timeout((uint16_t) value.type.Unsigned_Int); status = true; } else { *error_class = ERROR_CLASS_PROPERTY; @@ -870,13 +867,12 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { uint8_t encoding; encoding = - characterstring_encoding(&value.type. - Character_String); + characterstring_encoding(&value.type.Character_String); if (encoding == CHARACTER_ANSI_X34) { status = - Device_Set_Object_Name( - characterstring_value(&value.type.Character_String), - characterstring_length(&value.type.Character_String)); + Device_Set_Object_Name(characterstring_value(&value. + type.Character_String), + characterstring_length(&value.type.Character_String)); if (!status) { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; diff --git a/bacnet-stack/demo/object/lc.c b/bacnet-stack/demo/object/lc.c index 7ea47bb2..58cdc1ef 100644 --- a/bacnet-stack/demo/object/lc.c +++ b/bacnet-stack/demo/object/lc.c @@ -28,86 +28,86 @@ #include #include #include -#include /* for memcpy */ +#include /* for memcpy */ #include #include "bacdef.h" #include "bacdcode.h" #include "datetime.h" #include "bacenum.h" -#include "config.h" /* the custom stuff */ +#include "config.h" /* the custom stuff */ #include "lc.h" #include "wp.h" - + /* number of objects */ -#define MAX_LOAD_CONTROLS 6 - -/* indicates the current load shedding state of the object */ -static BACNET_SHED_STATE Present_Value[MAX_LOAD_CONTROLS]; - -typedef enum BACnetShedLevelType { - BACNET_SHED_TYPE_PERCENT, /* Unsigned */ - BACNET_SHED_TYPE_LEVEL, /* Unsigned */ - BACNET_SHED_TYPE_AMOUNT /* REAL */ -} BACNET_SHED_LEVEL_TYPE; - -/* The shed levels for the LEVEL choice of BACnetShedLevel - that have meaning for this particular Load Control object. */ -#define MAX_SHED_LEVELS 3 -typedef struct { - BACNET_SHED_LEVEL_TYPE type; - union { - unsigned level; - unsigned percent; - float amount; - } value; -} BACNET_SHED_LEVEL; -/* indicates the desired load shedding */ -static BACNET_SHED_LEVEL Requested_Shed_Level[MAX_LOAD_CONTROLS]; -/* Indicates the amount of power that the object expects - to be able to shed in response to a load shed request. */ -static BACNET_SHED_LEVEL Expected_Shed_Level[MAX_LOAD_CONTROLS]; -/* Indicates the actual amount of power being shed in response - to a load shed request. */ -static BACNET_SHED_LEVEL Actual_Shed_Level[MAX_LOAD_CONTROLS]; - -/* indicates the start of the duty window in which the load controlled - by the Load Control object must be compliant with the requested shed. */ -static BACNET_DATE_TIME Start_Time[MAX_LOAD_CONTROLS]; -static BACNET_DATE_TIME End_Time[MAX_LOAD_CONTROLS]; -static BACNET_DATE_TIME Previous_Start_Time[MAX_LOAD_CONTROLS]; -static BACNET_DATE_TIME Current_Time; - -/* indicates the duration of the load shed action, - starting at Start_Time in minutes */ -static uint32_t Shed_Duration[MAX_LOAD_CONTROLS]; - -/* indicates the time window used for load shed accounting in minutes */ -static uint32_t Duty_Window[MAX_LOAD_CONTROLS]; - -/* indicates and controls whether the Load Control object is - currently enabled to respond to load shed requests. */ -static bool Load_Control_Enable[MAX_LOAD_CONTROLS]; - -/* optional: indicates the baseline power consumption value - for the sheddable load controlled by this object, - if a fixed baseline is used. - The units of Full_Duty_Baseline are kilowatts.*/ -static float Full_Duty_Baseline[MAX_LOAD_CONTROLS]; - -/* Represents the shed levels for the LEVEL choice of - BACnetShedLevel that have meaning for this particular - Load Control object. */ -static unsigned Shed_Levels[MAX_LOAD_CONTROLS][MAX_SHED_LEVELS]; - -/* represents a description of the shed levels that the - Load Control object can take on. It is the same for - all the load control objects in this example device. */ -static char *Shed_Level_Descriptions[MAX_SHED_LEVELS] = { - "dim lights 10%", - "dim lights 20%", - "dim lights 30%" -}; - +#define MAX_LOAD_CONTROLS 6 + +/* indicates the current load shedding state of the object */ +static BACNET_SHED_STATE Present_Value[MAX_LOAD_CONTROLS]; + +typedef enum BACnetShedLevelType { + BACNET_SHED_TYPE_PERCENT, /* Unsigned */ + BACNET_SHED_TYPE_LEVEL, /* Unsigned */ + BACNET_SHED_TYPE_AMOUNT /* REAL */ +} BACNET_SHED_LEVEL_TYPE; + +/* The shed levels for the LEVEL choice of BACnetShedLevel + that have meaning for this particular Load Control object. */ +#define MAX_SHED_LEVELS 3 +typedef struct { + BACNET_SHED_LEVEL_TYPE type; + union { + unsigned level; + unsigned percent; + float amount; + } value; +} BACNET_SHED_LEVEL; +/* indicates the desired load shedding */ +static BACNET_SHED_LEVEL Requested_Shed_Level[MAX_LOAD_CONTROLS]; +/* Indicates the amount of power that the object expects + to be able to shed in response to a load shed request. */ +static BACNET_SHED_LEVEL Expected_Shed_Level[MAX_LOAD_CONTROLS]; +/* Indicates the actual amount of power being shed in response + to a load shed request. */ +static BACNET_SHED_LEVEL Actual_Shed_Level[MAX_LOAD_CONTROLS]; + +/* indicates the start of the duty window in which the load controlled + by the Load Control object must be compliant with the requested shed. */ +static BACNET_DATE_TIME Start_Time[MAX_LOAD_CONTROLS]; +static BACNET_DATE_TIME End_Time[MAX_LOAD_CONTROLS]; +static BACNET_DATE_TIME Previous_Start_Time[MAX_LOAD_CONTROLS]; +static BACNET_DATE_TIME Current_Time; + +/* indicates the duration of the load shed action, + starting at Start_Time in minutes */ +static uint32_t Shed_Duration[MAX_LOAD_CONTROLS]; + +/* indicates the time window used for load shed accounting in minutes */ +static uint32_t Duty_Window[MAX_LOAD_CONTROLS]; + +/* indicates and controls whether the Load Control object is + currently enabled to respond to load shed requests. */ +static bool Load_Control_Enable[MAX_LOAD_CONTROLS]; + +/* optional: indicates the baseline power consumption value + for the sheddable load controlled by this object, + if a fixed baseline is used. + The units of Full_Duty_Baseline are kilowatts.*/ +static float Full_Duty_Baseline[MAX_LOAD_CONTROLS]; + +/* Represents the shed levels for the LEVEL choice of + BACnetShedLevel that have meaning for this particular + Load Control object. */ +static unsigned Shed_Levels[MAX_LOAD_CONTROLS][MAX_SHED_LEVELS]; + +/* represents a description of the shed levels that the + Load Control object can take on. It is the same for + all the load control objects in this example device. */ +static char *Shed_Level_Descriptions[MAX_SHED_LEVELS] = { + "dim lights 10%", + "dim lights 20%", + "dim lights 30%" +}; + /* we need to have our arrays initialized before answering any calls */ static bool Load_Control_Initialized = false; @@ -117,26 +117,27 @@ void Load_Control_Init(void) if (!Load_Control_Initialized) { Load_Control_Initialized = true; - for (i = 0; i < MAX_LOAD_CONTROLS; i++) { - /* FIXME: load saved data? */ - Present_Value[i] = BACNET_SHED_INACTIVE; - Requested_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL; - Requested_Shed_Level[i].value.level = 0; - datetime_set_values(&Start_Time[i],0,0,0,0,0,0,0); - datetime_set_values(&Previous_Start_Time[i],0,0,0,0,0,0,0); - Shed_Duration[i] = 0; - Duty_Window[i] = 0; - Load_Control_Enable[i] = true; - Full_Duty_Baseline[i] = 0.0; - for (j = 0; j < MAX_SHED_LEVELS; j++) { - /* FIXME: fake data for lighting application */ - /* The array shall be ordered by increasing shed amount. */ - Shed_Levels[i][j] = 90 - (j * (30/MAX_SHED_LEVELS)); - } - Expected_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL; - Expected_Shed_Level[i].value.level = 0; - Actual_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL; - Actual_Shed_Level[i].value.level = 0; + for (i = 0; i < MAX_LOAD_CONTROLS; i++) { + /* FIXME: load saved data? */ + Present_Value[i] = BACNET_SHED_INACTIVE; + Requested_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL; + Requested_Shed_Level[i].value.level = 0; + datetime_set_values(&Start_Time[i], 0, 0, 0, 0, 0, 0, 0); + datetime_set_values(&Previous_Start_Time[i], 0, 0, 0, 0, 0, 0, + 0); + Shed_Duration[i] = 0; + Duty_Window[i] = 0; + Load_Control_Enable[i] = true; + Full_Duty_Baseline[i] = 0.0; + for (j = 0; j < MAX_SHED_LEVELS; j++) { + /* FIXME: fake data for lighting application */ + /* The array shall be ordered by increasing shed amount. */ + Shed_Levels[i][j] = 90 - (j * (30 / MAX_SHED_LEVELS)); + } + Expected_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL; + Expected_Shed_Level[i].value.level = 0; + Actual_Shed_Level[i].type = BACNET_SHED_TYPE_LEVEL; + Actual_Shed_Level[i].value.level = 0; } } @@ -186,7 +187,8 @@ unsigned Load_Control_Instance_To_Index(uint32_t object_instance) return index; } -static BACNET_SHED_STATE Load_Control_Present_Value(uint32_t object_instance) +static BACNET_SHED_STATE Load_Control_Present_Value(uint32_t + object_instance) { BACNET_SHED_STATE value = BACNET_SHED_INACTIVE; unsigned index = 0; @@ -194,7 +196,7 @@ static BACNET_SHED_STATE Load_Control_Present_Value(uint32_t object_instance) Load_Control_Init(); index = Load_Control_Instance_To_Index(object_instance); if (index < MAX_LOAD_CONTROLS) { - value = Present_Value[index]; + value = Present_Value[index]; } return value; @@ -217,63 +219,58 @@ static void Update_Current_Time(BACNET_DATE_TIME * bdatetime) { time_t timer; struct tm *tblock; - -/* -struct tm { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; -*/ - - timer = time(NULL); - tblock = localtime(&timer); - datetime_set_values( - bdatetime, - tblock->tm_year, - tblock->tm_mon, - tblock->tm_mday, - tblock->tm_hour, - tblock->tm_min, - tblock->tm_sec, - 0); -} -typedef enum load_control_state -{ - SHED_INACTIVE, - SHED_REQUEST_PENDING, - SHED_NON_COMPLIANT, - SHED_COMPLIANT +/* +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; +*/ + + timer = time(NULL); + tblock = localtime(&timer); + datetime_set_values(bdatetime, + tblock->tm_year, + tblock->tm_mon, + tblock->tm_mday, + tblock->tm_hour, tblock->tm_min, tblock->tm_sec, 0); +} + +typedef enum load_control_state { + SHED_INACTIVE, + SHED_REQUEST_PENDING, + SHED_NON_COMPLIANT, + SHED_COMPLIANT } LOAD_CONTROL_STATE; void Load_Control_State_Machine(int object_index) { static LOAD_CONTROL_STATE state[MAX_LOAD_CONTROLS]; static bool initialized = false; - unsigned i = 0; /* loop counter */ - int diff = 0; /* used for datetime comparison */ + unsigned i = 0; /* loop counter */ + int diff = 0; /* used for datetime comparison */ if (!initialized) { - initialized = true; - for (i = 0; i < MAX_LOAD_CONTROLS; i++) { - state[i] = SHED_INACTIVE; - } + initialized = true; + for (i = 0; i < MAX_LOAD_CONTROLS; i++) { + state[i] = SHED_INACTIVE; + } } - switch (state[object_index]) - { - case SHED_REQUEST_PENDING: + switch (state[object_index]) { + case SHED_REQUEST_PENDING: Update_Current_Time(&Current_Time); - datetime_copy(&End_Time[object_index],&Start_Time[object_index]); - datetime_add_minutes(&End_Time[object_index], Shed_Duration[object_index]); - diff = datetime_compare(&End_Time[object_index],&Current_Time); + datetime_copy(&End_Time[object_index], &Start_Time[object_index]); + datetime_add_minutes(&End_Time[object_index], + Shed_Duration[object_index]); + diff = datetime_compare(&End_Time[object_index], &Current_Time); if (diff < 0) { /* CancelShed */ /* FIXME: stop shedding! i.e. relinquish */ @@ -286,12 +283,12 @@ void Load_Control_State_Machine(int object_index) } break; - case SHED_NON_COMPLIANT: + case SHED_NON_COMPLIANT: break; - case SHED_COMPLIANT: + case SHED_COMPLIANT: break; - case SHED_INACTIVE: - default: + case SHED_INACTIVE: + default: diff = datetime_compare(&Previous_Start_Time[object_index], &Start_Time[object_index]); if (diff != 0) { @@ -301,25 +298,24 @@ void Load_Control_State_Machine(int object_index) /* FIXME: calculate your Actual Shed Level */ Expected_Shed_Level[object_index].type = Requested_Shed_Level[object_index].type; - switch (Requested_Shed_Level[object_index].type) - { - case BACNET_SHED_TYPE_PERCENT: - Actual_Shed_Level[object_index].value.percent = - Expected_Shed_Level[object_index].value.percent = - Requested_Shed_Level[object_index].value.percent; - break; - case BACNET_SHED_TYPE_AMOUNT: - Actual_Shed_Level[object_index].value.amount = - Expected_Shed_Level[object_index].value.amount = - Requested_Shed_Level[object_index].value.amount; - break; - case BACNET_SHED_TYPE_LEVEL: - default: - Actual_Shed_Level[object_index].value.level = - Expected_Shed_Level[object_index].value.level = - Requested_Shed_Level[object_index].value.level; - break; - } + switch (Requested_Shed_Level[object_index].type) { + case BACNET_SHED_TYPE_PERCENT: + Actual_Shed_Level[object_index].value.percent = + Expected_Shed_Level[object_index].value.percent = + Requested_Shed_Level[object_index].value.percent; + break; + case BACNET_SHED_TYPE_AMOUNT: + Actual_Shed_Level[object_index].value.amount = + Expected_Shed_Level[object_index].value.amount = + Requested_Shed_Level[object_index].value.amount; + break; + case BACNET_SHED_TYPE_LEVEL: + default: + Actual_Shed_Level[object_index].value.level = + Expected_Shed_Level[object_index].value.level = + Requested_Shed_Level[object_index].value.level; + break; + } state[object_index] = SHED_REQUEST_PENDING; } break; @@ -332,7 +328,7 @@ void Load_Control_State_Machine(int object_index) void Load_Control_State_Machine_Handler(void) { unsigned i = 0; - + for (i = 0; i < MAX_LOAD_CONTROLS; i++) { Load_Control_State_Machine(i); } @@ -365,33 +361,33 @@ int Load_Control_Encode_Property_APDU(uint8_t * apdu, characterstring_init_ansi(&char_string, Load_Control_Name(object_instance)); apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; + break; case PROP_OBJECT_TYPE: apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_LOAD_CONTROL); break; - /* optional property - case PROP_DESCRIPTION: - characterstring_init_ansi(&char_string,"optional description"); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - */ + /* optional property + case PROP_DESCRIPTION: + characterstring_init_ansi(&char_string,"optional description"); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + */ case PROP_PRESENT_VALUE: enumeration = Load_Control_Present_Value(object_instance); apdu_len = encode_tagged_enumerated(&apdu[0], enumeration); break; case PROP_STATUS_FLAGS: - bitstring_init(&bit_string); - /* IN_ALARM - Logical FALSE (0) if the Event_State property + bitstring_init(&bit_string); + /* IN_ALARM - Logical FALSE (0) if the Event_State property has a value of NORMAL, otherwise logical TRUE (1). */ - bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); - /* FAULT - Logical TRUE (1) if the Reliability property is - present and does not have a value of NO_FAULT_DETECTED, + bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); + /* FAULT - Logical TRUE (1) if the Reliability property is + present and does not have a value of NO_FAULT_DETECTED, otherwise logical FALSE (0). */ - bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); - /* OVERRIDDEN - Logical TRUE (1) if the point has been - overridden by some mechanism local to the BACnet Device, - otherwise logical FALSE (0).*/ - bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); + bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); + /* OVERRIDDEN - Logical TRUE (1) if the point has been + overridden by some mechanism local to the BACnet Device, + otherwise logical FALSE (0). */ + bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); /* OUT_OF_SERVICE - This bit shall always be Logical FALSE (0). */ bitstring_set_bit(&bit_string, STATUS_FLAG_OUT_OF_SERVICE, false); apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); @@ -400,95 +396,92 @@ int Load_Control_Encode_Property_APDU(uint8_t * apdu, apdu_len = encode_tagged_enumerated(&apdu[0], EVENT_STATE_NORMAL); break; case PROP_REQUESTED_SHED_LEVEL: - switch (Requested_Shed_Level[object_index].type) - { - case BACNET_SHED_TYPE_PERCENT: - apdu_len = encode_context_unsigned(&apdu[0], 0, - Requested_Shed_Level[object_index].value.percent); - break; - case BACNET_SHED_TYPE_AMOUNT: - apdu_len = encode_context_real(&apdu[0], 2, - Requested_Shed_Level[object_index].value.amount); - break; - case BACNET_SHED_TYPE_LEVEL: - default: - apdu_len = encode_context_unsigned(&apdu[0], 1, - Requested_Shed_Level[object_index].value.level); - break; - } - break; - case PROP_START_TIME: - len = encode_tagged_date(&apdu[0], - &Start_Time[object_index].date); - apdu_len = len; - len = encode_tagged_time(&apdu[apdu_len], - &Start_Time[object_index].time); - apdu_len += len; - break; - case PROP_SHED_DURATION: - apdu_len = encode_tagged_unsigned(&apdu[0], + switch (Requested_Shed_Level[object_index].type) { + case BACNET_SHED_TYPE_PERCENT: + apdu_len = encode_context_unsigned(&apdu[0], 0, + Requested_Shed_Level[object_index].value.percent); + break; + case BACNET_SHED_TYPE_AMOUNT: + apdu_len = encode_context_real(&apdu[0], 2, + Requested_Shed_Level[object_index].value.amount); + break; + case BACNET_SHED_TYPE_LEVEL: + default: + apdu_len = encode_context_unsigned(&apdu[0], 1, + Requested_Shed_Level[object_index].value.level); + break; + } + break; + case PROP_START_TIME: + len = encode_tagged_date(&apdu[0], &Start_Time[object_index].date); + apdu_len = len; + len = encode_tagged_time(&apdu[apdu_len], + &Start_Time[object_index].time); + apdu_len += len; + break; + case PROP_SHED_DURATION: + apdu_len = encode_tagged_unsigned(&apdu[0], Shed_Duration[object_index]); - break; - case PROP_DUTY_WINDOW: - apdu_len = encode_tagged_unsigned(&apdu[0], + break; + case PROP_DUTY_WINDOW: + apdu_len = encode_tagged_unsigned(&apdu[0], Duty_Window[object_index]); - break; - case PROP_ENABLE: + break; + case PROP_ENABLE: state = Load_Control_Enable[object_index]; apdu_len = encode_tagged_boolean(&apdu[0], state); - break; - case PROP_FULL_DUTY_BASELINE: /* optional */ + break; + case PROP_FULL_DUTY_BASELINE: /* optional */ apdu_len = encode_tagged_real(&apdu[0], Full_Duty_Baseline[object_index]); - break; - case PROP_EXPECTED_SHED_LEVEL: - switch (Expected_Shed_Level[object_index].type) - { - case BACNET_SHED_TYPE_PERCENT: - apdu_len = encode_context_unsigned(&apdu[0], 0, - Expected_Shed_Level[object_index].value.percent); - break; - case BACNET_SHED_TYPE_AMOUNT: - apdu_len = encode_context_real(&apdu[0], 2, - Expected_Shed_Level[object_index].value.amount); - break; - case BACNET_SHED_TYPE_LEVEL: - default: - apdu_len = encode_context_unsigned(&apdu[0], 1, - Expected_Shed_Level[object_index].value.level); - break; - } - break; - case PROP_ACTUAL_SHED_LEVEL: - switch (Actual_Shed_Level[object_index].type) - { - case BACNET_SHED_TYPE_PERCENT: - apdu_len = encode_context_unsigned(&apdu[0], 0, - Actual_Shed_Level[object_index].value.percent); - break; - case BACNET_SHED_TYPE_AMOUNT: - apdu_len = encode_context_real(&apdu[0], 2, - Actual_Shed_Level[object_index].value.amount); - break; - case BACNET_SHED_TYPE_LEVEL: - default: - apdu_len = encode_context_unsigned(&apdu[0], 1, - Actual_Shed_Level[object_index].value.level); - break; - } - break; + break; + case PROP_EXPECTED_SHED_LEVEL: + switch (Expected_Shed_Level[object_index].type) { + case BACNET_SHED_TYPE_PERCENT: + apdu_len = encode_context_unsigned(&apdu[0], 0, + Expected_Shed_Level[object_index].value.percent); + break; + case BACNET_SHED_TYPE_AMOUNT: + apdu_len = encode_context_real(&apdu[0], 2, + Expected_Shed_Level[object_index].value.amount); + break; + case BACNET_SHED_TYPE_LEVEL: + default: + apdu_len = encode_context_unsigned(&apdu[0], 1, + Expected_Shed_Level[object_index].value.level); + break; + } + break; + case PROP_ACTUAL_SHED_LEVEL: + switch (Actual_Shed_Level[object_index].type) { + case BACNET_SHED_TYPE_PERCENT: + apdu_len = encode_context_unsigned(&apdu[0], 0, + Actual_Shed_Level[object_index].value.percent); + break; + case BACNET_SHED_TYPE_AMOUNT: + apdu_len = encode_context_real(&apdu[0], 2, + Actual_Shed_Level[object_index].value.amount); + break; + case BACNET_SHED_TYPE_LEVEL: + default: + apdu_len = encode_context_unsigned(&apdu[0], 1, + Actual_Shed_Level[object_index].value.level); + break; + } + break; case PROP_SHED_LEVELS: /* Array element zero is the number of elements in the array */ if (array_index == BACNET_ARRAY_LENGTH_INDEX) - apdu_len = - encode_tagged_unsigned(&apdu[0], MAX_SHED_LEVELS); + apdu_len = encode_tagged_unsigned(&apdu[0], MAX_SHED_LEVELS); /* if no index was specified, then try to encode the entire list */ /* into one packet. */ else if (array_index == BACNET_ARRAY_ALL) { apdu_len = 0; for (i = 0; i < MAX_SHED_LEVELS; i++) { /* FIXME: check if we have room before adding it to APDU */ - len = encode_tagged_unsigned(&apdu[apdu_len], Shed_Levels[object_index][i]); + len = + encode_tagged_unsigned(&apdu[apdu_len], + Shed_Levels[object_index][i]); /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) apdu_len += len; @@ -501,20 +494,19 @@ int Load_Control_Encode_Property_APDU(uint8_t * apdu, } } else { if (array_index <= MAX_SHED_LEVELS) { - apdu_len = encode_tagged_unsigned(&apdu[0], - Shed_Levels[object_index][array_index-1]); + apdu_len = encode_tagged_unsigned(&apdu[0], + Shed_Levels[object_index][array_index - 1]); } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; apdu_len = -1; } } - break; + break; case PROP_SHED_LEVEL_DESCRIPTIONS: /* Array element zero is the number of elements in the array */ if (array_index == BACNET_ARRAY_LENGTH_INDEX) - apdu_len = - encode_tagged_unsigned(&apdu[0], MAX_SHED_LEVELS); + apdu_len = encode_tagged_unsigned(&apdu[0], MAX_SHED_LEVELS); /* if no index was specified, then try to encode the entire list */ /* into one packet. */ else if (array_index == BACNET_ARRAY_ALL) { @@ -523,7 +515,7 @@ int Load_Control_Encode_Property_APDU(uint8_t * apdu, /* FIXME: check if we have room before adding it to APDU */ characterstring_init_ansi(&char_string, Shed_Level_Descriptions[i]); - len = encode_tagged_character_string(&apdu[apdu_len], + len = encode_tagged_character_string(&apdu[apdu_len], &char_string); /* add it if we have room */ if ((apdu_len + len) < MAX_APDU) @@ -538,8 +530,8 @@ int Load_Control_Encode_Property_APDU(uint8_t * apdu, } else { if (array_index <= MAX_SHED_LEVELS) { characterstring_init_ansi(&char_string, - Shed_Level_Descriptions[array_index-1]); - apdu_len = encode_tagged_character_string(&apdu[0], + Shed_Level_Descriptions[array_index - 1]); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); } else { *error_class = ERROR_CLASS_PROPERTY; @@ -547,7 +539,7 @@ int Load_Control_Encode_Property_APDU(uint8_t * apdu, apdu_len = -1; } } - break; + break; default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_UNKNOWN_PROPERTY; @@ -565,7 +557,7 @@ bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, bool status = false; /* return value */ unsigned int object_index = 0; int len = 0; - BACNET_APPLICATION_DATA_VALUE value; + BACNET_APPLICATION_DATA_VALUE value; Load_Control_Init(); if (!Load_Control_Valid_Instance(wp_data->object_instance)) { @@ -574,111 +566,103 @@ bool Load_Control_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, 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? */ - object_index = Load_Control_Instance_To_Index(wp_data->object_instance); + 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? */ + object_index = + Load_Control_Instance_To_Index(wp_data->object_instance); switch (wp_data->object_property) { - case PROP_REQUESTED_SHED_LEVEL: - len = bacapp_decode_context_data( - wp_data->application_data, - wp_data->application_data_len, - &value, PROP_REQUESTED_SHED_LEVEL); - if (value.tag == 0) { - /* percent - Unsigned */ + case PROP_REQUESTED_SHED_LEVEL: + len = bacapp_decode_context_data(wp_data->application_data, + wp_data->application_data_len, + &value, PROP_REQUESTED_SHED_LEVEL); + if (value.tag == 0) { + /* percent - Unsigned */ Requested_Shed_Level[object_index].value.percent = - value.type.Unsigned_Int; + value.type.Unsigned_Int; status = true; - } else if (value.tag == 1) { - /* level - Unsigned */ + } else if (value.tag == 1) { + /* level - Unsigned */ Requested_Shed_Level[object_index].value.level = - value.type.Unsigned_Int; + value.type.Unsigned_Int; status = true; - } else if (value.tag == 2) { - /* amount - REAL */ + } else if (value.tag == 2) { + /* amount - REAL */ Requested_Shed_Level[object_index].value.amount = - value.type.Real; + value.type.Real; status = true; - } else { - /* error! */ + } else { + /* error! */ *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; - case PROP_START_TIME: - if (value.tag == BACNET_APPLICATION_TAG_DATE) { - memcpy(&Start_Time[object_index].date, - &value.type.Date,sizeof(value.type.Date)); + case PROP_START_TIME: + if (value.tag == BACNET_APPLICATION_TAG_DATE) { + memcpy(&Start_Time[object_index].date, + &value.type.Date, sizeof(value.type.Date)); status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - if (!status) - break; - len = bacapp_decode_application_data( - wp_data->application_data + len, - wp_data->application_data_len - len, - &value); - if (len && value.tag == BACNET_APPLICATION_TAG_TIME) { - memcpy(&Start_Time[object_index].time, - &value.type.Time,sizeof(value.type.Time)); + } + if (!status) + break; + len = + bacapp_decode_application_data(wp_data->application_data + len, + wp_data->application_data_len - len, &value); + if (len && value.tag == BACNET_APPLICATION_TAG_TIME) { + memcpy(&Start_Time[object_index].time, + &value.type.Time, sizeof(value.type.Time)); status = true; } else { status = false; *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } + } break; - case PROP_SHED_DURATION: + case PROP_SHED_DURATION: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - Shed_Duration[object_index] = - value.type.Unsigned_Int; + Shed_Duration[object_index] = value.type.Unsigned_Int; status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } + } break; - case PROP_DUTY_WINDOW: + case PROP_DUTY_WINDOW: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - Duty_Window[object_index] = - value.type.Unsigned_Int; + Duty_Window[object_index] = value.type.Unsigned_Int; status = true; } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } + } break; - case PROP_SHED_LEVELS: + case PROP_SHED_LEVELS: if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - /* re-write the size of the array? */ - if (wp_data->array_index == 0) { + /* re-write the size of the array? */ + if (wp_data->array_index == 0) { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - } - else if (wp_data->array_index == BACNET_ARRAY_ALL) { - /* FIXME: write entire array */ - status = true; - } - else if (wp_data->array_index <= MAX_SHED_LEVELS) { - Shed_Levels[object_index][wp_data->array_index-1] = + } else if (wp_data->array_index == BACNET_ARRAY_ALL) { + /* FIXME: write entire array */ + status = true; + } else if (wp_data->array_index <= MAX_SHED_LEVELS) { + Shed_Levels[object_index][wp_data->array_index - 1] = value.type.Unsigned_Int; - status = true; - } else { - } + status = true; + } else { + } } else { *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - case PROP_ENABLE: + } + break; + case PROP_ENABLE: if (value.tag == BACNET_APPLICATION_TAG_BOOLEAN) { - Load_Control_Enable[object_index] = - value.type.Boolean; + Load_Control_Enable[object_index] = value.type.Boolean; status = true; } else { *error_class = ERROR_CLASS_PROPERTY; diff --git a/bacnet-stack/demo/object/lsp.c b/bacnet-stack/demo/object/lsp.c index 1e2c0677..703764f6 100644 --- a/bacnet-stack/demo/object/lsp.c +++ b/bacnet-stack/demo/object/lsp.c @@ -30,7 +30,7 @@ #include #include "bacdef.h" #include "bacdcode.h" -#include "bacenum.h" +#include "bacenum.h" #include "bacapp.h" #include "config.h" /* the custom stuff */ #include "wp.h" @@ -244,8 +244,8 @@ bool Life_Safety_Point_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, { bool status = false; /* return value */ unsigned int object_index = 0; - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; Life_Safety_Point_Init(); if (!Life_Safety_Point_Valid_Instance(wp_data->object_instance)) { @@ -254,12 +254,10 @@ bool Life_Safety_Point_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, 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? */ + 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_MODE: if (value.tag == BACNET_APPLICATION_TAG_ENUMERATED) { diff --git a/bacnet-stack/demo/object/mso.c b/bacnet-stack/demo/object/mso.c index e6cbf2b5..adfb1eea 100644 --- a/bacnet-stack/demo/object/mso.c +++ b/bacnet-stack/demo/object/mso.c @@ -30,7 +30,7 @@ #include #include "bacdef.h" #include "bacdcode.h" -#include "bacenum.h" +#include "bacenum.h" #include "bacapp.h" #include "config.h" /* the custom stuff */ #include "wp.h" @@ -237,15 +237,15 @@ int Multistate_Output_Encode_Property_APDU(uint8_t * apdu, object_index = Multistate_Output_Instance_To_Index(object_instance); if (array_index <= BACNET_MAX_PRIORITY) { - if (Multistate_Output_Level[object_index][array_index-1] == - MULTISTATE_NULL) + if (Multistate_Output_Level[object_index][array_index - + 1] == MULTISTATE_NULL) apdu_len = encode_tagged_null(&apdu[0]); else { present_value = - Multistate_Output_Level[object_index][array_index-1]; + Multistate_Output_Level[object_index][array_index - + 1]; apdu_len = - encode_tagged_unsigned(&apdu[0], - present_value); + encode_tagged_unsigned(&apdu[0], present_value); } } else { *error_class = ERROR_CLASS_PROPERTY; @@ -282,8 +282,8 @@ bool Multistate_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, unsigned int object_index = 0; unsigned int priority = 0; uint32_t level = 0; - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; Multistate_Output_Init(); if (!Multistate_Output_Valid_Instance(wp_data->object_instance)) { @@ -292,12 +292,10 @@ bool Multistate_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, 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? */ + 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_UNSIGNED_INT) { @@ -307,14 +305,14 @@ bool Multistate_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, object. */ if (priority && (priority <= BACNET_MAX_PRIORITY) && (priority != 6 /* reserved */ ) && - (value.type.Unsigned_Int <= - MULTISTATE_NUMBER_OF_STATES)) { + (value.type.Unsigned_Int <= MULTISTATE_NUMBER_OF_STATES)) { level = value.type.Unsigned_Int; object_index = Multistate_Output_Instance_To_Index(wp_data-> object_instance); priority--; - Multistate_Output_Level[object_index][priority] = (uint8_t)level; + Multistate_Output_Level[object_index][priority] = + (uint8_t) level; /* 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 @@ -339,7 +337,8 @@ bool Multistate_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, priority = wp_data->priority; if (priority && (priority <= BACNET_MAX_PRIORITY)) { priority--; - Multistate_Output_Level[object_index][priority] = (uint8_t)level; + Multistate_Output_Level[object_index][priority] = + (uint8_t) level; /* Note: you could set the physical output here to the next highest priority, or to the relinquish default if no priorities are set. diff --git a/bacnet-stack/demo/writeprop/writeprop.c b/bacnet-stack/demo/writeprop/writeprop.c index cede3d72..09241376 100644 --- a/bacnet-stack/demo/writeprop/writeprop.c +++ b/bacnet-stack/demo/writeprop/writeprop.c @@ -162,72 +162,73 @@ int main(int argc, char *argv[]) printf("Usage: %s device-instance object-type object-instance " "property tag value [priority] [index]\r\n", filename_remove_path(argv[0])); - if ((argc > 1) && (strcmp(argv[1],"--help") == 0)) { - printf("device-instance:\r\n" - "BACnet Device Object Instance number that you are trying to\r\n" - "communicate to. This number will be used to try and bind with\r\n" - "the device using Who-Is and I-Am services. For example, if you were\r\n" - "writing to Device Object 123, the device-instance would be 123.\r\n" - "\r\n" - "object-type:\r\n" - "The object type is the integer value of the enumeration\r\n" - "BACNET_OBJECT_TYPE in bacenum.h. It is the object that you are\r\n" - "writing to. For example if you were writing to Analog Output 2, \r\n" - "the object-type would be 1.\r\n" - "\r\n" - "object-instance:\r\n" - "This is the object instance number of the object that you are \r\n" - "writing to. For example, if you were writing to Analog Output 2, \r\n" - "the object-instance would be 2.\r\n" - "\r\n" - "property:\r\n" - "The property is an integer value of the enumeration \r\n" - "BACNET_PROPERTY_ID in bacenum.h. It is the property you are \r\n" - "writing to. For example, if you were writing to the Present Value\r\n" - "property, you would use 85 as the property.\r\n" - "\r\n" - "tag:\r\n" - "Tag is the integer value of the enumeration BACNET_APPLICATION_TAG \r\n" - "in bacenum.h. It is the data type of the value that you are\r\n" - "writing. For example, if you were writing a REAL value, you would \r\n" - "use a tag of 4." - "\r\n" - "value:\r\n" - "The value is an ASCII representation of some type of data that you\r\n" - "are writing. It is encoded using the tag information provided. For\r\n" - "example, if you were writing a REAL value of 100.0, you would use \r\n" - "100.0 as the value.\r\n" - "\r\n" - "[priority]:\r\n" - "This optional parameter is used for setting the priority of the\r\n" - "write. If no priority is given, none is sent, and the BACnet \r\n" - "standard requires that the value is written at the lowest \r\n" - "priority (16) if the object property supports priorities.\r\n" - "\r\n" - "[index]\r\n" - "This optional integer parameter is the index number of an array.\r\n" - "If the property is an array, individual elements can be written\r\n" - "to if supported.\r\n" - "\r\n" - "Here is a brief overview of BACnet property and tags:\r\n" - "Certain properties are expected to be written with certain \r\n" - "application tags, so you probably need to know which ones to use\r\n" - "with each property of each object. It is almost safe to say that\r\n" - "given a property and an object and a table, the tag could be looked\r\n" - "up automatically. There may be a few exceptions to this, such as\r\n" - "the Any property type in the schedule object and the Present Value\r\n" - "accepting REAL, BOOLEAN, NULL, etc. Perhaps it would be simpler for\r\n" - "the demo to use this kind of table - but I also wanted to be able\r\n" - "to do negative testing by passing the wrong tag and have the server\r\n" - "return a reject message.\r\n" - "\r\n" - "Example:\r\n" - "If you want send a 100 to the Present-Value in the Analog Output\r\n" - "at priority 16, you could send the following command:\r\n" - "%s 123 1 0 85 4 100\r\n" - "You could also send a relinquish command:\r\n" - "%s 123 1 0 85 0 0\r\n", - filename_remove_path(argv[0]), filename_remove_path(argv[0])); + if ((argc > 1) && (strcmp(argv[1], "--help") == 0)) { + printf("device-instance:\r\n" + "BACnet Device Object Instance number that you are trying to\r\n" + "communicate to. This number will be used to try and bind with\r\n" + "the device using Who-Is and I-Am services. For example, if you were\r\n" + "writing to Device Object 123, the device-instance would be 123.\r\n" + "\r\n" + "object-type:\r\n" + "The object type is the integer value of the enumeration\r\n" + "BACNET_OBJECT_TYPE in bacenum.h. It is the object that you are\r\n" + "writing to. For example if you were writing to Analog Output 2, \r\n" + "the object-type would be 1.\r\n" + "\r\n" + "object-instance:\r\n" + "This is the object instance number of the object that you are \r\n" + "writing to. For example, if you were writing to Analog Output 2, \r\n" + "the object-instance would be 2.\r\n" + "\r\n" + "property:\r\n" + "The property is an integer value of the enumeration \r\n" + "BACNET_PROPERTY_ID in bacenum.h. It is the property you are \r\n" + "writing to. For example, if you were writing to the Present Value\r\n" + "property, you would use 85 as the property.\r\n" + "\r\n" + "tag:\r\n" + "Tag is the integer value of the enumeration BACNET_APPLICATION_TAG \r\n" + "in bacenum.h. It is the data type of the value that you are\r\n" + "writing. For example, if you were writing a REAL value, you would \r\n" + "use a tag of 4." + "\r\n" + "value:\r\n" + "The value is an ASCII representation of some type of data that you\r\n" + "are writing. It is encoded using the tag information provided. For\r\n" + "example, if you were writing a REAL value of 100.0, you would use \r\n" + "100.0 as the value.\r\n" + "\r\n" + "[priority]:\r\n" + "This optional parameter is used for setting the priority of the\r\n" + "write. If no priority is given, none is sent, and the BACnet \r\n" + "standard requires that the value is written at the lowest \r\n" + "priority (16) if the object property supports priorities.\r\n" + "\r\n" + "[index]\r\n" + "This optional integer parameter is the index number of an array.\r\n" + "If the property is an array, individual elements can be written\r\n" + "to if supported.\r\n" + "\r\n" + "Here is a brief overview of BACnet property and tags:\r\n" + "Certain properties are expected to be written with certain \r\n" + "application tags, so you probably need to know which ones to use\r\n" + "with each property of each object. It is almost safe to say that\r\n" + "given a property and an object and a table, the tag could be looked\r\n" + "up automatically. There may be a few exceptions to this, such as\r\n" + "the Any property type in the schedule object and the Present Value\r\n" + "accepting REAL, BOOLEAN, NULL, etc. Perhaps it would be simpler for\r\n" + "the demo to use this kind of table - but I also wanted to be able\r\n" + "to do negative testing by passing the wrong tag and have the server\r\n" + "return a reject message.\r\n" + "\r\n" + "Example:\r\n" + "If you want send a 100 to the Present-Value in the Analog Output\r\n" + "at priority 16, you could send the following command:\r\n" + "%s 123 1 0 85 4 100\r\n" + "You could also send a relinquish command:\r\n" + "%s 123 1 0 85 0 0\r\n", + filename_remove_path(argv[0]), + filename_remove_path(argv[0])); } return 0; } diff --git a/bacnet-stack/iam.c b/bacnet-stack/iam.c index f9ed4923..5ae007fe 100755 --- a/bacnet-stack/iam.c +++ b/bacnet-stack/iam.c @@ -218,12 +218,9 @@ void testIAm(Test * pTest) #ifdef TEST_IAM /* dummy function stubs */ -int datalink_send_pdu( - BACNET_ADDRESS * dest, - BACNET_NPDU_DATA * npdu_data, - uint8_t * pdu, - unsigned pdu_len) -{ +int datalink_send_pdu(BACNET_ADDRESS * dest, + BACNET_NPDU_DATA * npdu_data, uint8_t * pdu, unsigned pdu_len) +{ (void) dest; (void) npdu_data; (void) pdu; diff --git a/bacnet-stack/npdu.c b/bacnet-stack/npdu.c index de925f39..03a37f61 100644 --- a/bacnet-stack/npdu.c +++ b/bacnet-stack/npdu.c @@ -337,7 +337,8 @@ void npdu_handler(BACNET_ADDRESS * src, /* source address */ } else if ((apdu_offset > 0) && (apdu_offset <= pdu_len)) { /* only handle the version that we know how to handle */ if (npdu_data.protocol_version == BACNET_PROTOCOL_VERSION) - apdu_handler(src, &pdu[apdu_offset], (uint16_t)(pdu_len - apdu_offset)); + apdu_handler(src, &pdu[apdu_offset], + (uint16_t) (pdu_len - apdu_offset)); } return; diff --git a/bacnet-stack/ports/pic18f6720/device.c b/bacnet-stack/ports/pic18f6720/device.c index 7e37e924..fbf2b2bb 100644 --- a/bacnet-stack/ports/pic18f6720/device.c +++ b/bacnet-stack/ports/pic18f6720/device.c @@ -1,567 +1,567 @@ -/************************************************************************** -* -* Copyright (C) 2007 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -#include -#include -#include /* for memmove */ -#include "bacdef.h" -#include "bacdcode.h" -#include "bacstr.h" -#include "bacenum.h" -#include "config.h" /* the custom stuff */ -#include "apdu.h" -#include "device.h" /* me */ -#include "dlmstp.h" -#include "rs485.h" -#include "ai.h" -#include "bi.h" -#include "bv.h" -#include "wp.h" -#include "dcc.h" - -/* note: you really only need to define variables for - properties that are writable or that may change. - The properties that are constant can be hard coded - into the read-property encoding. */ -static uint32_t Object_Instance_Number = 12345; -static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; - -BACNET_REINITIALIZED_STATE_OF_DEVICE Reinitialize_State = - REINITIALIZED_STATE_IDLE; - -void Device_Reinit(void) -{ - dcc_set_status_duration(COMMUNICATION_ENABLE,0); - Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); -} - -void Device_Init(void) -{ - Reinitialize_State = REINITIALIZED_STATE_IDLE; - dcc_set_status_duration(COMMUNICATION_ENABLE,0); - /* FIXME: Get the data from the eeprom */ - /* I2C_Read_Block(EEPROM_DEVICE_ADDRESS, - (char *)&Object_Instance_Number, - sizeof(Object_Instance_Number), - EEPROM_BACNET_ID_ADDR); */ -} - -/* methods to manipulate the data */ -uint32_t Device_Object_Instance_Number(void) -{ - return Object_Instance_Number; -} - -bool Device_Set_Object_Instance_Number(uint32_t object_id) -{ - bool status = true; /* return value */ - - if (object_id <= BACNET_MAX_INSTANCE) - { - Object_Instance_Number = object_id; - /* FIXME: Write the data to the eeprom */ - /* I2C_Write_Block( - EEPROM_DEVICE_ADDRESS, - (char *)&Object_Instance_Number, - sizeof(Object_Instance_Number), - EEPROM_BACNET_ID_ADDR); */ - } - else - status = false; - - return status; -} - -bool Device_Valid_Object_Instance_Number(uint32_t object_id) -{ - /* BACnet allows for a wildcard instance number */ - return ((Object_Instance_Number == object_id) || - (object_id == BACNET_MAX_INSTANCE)); -} - -BACNET_DEVICE_STATUS Device_System_Status(void) -{ - return System_Status; -} - -void Device_Set_System_Status(BACNET_DEVICE_STATUS status) -{ - if (status < MAX_DEVICE_STATUS) - System_Status = status; -} - -/* FIXME: put your vendor ID here! */ -uint16_t Device_Vendor_Identifier(void) -{ - return 0; -} - -uint8_t Device_Protocol_Version(void) -{ - return 1; -} - -uint8_t Device_Protocol_Revision(void) -{ - return 5; -} - -/* FIXME: MAX_APDU is defined in config.ini - set it! */ -uint16_t Device_Max_APDU_Length_Accepted(void) -{ - return MAX_APDU; -} - -BACNET_SEGMENTATION Device_Segmentation_Supported(void) -{ - return SEGMENTATION_NONE; -} - -uint16_t Device_APDU_Timeout(void) -{ - return 60000; -} - - -uint8_t Device_Number_Of_APDU_Retries(void) -{ - return 0; -} - -uint8_t Device_Database_Revision(void) -{ - return 0; -} - -/* Since many network clients depend on the object list */ -/* for discovery, it must be consistent! */ -unsigned Device_Object_List_Count(void) -{ - unsigned count = 1;/* at least 1 for device object */ - -/* FIXME: add objects as needed */ -#if 0 - count += Binary_Value_Count(); - count += Analog_Input_Count(); - count += Binary_Input_Count(); -#endif - - return count; -} - -/* Since many network clients depend on the object list */ -/* for discovery, it must be consistent! */ -bool Device_Object_List_Identifier(unsigned array_index, - int *object_type, uint32_t * instance) -{ - bool status = false; - unsigned object_index = 0; - unsigned object_count = 0; - - /* device object */ - if (array_index == 1) { - *object_type = OBJECT_DEVICE; - *instance = Object_Instance_Number; - status = true; - } - #if 0 - /* FIXME: add objects as needed */ - /* binary input objects */ - if (!status) { - /* normalize the index since - we know it is not the previous objects */ - /* array index starts at 1, and 1 for the device object */ - object_index = array_index - 2; - object_count = Binary_Value_Count(); - /* is it a valid index for this object? */ - if (object_index < object_count) { - *object_type = OBJECT_BINARY_VALUE; - *instance = Binary_Value_Index_To_Instance(object_index); - status = true; - } - } - /* analog input objects */ - if (!status) { - /* array index starts at 1, and 1 for the device object */ - object_index -= object_count; - object_count = Analog_Input_Count(); - if (object_index < object_count) { - *object_type = OBJECT_ANALOG_INPUT; - *instance = Analog_Input_Index_To_Instance(object_index); - status = true; - } - } - /* binary input objects */ - if (!status) { - /* normalize the index since - we know it is not the previous objects */ - object_index -= object_count; - object_count = Binary_Input_Count(); - /* is it a valid index for this object? */ - if (object_index < object_count) { - *object_type = OBJECT_BINARY_INPUT; - *instance = Binary_Input_Index_To_Instance(object_index); - status = true; - } - } - #endif - - return status; -} - -/* return the length of the apdu encoded or -1 for error */ -int Device_Encode_Property_APDU(uint8_t * apdu, - BACNET_PROPERTY_ID property, - int32_t array_index, - BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) -{ - int apdu_len = 0; /* return value */ - int len = 0; /* apdu len intermediate value */ - BACNET_BIT_STRING bit_string; - BACNET_CHARACTER_STRING char_string; - unsigned i = 0; - int object_type = 0; - uint32_t instance = 0; - unsigned count = 0; - BACNET_TIME local_time; - BACNET_DATE local_date; - uint8_t year = 0; - char string_buffer[24]; - int16_t TimeZone = 0; - - /* FIXME: change the hardcoded names to suit your application */ - switch (property) { - case PROP_OBJECT_IDENTIFIER: - apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_DEVICE, - Object_Instance_Number); - break; - case PROP_OBJECT_NAME: - (void)strcpypgm2ram(&string_buffer[0], "PIC18F6720 Device"); - characterstring_init_ansi(&char_string, string_buffer); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_OBJECT_TYPE: - apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_DEVICE); - break; - case PROP_DESCRIPTION: - (void)strcpypgm2ram(&string_buffer[0], "BACnet Demo"); - characterstring_init_ansi(&char_string, string_buffer); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_SYSTEM_STATUS: - apdu_len = encode_tagged_enumerated(&apdu[0], Device_System_Status()); - break; - case PROP_VENDOR_NAME: - (void)strcpypgm2ram(&string_buffer[0], "ASHRAE"); - characterstring_init_ansi(&char_string, string_buffer); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_VENDOR_IDENTIFIER: - apdu_len = encode_tagged_unsigned(&apdu[0], Device_Vendor_Identifier()); - break; - case PROP_MODEL_NAME: - (void)strcpypgm2ram(&string_buffer[0], "GNU Demo"); - characterstring_init_ansi(&char_string, string_buffer); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_FIRMWARE_REVISION: - (void)strcpypgm2ram(&string_buffer[0], "1.00"); - characterstring_init_ansi(&char_string, string_buffer); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_APPLICATION_SOFTWARE_VERSION: - (void)strcpypgm2ram(&string_buffer[0], "1.00"); - characterstring_init_ansi(&char_string, string_buffer); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_LOCATION: - (void)strcpypgm2ram(&string_buffer[0], "USA"); - characterstring_init_ansi(&char_string, string_buffer); - apdu_len = encode_tagged_character_string(&apdu[0], &char_string); - break; - case PROP_PROTOCOL_VERSION: - apdu_len = - encode_tagged_unsigned(&apdu[0], Device_Protocol_Version()); - break; - case PROP_PROTOCOL_REVISION: - apdu_len = - encode_tagged_unsigned(&apdu[0], Device_Protocol_Revision()); - break; - /* BACnet Legacy Support */ - case PROP_PROTOCOL_CONFORMANCE_CLASS: - apdu_len = encode_tagged_unsigned(&apdu[0], 1); - break; - case PROP_PROTOCOL_SERVICES_SUPPORTED: - /* Note: list of services that are executed, not initiated. */ - bitstring_init(&bit_string); - for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) { - /* automatic lookup based on handlers set */ - bitstring_set_bit(&bit_string, (uint8_t) i, - apdu_service_supported(i)); - } - apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); - break; - case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: - /* Note: this is the list of objects that can be in this device, - not a list of objects that this device can access */ - bitstring_init(&bit_string); - for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { - /* initialize all the object types to not-supported */ - bitstring_set_bit(&bit_string, (uint8_t) i, false); - } - /* FIXME: indicate the objects that YOU support */ - bitstring_set_bit(&bit_string, OBJECT_DEVICE, true); - #if 0 - bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true); - bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true); - bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true); - #endif - apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); - break; - case PROP_OBJECT_LIST: - count = Device_Object_List_Count(); - /* Array element zero is the number of objects in the list */ - if (array_index == BACNET_ARRAY_LENGTH_INDEX) - apdu_len = encode_tagged_unsigned(&apdu[0], count); - /* if no index was specified, then try to encode the entire list */ - /* into one packet. Note that more than likely you will have */ - /* to return an error if the number of encoded objects exceeds */ - /* your maximum APDU size. */ - else if (array_index == BACNET_ARRAY_ALL) { - for (i = 1; i <= count; i++) { - if (Device_Object_List_Identifier(i, &object_type, - &instance)) { - len = - encode_tagged_object_id(&apdu[apdu_len], - object_type, instance); - apdu_len += len; - /* assume next one is the same size as this one */ - /* can we all fit into the APDU? */ - if ((apdu_len + len) >= MAX_APDU) { - *error_class = ERROR_CLASS_SERVICES; - *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; - apdu_len = -1; - break; - } - } else { - /* error: internal error? */ - *error_class = ERROR_CLASS_SERVICES; - *error_code = ERROR_CODE_OTHER; - apdu_len = -1; - break; - } - } - } else { - if (Device_Object_List_Identifier(array_index, &object_type, - &instance)) - apdu_len = - encode_tagged_object_id(&apdu[0], object_type, - instance); - else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; - apdu_len = -1; - } - } - break; - case PROP_MAX_APDU_LENGTH_ACCEPTED: - apdu_len = encode_tagged_unsigned(&apdu[0], - Device_Max_APDU_Length_Accepted()); - break; - case PROP_SEGMENTATION_SUPPORTED: - apdu_len = encode_tagged_enumerated(&apdu[0], - Device_Segmentation_Supported()); - break; - case PROP_APDU_TIMEOUT: - apdu_len = encode_tagged_unsigned(&apdu[0], Device_APDU_Timeout()); - break; - case PROP_NUMBER_OF_APDU_RETRIES: - apdu_len = - encode_tagged_unsigned(&apdu[0], Device_Number_Of_APDU_Retries()); - break; - case PROP_DEVICE_ADDRESS_BINDING: - /* FIXME: encode the list here, if it exists */ - break; - case PROP_DATABASE_REVISION: - apdu_len = encode_tagged_unsigned(&apdu[0], Device_Database_Revision()); - break; - case PROP_MAX_INFO_FRAMES: - apdu_len = encode_tagged_unsigned(&apdu[0], dlmstp_max_info_frames()); - break; - case PROP_MAX_MASTER: - apdu_len = encode_tagged_unsigned(&apdu[0], dlmstp_max_master()); - 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_tagged_time(&apdu[0], &local_time); - break; - case PROP_UTC_OFFSET: - /* Note: BACnet Time Zone is inverse of everybody else */ - apdu_len = encode_tagged_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_tagged_date(&apdu[0], &local_date); - break; - case PROP_DAYLIGHT_SAVINGS_STATUS: - /* FIXME: if you support time/date */ - apdu_len = encode_tagged_boolean(&apdu[0], false); - break; - case 9600: - apdu_len = encode_tagged_unsigned(&apdu[0], RS485_Get_Baud_Rate()); - break; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_UNKNOWN_PROPERTY; - apdu_len = -1; - break; - } - - return apdu_len; -} - -bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, - BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) -{ - bool status = false; /* return value */ - int len = 0; - BACNET_APPLICATION_DATA_VALUE value; - - if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) { - *error_class = ERROR_CLASS_OBJECT; - *error_code = ERROR_CODE_UNKNOWN_OBJECT; - return false; - } - /* decode the some of the request */ - len = bacapp_decode_application_data( - wp_data->application_data, - wp_data->application_data_len, - &value); - /* FIXME: len < application_data_len: more data? */ - /* FIXME: len == 0: unable to decode? */ - switch (wp_data->object_property) { - case PROP_OBJECT_IDENTIFIER: - if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) { - if ((value.type.Object_Id.type == OBJECT_DEVICE) && - (Device_Set_Object_Instance_Number(value.type. - Object_Id.instance))) { - /* we could send an I-Am broadcast to let the world know */ - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - case PROP_MAX_INFO_FRAMES: - if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - if (value.type.Unsigned_Int <= 255) { - dlmstp_set_max_info_frames(value.type.Unsigned_Int); - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - case PROP_MAX_MASTER: - if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - if ((value.type.Unsigned_Int > 0) && - (value.type.Unsigned_Int <= 127)) { - dlmstp_set_max_master(value.type.Unsigned_Int); - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - case PROP_OBJECT_NAME: - if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { - uint8_t encoding; - size_t len; - - encoding = - characterstring_encoding(&value.type.Character_String); - len = characterstring_length(&value.type.Character_String); - if (encoding == CHARACTER_ANSI_X34) { - if (len <= 20) { - /* FIXME: set the name */ - /* Display_Set_Name( - characterstring_value(&value.type.Character_String)); */ - - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - case 9600: - if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { - if (value.type.Unsigned_Int > 115200) { - RS485_Set_Baud_Rate(value.type.Unsigned_Int); - status = true; - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; - } - } else { - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_INVALID_DATA_TYPE; - } - break; - default: - *error_class = ERROR_CLASS_PROPERTY; - *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; - break; - } - - return status; -} - +/************************************************************************** +* +* Copyright (C) 2007 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +#include +#include +#include /* for memmove */ +#include "bacdef.h" +#include "bacdcode.h" +#include "bacstr.h" +#include "bacenum.h" +#include "config.h" /* the custom stuff */ +#include "apdu.h" +#include "device.h" /* me */ +#include "dlmstp.h" +#include "rs485.h" +#include "ai.h" +#include "bi.h" +#include "bv.h" +#include "wp.h" +#include "dcc.h" + +/* note: you really only need to define variables for + properties that are writable or that may change. + The properties that are constant can be hard coded + into the read-property encoding. */ +static uint32_t Object_Instance_Number = 12345; +static BACNET_DEVICE_STATUS System_Status = STATUS_OPERATIONAL; + +BACNET_REINITIALIZED_STATE_OF_DEVICE Reinitialize_State = + REINITIALIZED_STATE_IDLE; + +void Device_Reinit(void) +{ + dcc_set_status_duration(COMMUNICATION_ENABLE, 0); + Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); +} + +void Device_Init(void) +{ + Reinitialize_State = REINITIALIZED_STATE_IDLE; + dcc_set_status_duration(COMMUNICATION_ENABLE, 0); + /* FIXME: Get the data from the eeprom */ + /* I2C_Read_Block(EEPROM_DEVICE_ADDRESS, + (char *)&Object_Instance_Number, + sizeof(Object_Instance_Number), + EEPROM_BACNET_ID_ADDR); */ +} + +/* methods to manipulate the data */ +uint32_t Device_Object_Instance_Number(void) +{ + return Object_Instance_Number; +} + +bool Device_Set_Object_Instance_Number(uint32_t object_id) +{ + bool status = true; /* return value */ + + if (object_id <= BACNET_MAX_INSTANCE) { + Object_Instance_Number = object_id; + /* FIXME: Write the data to the eeprom */ + /* I2C_Write_Block( + EEPROM_DEVICE_ADDRESS, + (char *)&Object_Instance_Number, + sizeof(Object_Instance_Number), + EEPROM_BACNET_ID_ADDR); */ + } else + status = false; + + return status; +} + +bool Device_Valid_Object_Instance_Number(uint32_t object_id) +{ + /* BACnet allows for a wildcard instance number */ + return ((Object_Instance_Number == object_id) || + (object_id == BACNET_MAX_INSTANCE)); +} + +BACNET_DEVICE_STATUS Device_System_Status(void) +{ + return System_Status; +} + +void Device_Set_System_Status(BACNET_DEVICE_STATUS status) +{ + if (status < MAX_DEVICE_STATUS) + System_Status = status; +} + +/* FIXME: put your vendor ID here! */ +uint16_t Device_Vendor_Identifier(void) +{ + return 0; +} + +uint8_t Device_Protocol_Version(void) +{ + return 1; +} + +uint8_t Device_Protocol_Revision(void) +{ + return 5; +} + +/* FIXME: MAX_APDU is defined in config.ini - set it! */ +uint16_t Device_Max_APDU_Length_Accepted(void) +{ + return MAX_APDU; +} + +BACNET_SEGMENTATION Device_Segmentation_Supported(void) +{ + return SEGMENTATION_NONE; +} + +uint16_t Device_APDU_Timeout(void) +{ + return 60000; +} + + +uint8_t Device_Number_Of_APDU_Retries(void) +{ + return 0; +} + +uint8_t Device_Database_Revision(void) +{ + return 0; +} + +/* Since many network clients depend on the object list */ +/* for discovery, it must be consistent! */ +unsigned Device_Object_List_Count(void) +{ + unsigned count = 1; /* at least 1 for device object */ + +/* FIXME: add objects as needed */ +#if 0 + count += Binary_Value_Count(); + count += Analog_Input_Count(); + count += Binary_Input_Count(); +#endif + + return count; +} + +/* Since many network clients depend on the object list */ +/* for discovery, it must be consistent! */ +bool Device_Object_List_Identifier(unsigned array_index, + int *object_type, uint32_t * instance) +{ + bool status = false; + unsigned object_index = 0; + unsigned object_count = 0; + + /* device object */ + if (array_index == 1) { + *object_type = OBJECT_DEVICE; + *instance = Object_Instance_Number; + status = true; + } +#if 0 + /* FIXME: add objects as needed */ + /* binary input objects */ + if (!status) { + /* normalize the index since + we know it is not the previous objects */ + /* array index starts at 1, and 1 for the device object */ + object_index = array_index - 2; + object_count = Binary_Value_Count(); + /* is it a valid index for this object? */ + if (object_index < object_count) { + *object_type = OBJECT_BINARY_VALUE; + *instance = Binary_Value_Index_To_Instance(object_index); + status = true; + } + } + /* analog input objects */ + if (!status) { + /* array index starts at 1, and 1 for the device object */ + object_index -= object_count; + object_count = Analog_Input_Count(); + if (object_index < object_count) { + *object_type = OBJECT_ANALOG_INPUT; + *instance = Analog_Input_Index_To_Instance(object_index); + status = true; + } + } + /* binary input objects */ + if (!status) { + /* normalize the index since + we know it is not the previous objects */ + object_index -= object_count; + object_count = Binary_Input_Count(); + /* is it a valid index for this object? */ + if (object_index < object_count) { + *object_type = OBJECT_BINARY_INPUT; + *instance = Binary_Input_Index_To_Instance(object_index); + status = true; + } + } +#endif + + return status; +} + +/* return the length of the apdu encoded or -1 for error */ +int Device_Encode_Property_APDU(uint8_t * apdu, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) +{ + int apdu_len = 0; /* return value */ + int len = 0; /* apdu len intermediate value */ + BACNET_BIT_STRING bit_string; + BACNET_CHARACTER_STRING char_string; + unsigned i = 0; + int object_type = 0; + uint32_t instance = 0; + unsigned count = 0; + BACNET_TIME local_time; + BACNET_DATE local_date; + uint8_t year = 0; + char string_buffer[24]; + int16_t TimeZone = 0; + + /* FIXME: change the hardcoded names to suit your application */ + switch (property) { + case PROP_OBJECT_IDENTIFIER: + apdu_len = encode_tagged_object_id(&apdu[0], OBJECT_DEVICE, + Object_Instance_Number); + break; + case PROP_OBJECT_NAME: + (void) strcpypgm2ram(&string_buffer[0], "PIC18F6720 Device"); + characterstring_init_ansi(&char_string, string_buffer); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_OBJECT_TYPE: + apdu_len = encode_tagged_enumerated(&apdu[0], OBJECT_DEVICE); + break; + case PROP_DESCRIPTION: + (void) strcpypgm2ram(&string_buffer[0], "BACnet Demo"); + characterstring_init_ansi(&char_string, string_buffer); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_SYSTEM_STATUS: + apdu_len = + encode_tagged_enumerated(&apdu[0], Device_System_Status()); + break; + case PROP_VENDOR_NAME: + (void) strcpypgm2ram(&string_buffer[0], "ASHRAE"); + characterstring_init_ansi(&char_string, string_buffer); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_VENDOR_IDENTIFIER: + apdu_len = + encode_tagged_unsigned(&apdu[0], Device_Vendor_Identifier()); + break; + case PROP_MODEL_NAME: + (void) strcpypgm2ram(&string_buffer[0], "GNU Demo"); + characterstring_init_ansi(&char_string, string_buffer); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_FIRMWARE_REVISION: + (void) strcpypgm2ram(&string_buffer[0], "1.00"); + characterstring_init_ansi(&char_string, string_buffer); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_APPLICATION_SOFTWARE_VERSION: + (void) strcpypgm2ram(&string_buffer[0], "1.00"); + characterstring_init_ansi(&char_string, string_buffer); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_LOCATION: + (void) strcpypgm2ram(&string_buffer[0], "USA"); + characterstring_init_ansi(&char_string, string_buffer); + apdu_len = encode_tagged_character_string(&apdu[0], &char_string); + break; + case PROP_PROTOCOL_VERSION: + apdu_len = + encode_tagged_unsigned(&apdu[0], Device_Protocol_Version()); + break; + case PROP_PROTOCOL_REVISION: + apdu_len = + encode_tagged_unsigned(&apdu[0], Device_Protocol_Revision()); + break; + /* BACnet Legacy Support */ + case PROP_PROTOCOL_CONFORMANCE_CLASS: + apdu_len = encode_tagged_unsigned(&apdu[0], 1); + break; + case PROP_PROTOCOL_SERVICES_SUPPORTED: + /* Note: list of services that are executed, not initiated. */ + bitstring_init(&bit_string); + for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) { + /* automatic lookup based on handlers set */ + bitstring_set_bit(&bit_string, (uint8_t) i, + apdu_service_supported(i)); + } + apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); + break; + case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: + /* Note: this is the list of objects that can be in this device, + not a list of objects that this device can access */ + bitstring_init(&bit_string); + for (i = 0; i < MAX_ASHRAE_OBJECT_TYPE; i++) { + /* initialize all the object types to not-supported */ + bitstring_set_bit(&bit_string, (uint8_t) i, false); + } + /* FIXME: indicate the objects that YOU support */ + bitstring_set_bit(&bit_string, OBJECT_DEVICE, true); +#if 0 + bitstring_set_bit(&bit_string, OBJECT_BINARY_VALUE, true); + bitstring_set_bit(&bit_string, OBJECT_ANALOG_INPUT, true); + bitstring_set_bit(&bit_string, OBJECT_BINARY_INPUT, true); +#endif + apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); + break; + case PROP_OBJECT_LIST: + count = Device_Object_List_Count(); + /* Array element zero is the number of objects in the list */ + if (array_index == BACNET_ARRAY_LENGTH_INDEX) + apdu_len = encode_tagged_unsigned(&apdu[0], count); + /* if no index was specified, then try to encode the entire list */ + /* into one packet. Note that more than likely you will have */ + /* to return an error if the number of encoded objects exceeds */ + /* your maximum APDU size. */ + else if (array_index == BACNET_ARRAY_ALL) { + for (i = 1; i <= count; i++) { + if (Device_Object_List_Identifier(i, &object_type, + &instance)) { + len = + encode_tagged_object_id(&apdu[apdu_len], + object_type, instance); + apdu_len += len; + /* assume next one is the same size as this one */ + /* can we all fit into the APDU? */ + if ((apdu_len + len) >= MAX_APDU) { + *error_class = ERROR_CLASS_SERVICES; + *error_code = ERROR_CODE_NO_SPACE_FOR_OBJECT; + apdu_len = -1; + break; + } + } else { + /* error: internal error? */ + *error_class = ERROR_CLASS_SERVICES; + *error_code = ERROR_CODE_OTHER; + apdu_len = -1; + break; + } + } + } else { + if (Device_Object_List_Identifier(array_index, &object_type, + &instance)) + apdu_len = + encode_tagged_object_id(&apdu[0], object_type, + instance); + else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_ARRAY_INDEX; + apdu_len = -1; + } + } + break; + case PROP_MAX_APDU_LENGTH_ACCEPTED: + apdu_len = encode_tagged_unsigned(&apdu[0], + Device_Max_APDU_Length_Accepted()); + break; + case PROP_SEGMENTATION_SUPPORTED: + apdu_len = encode_tagged_enumerated(&apdu[0], + Device_Segmentation_Supported()); + break; + case PROP_APDU_TIMEOUT: + apdu_len = encode_tagged_unsigned(&apdu[0], Device_APDU_Timeout()); + break; + case PROP_NUMBER_OF_APDU_RETRIES: + apdu_len = + encode_tagged_unsigned(&apdu[0], + Device_Number_Of_APDU_Retries()); + break; + case PROP_DEVICE_ADDRESS_BINDING: + /* FIXME: encode the list here, if it exists */ + break; + case PROP_DATABASE_REVISION: + apdu_len = + encode_tagged_unsigned(&apdu[0], Device_Database_Revision()); + break; + case PROP_MAX_INFO_FRAMES: + apdu_len = + encode_tagged_unsigned(&apdu[0], dlmstp_max_info_frames()); + break; + case PROP_MAX_MASTER: + apdu_len = encode_tagged_unsigned(&apdu[0], dlmstp_max_master()); + 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_tagged_time(&apdu[0], &local_time); + break; + case PROP_UTC_OFFSET: + /* Note: BACnet Time Zone is inverse of everybody else */ + apdu_len = encode_tagged_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_tagged_date(&apdu[0], &local_date); + break; + case PROP_DAYLIGHT_SAVINGS_STATUS: + /* FIXME: if you support time/date */ + apdu_len = encode_tagged_boolean(&apdu[0], false); + break; + case 9600: + apdu_len = encode_tagged_unsigned(&apdu[0], RS485_Get_Baud_Rate()); + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_UNKNOWN_PROPERTY; + apdu_len = -1; + break; + } + + return apdu_len; +} + +bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, + BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code) +{ + bool status = false; /* return value */ + int len = 0; + BACNET_APPLICATION_DATA_VALUE value; + + if (!Device_Valid_Object_Instance_Number(wp_data->object_instance)) { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + return false; + } + /* decode the some of the request */ + len = bacapp_decode_application_data(wp_data->application_data, + wp_data->application_data_len, &value); + /* FIXME: len < application_data_len: more data? */ + /* FIXME: len == 0: unable to decode? */ + switch (wp_data->object_property) { + case PROP_OBJECT_IDENTIFIER: + if (value.tag == BACNET_APPLICATION_TAG_OBJECT_ID) { + if ((value.type.Object_Id.type == OBJECT_DEVICE) && + (Device_Set_Object_Instance_Number(value.type. + Object_Id.instance))) { + /* we could send an I-Am broadcast to let the world know */ + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_MAX_INFO_FRAMES: + if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { + if (value.type.Unsigned_Int <= 255) { + dlmstp_set_max_info_frames(value.type.Unsigned_Int); + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_MAX_MASTER: + if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { + if ((value.type.Unsigned_Int > 0) && + (value.type.Unsigned_Int <= 127)) { + dlmstp_set_max_master(value.type.Unsigned_Int); + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case PROP_OBJECT_NAME: + if (value.tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) { + uint8_t encoding; + size_t len; + + encoding = + characterstring_encoding(&value.type.Character_String); + len = characterstring_length(&value.type.Character_String); + if (encoding == CHARACTER_ANSI_X34) { + if (len <= 20) { + /* FIXME: set the name */ + /* Display_Set_Name( + characterstring_value(&value.type.Character_String)); */ + + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_NO_SPACE_TO_WRITE_PROPERTY; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_CHARACTER_SET_NOT_SUPPORTED; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + case 9600: + if (value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) { + if (value.type.Unsigned_Int > 115200) { + RS485_Set_Baud_Rate(value.type.Unsigned_Int); + status = true; + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_VALUE_OUT_OF_RANGE; + } + } else { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + default: + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; + break; + } + + return status; +} diff --git a/bacnet-stack/ports/pic18f6720/dlmstp.c b/bacnet-stack/ports/pic18f6720/dlmstp.c index e1676dee..1416a9be 100644 --- a/bacnet-stack/ports/pic18f6720/dlmstp.c +++ b/bacnet-stack/ports/pic18f6720/dlmstp.c @@ -1,370 +1,361 @@ -/************************************************************************** -* -* 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. -* -*********************************************************************/ -#include -#include -#include -#include -#if PRINT_ENABLED -#include -#endif -#include "bacdef.h" -#include "mstp.h" -#include "dlmstp.h" -#include "rs485.h" -#include "npdu.h" - -// Number of MS/TP Packets Rx/Tx -uint16_t MSTP_Packets = 0; - -/* receive buffer */ -#pragma udata MSTP_RxData -static DLMSTP_PACKET Receive_Buffer; -/* temp buffer for NPDU insertion */ -/* local MS/TP port data - shared with RS-485 */ -#pragma udata MSTP_PortData -volatile struct mstp_port_struct_t MSTP_Port; -#pragma udata - -#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;} - -// This defines the number of edit fields for this module -#define MAX_EDIT_FIELD 1 -static uint8_t EditField = 0; -/* ************************************************************************* - DESCRIPTION: This function handles incrementing or decrementing our - EditField - RETURN: none - ALGORITHM: none - NOTES: Pass a #>0 to increment #<0 to decrement - *************************************************************************** */ -void dlmstp_SetEditField( - signed char state) /* direction our editfield is moving */ -{ - if (state > 0) - { - if (++EditField > MAX_EDIT_FIELD) - EditField = 0; - } - else if (state < 0) - { - if (EditField) - EditField--; - else - EditField = MAX_EDIT_FIELD; - } - else - EditField = 0; -} - -/* ************************************************************************* - DESCRIPTION: Gets the current edit field for this module - RETURN: the current edit field - ALGORITHM: none - NOTES: none - *************************************************************************** */ -uint8_t dlmstp_GetEditField(void) -{ - return (EditField); -} - -void dlmstp_millisecond_timer(void) -{ - INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer); -} - -void dlmstp_reinit(void) -{ - RS485_Reinit(); - dlmstp_set_my_address(DEFAULT_MAC_ADDRESS); - dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); - dlmstp_set_max_master(DEFAULT_MAX_MASTER); -} - -void dlmstp_init(void) -{ - uint8_t data; - - /* initialize buffer */ - Receive_Buffer.ready = false; - Receive_Buffer.pdu_len = 0; - /* initialize hardware */ - RS485_Initialize(); - MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0]; - MSTP_Init(&MSTP_Port); - /* FIXME: implement your data storage */ - data = 64; /* I2C_Read_Byte( - EEPROM_DEVICE_ADDRESS, - EEPROM_MSTP_MAC_ADDR); */ - if (data <= 127) - MSTP_Port.This_Station = data; - else - dlmstp_set_my_address(DEFAULT_MAC_ADDRESS); - /* FIXME: implement your data storage */ - data = 127; /* I2C_Read_Byte( - EEPROM_DEVICE_ADDRESS, - EEPROM_MSTP_MAX_MASTER_ADDR); */ - if ((data <= 127) && (data >= MSTP_Port.This_Station)) - MSTP_Port.Nmax_master = data; - else - dlmstp_set_max_master(DEFAULT_MAX_MASTER); - /* FIXME: implement your data storage */ - data = 1; - /* I2C_Read_Byte( - EEPROM_DEVICE_ADDRESS, - EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */ - if (data >= 1) - MSTP_Port.Nmax_info_frames = data; - else - dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); -} - -void dlmstp_cleanup(void) -{ - /* nothing to do for static buffers */ -} - -/* returns number of bytes sent on success, zero on failure */ -int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ - BACNET_NPDU_DATA * npdu_data, /* network information */ - uint8_t * pdu, /* any data to be sent - may be null */ - unsigned pdu_len) -{ /* number of bytes of data */ - int bytes_sent = 0; - unsigned npdu_len = 0; - uint8_t frame_type = 0; - uint8_t destination = 0; /* destination address */ - BACNET_ADDRESS src; - unsigned i = 0; /* loop counter */ - - if (MSTP_Port.TxReady == false) { - if (npdu_data->data_expecting_reply) - MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; - else - MSTP_Port.TxFrameType = - FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; - - /* load destination MAC address */ - if (dest && dest->mac_len == 1) { - destination = dest->mac[0]; - } else { - return -2; - } - dlmstp_get_my_address(&src); - if ((8 /* header len */ + pdu_len) > MAX_MPDU) { - return -4; - } - bytes_sent = MSTP_Create_Frame( - (uint8_t *) & MSTP_Port.TxBuffer[0], - sizeof(MSTP_Port.TxBuffer), - MSTP_Port.TxFrameType, - destination, - MSTP_Port.This_Station, pdu, pdu_len); - MSTP_Port.TxLength = bytes_sent; - MSTP_Port.TxReady = true; - MSTP_Packets++; - } - - return bytes_sent; -} - -void dlmstp_task(void) -{ - uint8_t bytes_remaining; - bool received_frame; - - /* only do receive state machine while we don't have a frame */ - if ((MSTP_Port.ReceivedValidFrame == false) && - (MSTP_Port.ReceivedInvalidFrame == false)) - { - do { - bytes_remaining = RS485_Check_UART_Data(&MSTP_Port); - MSTP_Receive_Frame_FSM(&MSTP_Port); - received_frame = MSTP_Port.ReceivedValidFrame || - MSTP_Port.ReceivedInvalidFrame; - if (received_frame) - break; - } while (bytes_remaining); - } - /* only do master state machine while rx is idle */ - if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) { - while (MSTP_Master_Node_FSM(&MSTP_Port)) {}; - //MSTP_Master_Node_FSM(&MSTP_Port); - } - /* see if there is a packet available, and a place - to put the reply (if necessary) and process it */ - if (Receive_Buffer.ready && !MSTP_Port.TxReady) { - if (Receive_Buffer.pdu_len) { - MSTP_Packets++; - npdu_handler( - &Receive_Buffer.address, - &Receive_Buffer.pdu[0], - Receive_Buffer.pdu_len); - } - Receive_Buffer.ready = false; - } - - return; -} - -void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address) -{ - int i = 0; - - if (mstp_address == MSTP_BROADCAST_ADDRESS) { - /* mac_len = 0 if broadcast address */ - src->mac_len = 0; - src->mac[0] = 0; - } else { - src->mac_len = 1; - src->mac[0] = mstp_address; - } - /* fill with 0's starting with index 1; index 0 filled above */ - for (i = 1; i < MAX_MAC_LEN; i++) { - src->mac[i] = 0; - } - src->net = 0; - src->len = 0; - for (i = 0; i < MAX_MAC_LEN; i++) { - src->adr[i] = 0; - } -} - -/* for the MS/TP state machine to use for putting received data */ -uint16_t dlmstp_put_receive( - uint8_t src, /* source MS/TP address */ - uint8_t * pdu, /* PDU data */ - uint16_t pdu_len) /* amount of PDU data */ -{ - /* PDU is already in the Receive_Buffer */ - dlmstp_fill_bacnet_address(&Receive_Buffer.address, src); - Receive_Buffer.pdu_len = pdu_len; - Receive_Buffer.ready = true; -} - -void dlmstp_set_my_address(uint8_t mac_address) -{ - /* Master Nodes can only have address 0-127 */ - if (mac_address <= 127) { - MSTP_Port.This_Station = mac_address; - /* FIXME: implement your data storage */ - /* I2C_Write_Byte( - EEPROM_DEVICE_ADDRESS, - mac_address, - EEPROM_MSTP_MAC_ADDR); */ - if (mac_address > MSTP_Port.Nmax_master) - dlmstp_set_max_master(mac_address); - } - - return; -} - -uint8_t dlmstp_my_address(void) -{ - return MSTP_Port.This_Station; -} - -/* This parameter represents the value of the Max_Info_Frames property of */ -/* the node's Device object. The value of Max_Info_Frames specifies the */ -/* maximum number of information frames the node may send before it must */ -/* pass the token. Max_Info_Frames may have different values on different */ -/* nodes. This may be used to allocate more or less of the available link */ -/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ -/* node, its value shall be 1. */ -void dlmstp_set_max_info_frames(uint8_t max_info_frames) -{ - if (max_info_frames >= 1) { - MSTP_Port.Nmax_info_frames = max_info_frames; - /* FIXME: implement your data storage */ - /* I2C_Write_Byte( - EEPROM_DEVICE_ADDRESS, - (uint8_t)max_info_frames, - EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */ - } - - return; -} - -unsigned dlmstp_max_info_frames(void) -{ - return MSTP_Port.Nmax_info_frames; -} - -/* This parameter represents the value of the Max_Master property of the */ -/* node's Device object. The value of Max_Master specifies the highest */ -/* allowable address for master nodes. The value of Max_Master shall be */ -/* less than or equal to 127. If Max_Master is not writable in a node, */ -/* its value shall be 127. */ -void dlmstp_set_max_master(uint8_t max_master) -{ - if (max_master <= 127) { - if (MSTP_Port.This_Station <= max_master) { - MSTP_Port.Nmax_master = max_master; - /* FIXME: implement your data storage */ - /* I2C_Write_Byte( - EEPROM_DEVICE_ADDRESS, - max_master, - EEPROM_MSTP_MAX_MASTER_ADDR); */ - } - } - - return; -} - -uint8_t dlmstp_max_master(void) -{ - return MSTP_Port.Nmax_master; -} - -void dlmstp_get_my_address(BACNET_ADDRESS * my_address) -{ - int i = 0; /* counter */ - - my_address->mac_len = 1; - my_address->mac[0] = MSTP_Port.This_Station; - my_address->net = 0; /* local only, no routing */ - my_address->len = 0; - for (i = 0; i < MAX_MAC_LEN; i++) { - my_address->adr[i] = 0; - } - - return; -} - -void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest) -{ /* destination address */ - int i = 0; /* counter */ - - if (dest) { - dest->mac_len = 1; - dest->mac[0] = MSTP_BROADCAST_ADDRESS; - dest->net = BACNET_BROADCAST_NETWORK; - dest->len = 0; /* len=0 denotes broadcast address */ - for (i = 0; i < MAX_MAC_LEN; i++) { - dest->adr[i] = 0; - } - } - - return; -} +/************************************************************************** +* +* 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. +* +*********************************************************************/ +#include +#include +#include +#include +#if PRINT_ENABLED +#include +#endif +#include "bacdef.h" +#include "mstp.h" +#include "dlmstp.h" +#include "rs485.h" +#include "npdu.h" + +/* Number of MS/TP Packets Rx/Tx */ +uint16_t MSTP_Packets = 0; + +/* receive buffer */ +#pragma udata MSTP_RxData +static DLMSTP_PACKET Receive_Buffer; +/* temp buffer for NPDU insertion */ +/* local MS/TP port data - shared with RS-485 */ +#pragma udata MSTP_PortData +volatile struct mstp_port_struct_t MSTP_Port; +#pragma udata + +#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;} + +/* This defines the number of edit fields for this module */ +#define MAX_EDIT_FIELD 1 +static uint8_t EditField = 0; +/* ************************************************************************* + DESCRIPTION: This function handles incrementing or decrementing our + EditField + RETURN: none + ALGORITHM: none + NOTES: Pass a #>0 to increment #<0 to decrement + *************************************************************************** */ +void dlmstp_SetEditField(signed char state) +{ /* direction our editfield is moving */ + if (state > 0) { + if (++EditField > MAX_EDIT_FIELD) + EditField = 0; + } else if (state < 0) { + if (EditField) + EditField--; + else + EditField = MAX_EDIT_FIELD; + } else + EditField = 0; +} + +/* ************************************************************************* + DESCRIPTION: Gets the current edit field for this module + RETURN: the current edit field + ALGORITHM: none + NOTES: none + *************************************************************************** */ +uint8_t dlmstp_GetEditField(void) +{ + return (EditField); +} + +void dlmstp_millisecond_timer(void) +{ + INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer); +} + +void dlmstp_reinit(void) +{ + RS485_Reinit(); + dlmstp_set_my_address(DEFAULT_MAC_ADDRESS); + dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); + dlmstp_set_max_master(DEFAULT_MAX_MASTER); +} + +void dlmstp_init(void) +{ + uint8_t data; + + /* initialize buffer */ + Receive_Buffer.ready = false; + Receive_Buffer.pdu_len = 0; + /* initialize hardware */ + RS485_Initialize(); + MSTP_Port.InputBuffer = &Receive_Buffer.pdu[0]; + MSTP_Init(&MSTP_Port); + /* FIXME: implement your data storage */ + data = 64; /* I2C_Read_Byte( + EEPROM_DEVICE_ADDRESS, + EEPROM_MSTP_MAC_ADDR); */ + if (data <= 127) + MSTP_Port.This_Station = data; + else + dlmstp_set_my_address(DEFAULT_MAC_ADDRESS); + /* FIXME: implement your data storage */ + data = 127; /* I2C_Read_Byte( + EEPROM_DEVICE_ADDRESS, + EEPROM_MSTP_MAX_MASTER_ADDR); */ + if ((data <= 127) && (data >= MSTP_Port.This_Station)) + MSTP_Port.Nmax_master = data; + else + dlmstp_set_max_master(DEFAULT_MAX_MASTER); + /* FIXME: implement your data storage */ + data = 1; + /* I2C_Read_Byte( + EEPROM_DEVICE_ADDRESS, + EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */ + if (data >= 1) + MSTP_Port.Nmax_info_frames = data; + else + dlmstp_set_max_info_frames(DEFAULT_MAX_INFO_FRAMES); +} + +void dlmstp_cleanup(void) +{ + /* nothing to do for static buffers */ +} + +/* returns number of bytes sent on success, zero on failure */ +int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ + BACNET_NPDU_DATA * npdu_data, /* network information */ + uint8_t * pdu, /* any data to be sent - may be null */ + unsigned pdu_len) +{ /* number of bytes of data */ + int bytes_sent = 0; + unsigned npdu_len = 0; + uint8_t frame_type = 0; + uint8_t destination = 0; /* destination address */ + BACNET_ADDRESS src; + unsigned i = 0; /* loop counter */ + + if (MSTP_Port.TxReady == false) { + if (npdu_data->data_expecting_reply) + MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; + else + MSTP_Port.TxFrameType = + FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; + + /* load destination MAC address */ + if (dest && dest->mac_len == 1) { + destination = dest->mac[0]; + } else { + return -2; + } + dlmstp_get_my_address(&src); + if ((8 /* header len */ + pdu_len) > MAX_MPDU) { + return -4; + } + bytes_sent = MSTP_Create_Frame( + (uint8_t *) & MSTP_Port.TxBuffer[0], + sizeof(MSTP_Port.TxBuffer), + MSTP_Port.TxFrameType, + destination, MSTP_Port.This_Station, pdu, pdu_len); + MSTP_Port.TxLength = bytes_sent; + MSTP_Port.TxReady = true; + MSTP_Packets++; + } + + return bytes_sent; +} + +void dlmstp_task(void) +{ + uint8_t bytes_remaining; + bool received_frame; + + /* only do receive state machine while we don't have a frame */ + if ((MSTP_Port.ReceivedValidFrame == false) && + (MSTP_Port.ReceivedInvalidFrame == false)) { + do { + bytes_remaining = RS485_Check_UART_Data(&MSTP_Port); + MSTP_Receive_Frame_FSM(&MSTP_Port); + received_frame = MSTP_Port.ReceivedValidFrame || + MSTP_Port.ReceivedInvalidFrame; + if (received_frame) + break; + } while (bytes_remaining); + } + /* only do master state machine while rx is idle */ + if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) { + while (MSTP_Master_Node_FSM(&MSTP_Port)) { + }; + /*MSTP_Master_Node_FSM(&MSTP_Port); */ + } + /* see if there is a packet available, and a place + to put the reply (if necessary) and process it */ + if (Receive_Buffer.ready && !MSTP_Port.TxReady) { + if (Receive_Buffer.pdu_len) { + MSTP_Packets++; + npdu_handler(&Receive_Buffer.address, + &Receive_Buffer.pdu[0], Receive_Buffer.pdu_len); + } + Receive_Buffer.ready = false; + } + + return; +} + +void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address) +{ + int i = 0; + + if (mstp_address == MSTP_BROADCAST_ADDRESS) { + /* mac_len = 0 if broadcast address */ + src->mac_len = 0; + src->mac[0] = 0; + } else { + src->mac_len = 1; + src->mac[0] = mstp_address; + } + /* fill with 0's starting with index 1; index 0 filled above */ + for (i = 1; i < MAX_MAC_LEN; i++) { + src->mac[i] = 0; + } + src->net = 0; + src->len = 0; + for (i = 0; i < MAX_MAC_LEN; i++) { + src->adr[i] = 0; + } +} + +/* for the MS/TP state machine to use for putting received data */ +uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */ + uint8_t * pdu, /* PDU data */ + uint16_t pdu_len) +{ /* amount of PDU data */ + /* PDU is already in the Receive_Buffer */ + dlmstp_fill_bacnet_address(&Receive_Buffer.address, src); + Receive_Buffer.pdu_len = pdu_len; + Receive_Buffer.ready = true; +} + +void dlmstp_set_my_address(uint8_t mac_address) +{ + /* Master Nodes can only have address 0-127 */ + if (mac_address <= 127) { + MSTP_Port.This_Station = mac_address; + /* FIXME: implement your data storage */ + /* I2C_Write_Byte( + EEPROM_DEVICE_ADDRESS, + mac_address, + EEPROM_MSTP_MAC_ADDR); */ + if (mac_address > MSTP_Port.Nmax_master) + dlmstp_set_max_master(mac_address); + } + + return; +} + +uint8_t dlmstp_my_address(void) +{ + return MSTP_Port.This_Station; +} + +/* This parameter represents the value of the Max_Info_Frames property of */ +/* the node's Device object. The value of Max_Info_Frames specifies the */ +/* maximum number of information frames the node may send before it must */ +/* pass the token. Max_Info_Frames may have different values on different */ +/* nodes. This may be used to allocate more or less of the available link */ +/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ +/* node, its value shall be 1. */ +void dlmstp_set_max_info_frames(uint8_t max_info_frames) +{ + if (max_info_frames >= 1) { + MSTP_Port.Nmax_info_frames = max_info_frames; + /* FIXME: implement your data storage */ + /* I2C_Write_Byte( + EEPROM_DEVICE_ADDRESS, + (uint8_t)max_info_frames, + EEPROM_MSTP_MAX_INFO_FRAMES_ADDR); */ + } + + return; +} + +unsigned dlmstp_max_info_frames(void) +{ + return MSTP_Port.Nmax_info_frames; +} + +/* This parameter represents the value of the Max_Master property of the */ +/* node's Device object. The value of Max_Master specifies the highest */ +/* allowable address for master nodes. The value of Max_Master shall be */ +/* less than or equal to 127. If Max_Master is not writable in a node, */ +/* its value shall be 127. */ +void dlmstp_set_max_master(uint8_t max_master) +{ + if (max_master <= 127) { + if (MSTP_Port.This_Station <= max_master) { + MSTP_Port.Nmax_master = max_master; + /* FIXME: implement your data storage */ + /* I2C_Write_Byte( + EEPROM_DEVICE_ADDRESS, + max_master, + EEPROM_MSTP_MAX_MASTER_ADDR); */ + } + } + + return; +} + +uint8_t dlmstp_max_master(void) +{ + return MSTP_Port.Nmax_master; +} + +void dlmstp_get_my_address(BACNET_ADDRESS * my_address) +{ + int i = 0; /* counter */ + + my_address->mac_len = 1; + my_address->mac[0] = MSTP_Port.This_Station; + my_address->net = 0; /* local only, no routing */ + my_address->len = 0; + for (i = 0; i < MAX_MAC_LEN; i++) { + my_address->adr[i] = 0; + } + + return; +} + +void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest) +{ /* destination address */ + int i = 0; /* counter */ + + if (dest) { + dest->mac_len = 1; + dest->mac[0] = MSTP_BROADCAST_ADDRESS; + dest->net = BACNET_BROADCAST_NETWORK; + dest->len = 0; /* len=0 denotes broadcast address */ + for (i = 0; i < MAX_MAC_LEN; i++) { + dest->adr[i] = 0; + } + } + + return; +} diff --git a/bacnet-stack/ports/pic18f6720/dlmstp.h b/bacnet-stack/ports/pic18f6720/dlmstp.h index a57dba59..1343d7a8 100644 --- a/bacnet-stack/ports/pic18f6720/dlmstp.h +++ b/bacnet-stack/ports/pic18f6720/dlmstp.h @@ -1,110 +1,110 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2005 Steve Karg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307 - USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ -#ifndef DLMSTP_H -#define DLMSTP_H - -#include -#include -#include -#include "bacdef.h" -#include "npdu.h" - -/* defines specific to MS/TP */ -#define MAX_HEADER (2+1+1+1+2+1+2+1) -#define MAX_MPDU (MAX_HEADER+MAX_PDU) - -typedef struct dlmstp_packet { - bool ready; /* true if ready to be sent or received */ - BACNET_ADDRESS address; /* source address */ - uint8_t frame_type; /* type of message */ - unsigned pdu_len; /* packet length */ - uint8_t pdu[MAX_MPDU]; /* packet */ -} DLMSTP_PACKET; - -/* number of MS/TP tx/rx packets */ -extern uint16_t MSTP_Packets; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - void dlmstp_reinit(void); - void dlmstp_init(void); - void dlmstp_cleanup(void); - void dlmstp_millisecond_timer(void); - void dlmstp_task(void); - - /* returns number of bytes sent on success, negative on failure */ - int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ - BACNET_NPDU_DATA * npdu_data, /* network information */ - uint8_t * pdu, /* any data to be sent - may be null */ - unsigned pdu_len); /* number of bytes of data */ - - /* This parameter represents the value of the Max_Info_Frames property of */ - /* the node's Device object. The value of Max_Info_Frames specifies the */ - /* maximum number of information frames the node may send before it must */ - /* pass the token. Max_Info_Frames may have different values on different */ - /* nodes. This may be used to allocate more or less of the available link */ - /* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ - /* node, its value shall be 1. */ - void dlmstp_set_max_info_frames(uint8_t max_info_frames); - unsigned dlmstp_max_info_frames(void); - - /* This parameter represents the value of the Max_Master property of the */ - /* node's Device object. The value of Max_Master specifies the highest */ - /* allowable address for master nodes. The value of Max_Master shall be */ - /* less than or equal to 127. If Max_Master is not writable in a node, */ - /* its value shall be 127. */ - void dlmstp_set_max_master(uint8_t max_master); - uint8_t dlmstp_max_master(void); - - /* MAC address for MS/TP */ - void dlmstp_set_my_address(uint8_t my_address); - uint8_t dlmstp_my_address(void); - - /* BACnet address used in datalink */ - void dlmstp_get_my_address(BACNET_ADDRESS * my_address); - void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest); /* destination address */ - - /* MS/TP state machine functions */ - uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */ - uint8_t * pdu, /* PDU data */ - uint16_t pdu_len); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2005 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307 + USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ +#ifndef DLMSTP_H +#define DLMSTP_H + +#include +#include +#include +#include "bacdef.h" +#include "npdu.h" + +/* defines specific to MS/TP */ +#define MAX_HEADER (2+1+1+1+2+1+2+1) +#define MAX_MPDU (MAX_HEADER+MAX_PDU) + +typedef struct dlmstp_packet { + bool ready; /* true if ready to be sent or received */ + BACNET_ADDRESS address; /* source address */ + uint8_t frame_type; /* type of message */ + unsigned pdu_len; /* packet length */ + uint8_t pdu[MAX_MPDU]; /* packet */ +} DLMSTP_PACKET; + +/* number of MS/TP tx/rx packets */ +extern uint16_t MSTP_Packets; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void dlmstp_reinit(void); + void dlmstp_init(void); + void dlmstp_cleanup(void); + void dlmstp_millisecond_timer(void); + void dlmstp_task(void); + + /* returns number of bytes sent on success, negative on failure */ + int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ + BACNET_NPDU_DATA * npdu_data, /* network information */ + uint8_t * pdu, /* any data to be sent - may be null */ + unsigned pdu_len); /* number of bytes of data */ + + /* This parameter represents the value of the Max_Info_Frames property of */ + /* the node's Device object. The value of Max_Info_Frames specifies the */ + /* maximum number of information frames the node may send before it must */ + /* pass the token. Max_Info_Frames may have different values on different */ + /* nodes. This may be used to allocate more or less of the available link */ + /* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ + /* node, its value shall be 1. */ + void dlmstp_set_max_info_frames(uint8_t max_info_frames); + unsigned dlmstp_max_info_frames(void); + + /* This parameter represents the value of the Max_Master property of the */ + /* node's Device object. The value of Max_Master specifies the highest */ + /* allowable address for master nodes. The value of Max_Master shall be */ + /* less than or equal to 127. If Max_Master is not writable in a node, */ + /* its value shall be 127. */ + void dlmstp_set_max_master(uint8_t max_master); + uint8_t dlmstp_max_master(void); + + /* MAC address for MS/TP */ + void dlmstp_set_my_address(uint8_t my_address); + uint8_t dlmstp_my_address(void); + + /* BACnet address used in datalink */ + void dlmstp_get_my_address(BACNET_ADDRESS * my_address); + void dlmstp_get_broadcast_address(BACNET_ADDRESS * dest); /* destination address */ + + /* MS/TP state machine functions */ + uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */ + uint8_t * pdu, /* PDU data */ + uint16_t pdu_len); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/pic18f6720/hardware.h b/bacnet-stack/ports/pic18f6720/hardware.h index 28f04dd4..755aaa30 100644 --- a/bacnet-stack/ports/pic18f6720/hardware.h +++ b/bacnet-stack/ports/pic18f6720/hardware.h @@ -1,268 +1,262 @@ -/************************************************************************** -* -* Copyright (C) 2007 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ -#ifndef HARDWARE_H -#define HARDWARE_H - -#include -#include -#include - -/* PORTA.0 Photocell Input PORTA.1 LED Row6 PORTA.2 LED Row5 PORTA.3 LED - * Row4 PORTA.4 Square Wave input from RTC PORTA.5 LCD RW PORTB.0 Zero - * Cross PORTB.1 USB RXF# PORTB.2 USB TXE# PORTB.3 Keypad Row Enable - * (74HC373 Output Control) PORTB.4 Keypad Row Gate (74HC373 Gate) - * PORTB.5 Switch Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6 - * ICD connection PORTB.7 ICD connection PORTC.0 Pilot Latch PORTC.1 - * Pilot Output Enable (low) PORTC.2 Piezo PORTC.3 I2C clock PORTC.4 I2C - * data PORTC.5 RS232 enable (low) PORTC.6 RS232 Tx PORTC.7 RS232 Rx - * PORTD.0 Data bus PORTD.1 Data bus PORTD.2 Data bus PORTD.3 Data bus - * PORTD.4 Data bus PORTD.5 Data bus PORTD.6 Data bus PORTD.7 Data bus - * PORTE.0 USB RD PORTE.1 USB WR PORTE.2 LCD RS PORTE.3 485 transmit - * enable PORTE.4 Relay data latch PORTE.5 Switch Input Clock PORTE.6 - * Switch Input High/Low PORTE.7 Switch Input Data PORTF.0 LED Row2 - * PORTF.1 LED Row1 PORTF.2 LED Col5 PORTF.3 LED Col4 PORTF.4 LED Col3 - * PORTF.5 LED Col2 PORTF.6 LED Col1 PORTF.7 LED Col0 PORTG.0 485 receive - * enable PORTG.1 485 Tx PORTG.2 485 Rx PORTG.3 LCD E PORTG.4 LED Row0 */ -#define LCD_BUSY PORTDbits.RD7 -#define LCD_E PORTGbits.RG3 -#define LCD_RW PORTAbits.RA5 -#define LCD_RS PORTEbits.RE2 -#define LCD_DATA PORTD -#define LCD_TRIS TRISD - -#define PILOT_LATCH PORTCbits.RC0 -#define PILOT_ENABLE PORTCbits.RC1 -#define PILOT_PORT PORTD -#define PILOT_PORT_TRIS TRISD - -#define PIEZO PORTCbits.RC2 -#define PIEZO_ON() TRISCbits.TRISC2 = 0 -#define PIEZO_OFF() TRISCbits.TRISC2 = 1 - -#define RS232_ENABLE PORTCbits.RC5 - -#define RS485_TX_ENABLE PORTEbits.RE3 -#define RS485_RX_DISABLE PORTGbits.RG0 - -#define SWITCH_LOAD PORTBbits.RB5 -#define SWITCH_CLK PORTEbits.RE5 -#define SWITCH_COM PORTEbits.RE6 -#define SWITCH_DATA PORTEbits.RE7 - -#define LEDPORT PORTF -#define LEDTRIS TRISF -#define LED_ROW1 PORTGbits.RG4 -#define LED_ROW2 PORTFbits.RF1 -#define LED_ROW3 PORTFbits.RF0 -#define LED_ROW4 PORTAbits.RA3 -#define LED_ROW5 PORTAbits.RA2 -#define LED_ROW6 PORTAbits.RA1 - -#define RELAY_PORT PORTD -#define RELAY_PORT_TRIS TRISD -#define RELAY_LATCH PORTEbits.RE4 - -#define KEYPAD_DATA PORTD -#define KEYPAD_TRIS TRISD -#define KEYPAD_COL_LATCH PORTBbits.RB5 -#define KEYPAD_ROW_ENABLE PORTBbits.RB3 -#define KEYPAD_ROW_LATCH PORTBbits.RB4 -#define KEYPAD_ROW1 0 b00000001 -#define KEYPAD_ROW2 0 b00000010 -#define KEYPAD_ROW3 0 b00000100 -#define KEYPAD_ROW4 0 b00001000 -#define KEYPAD_ROW5 0 b00010000 -#define KEYPAD_ROW6 0 b00100000 - -#define USB_RD_EMPTY PORTBbits.RB1 -#define USB_WR_FULL PORTBbits.RB2 -#define USB_RD PORTEbits.RE0 -#define USB_WR PORTEbits.RE1 -#define USB_PORT PORTD -#define USB_PORT_TRIS TRISD - -#define ZERO_CROSS PORTBbits.RB0 - -#define PORT_A_TRIS_MASK 0x11 /* 0b00010001 */ -#define PORT_B_TRIS_MASK 0xC7 /* 0b11000111 */ -#define PORT_C_TRIS_MASK 0x9C /* 0b10011100 */ -#define PORT_D_TRIS_MASK 0xFF /* 0b11111111 */ -#define PORT_E_TRIS_MASK 0x88 /* 0b10001000 */ -#define PORT_F_TRIS_MASK 0x00 /* 0b00000000 */ -#define PORT_G_TRIS_MASK 0x04 /* 0b00000100 */ - -#define TURN_OFF_COMPARATORS() CMCON = 0x07 - -#define SHORT_BEEP 50 -#define LONG_BEEP 250 - -#define CLICK() Hardware_Sound_Piezo(SHORT_BEEP); -#define BEEP() Hardware_Sound_Piezo(LONG_BEEP); - -typedef union -{ - struct - { - uint8_t:1; - uint8_t:1; - uint8_t Thursday : 1; - uint8_t Wednesday : 1; - uint8_t Tuesday : 1; - uint8_t Monday : 1; - uint8_t Program : 1; - uint8_t Run : 1; - - uint8_t:1; - uint8_t:1; - uint8_t Input1 : 1; - uint8_t Input2 : 1; - uint8_t Input3 : 1; - uint8_t Input4 : 1; - uint8_t Input5 : 1; - uint8_t Input6 : 1; - - uint8_t:1; - uint8_t:1; - uint8_t:1; - uint8_t Input7 : 1; - uint8_t:1; - uint8_t:1; - uint8_t Input8 : 1; - uint8_t Photocell : 1; - - uint8_t:1; - uint8_t:1; - uint8_t:1; - uint8_t:1; - uint8_t:1; - uint8_t:1; - uint8_t Remote : 1; - uint8_t Relay8 : 1; - - uint8_t:1; - uint8_t:1; - uint8_t:1; - uint8_t Relay7 : 1; - uint8_t Relay6 : 1; - uint8_t Relay5 : 1; - uint8_t Relay4 : 1; - uint8_t Relay3 : 1; - - uint8_t:1; - uint8_t:1; - uint8_t Relay2 : 1; - uint8_t Relay1 : 1; - uint8_t Holiday : 1; - uint8_t Sunday : 1; - uint8_t Saturday : 1; - uint8_t Friday : 1; - }; - struct - { - uint8_t row1; - uint8_t row2; - uint8_t row3; - uint8_t row4; - uint8_t row5; - uint8_t row6; - }; -} LED_REGS; - -union SWITCH_REGS -{ - struct - { - uint8_t All_On : 1; - uint8_t All_Off : 1; - uint8_t Addr : 4; - uint8_t Pilot_Fault : 1; - uint8_t Master : 1; - }; - uint8_t Sw_Byte; -}; - -enum INT_STATE { INT_DISABLED, INT_ENABLED, INT_RESTORE }; - -#define RESTART_WDT() { _asm CLRWDT _endasm } - -/* ************************************************************************* - define ENABLE_GLOBAL_INT() INTCONbits.GIE = 1 £ - #define DISABLE_GLOBAL_INT() INTCONbits.GIE = 0 £ - #define ENABLE_PERIPHERAL_INT() INTCONbits.PEIE = 1 £ - #define DISABLE_PERIPHERAL_INT() INTCONbits.PEIE = 0 - *************************************************************************** */ -#define ENABLE_HIGH_INT() INTCONbits.GIE = 1 -#define DISABLE_HIGH_INT() INTCONbits.GIE = 0 - -#define ENABLE_LOW_INT() INTCONbits.PEIE = 1 -#define DISABLE_LOW_INT() INTCONbits.PEIE = 0 - -#define ENABLE_TIMER0_INT() INTCONbits.TMR0IE = 1 -#define DISABLE_TIMER0_INT() INTCONbits.TMR0IE = 0 - -#define ENABLE_TIMER2_INT() PIE1bits.TMR2IE = 1 -#define DISABLE_TIMER2_INT() PIE1bits.TMR2IE = 0 - -#define ENABLE_TIMER4_INT() PIE3bits.TMR4IE = 1 -#define DISABLE_TIMER4_INT() PIE3bits.TMR4IE = 0 - -#define ENABLE_CCP2_INT() PIE2bits.CCP2IE = 1 -#define DISABLE_CCP2_INT() PIE2bits.CCP2IE = 0 - -#define ENABLE_CCP1_INT() PIE1bits.CCP1IE = 1 -#define DISABLE_CCP1_INT() PIE1bits.CCP1IE = 0 - -#define ENABLE_ABUS_INT() PIE1bits.SSPIE = 1 -#define DISABLE_ABUS_INT() PIE1bits.SSPIE = 0 -#define CLEAR_ABUS_FLAG() PIR1bits.SSPIF = 0 - -#define SETUP_CCP1(x) CCP1CON = x -#define SETUP_CCP2(x) CCP2CON = x - -#define DISABLE_RX_INT() PIE1bits.RCIE = 0 -#define ENABLE_RX_INT() PIE1bits.RCIE = 1 - -#define DISABLE_TX_INT() PIE1bits.TXIE = 0 -#define ENABLE_TX_INT() PIE1bits.TXIE = 1 - -#if CLOCKSPEED == 20 -#define DELAY_US(x) { _asm \ - MOVLW x \ - LOOP: \ - NOP \ - NOP \ - DECFSZ WREG, 1, 0 \ - BRA LOOP \ - _endasm } -#endif - -/* Global Vars */ -extern volatile LED_REGS LEDS; -extern volatile LED_REGS Blink; -extern uint8_t Piezo_Timer; -extern volatile bool DataPortLocked; - -#endif /* HARDWARE_H */ - +/************************************************************************** +* +* Copyright (C) 2007 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ +#ifndef HARDWARE_H +#define HARDWARE_H + +#include +#include +#include + +/* PORTA.0 Photocell Input PORTA.1 LED Row6 PORTA.2 LED Row5 PORTA.3 LED + * Row4 PORTA.4 Square Wave input from RTC PORTA.5 LCD RW PORTB.0 Zero + * Cross PORTB.1 USB RXF# PORTB.2 USB TXE# PORTB.3 Keypad Row Enable + * (74HC373 Output Control) PORTB.4 Keypad Row Gate (74HC373 Gate) + * PORTB.5 Switch Input Latch & Keypad Column Gate (74HC373 Gate) PORTB.6 + * ICD connection PORTB.7 ICD connection PORTC.0 Pilot Latch PORTC.1 + * Pilot Output Enable (low) PORTC.2 Piezo PORTC.3 I2C clock PORTC.4 I2C + * data PORTC.5 RS232 enable (low) PORTC.6 RS232 Tx PORTC.7 RS232 Rx + * PORTD.0 Data bus PORTD.1 Data bus PORTD.2 Data bus PORTD.3 Data bus + * PORTD.4 Data bus PORTD.5 Data bus PORTD.6 Data bus PORTD.7 Data bus + * PORTE.0 USB RD PORTE.1 USB WR PORTE.2 LCD RS PORTE.3 485 transmit + * enable PORTE.4 Relay data latch PORTE.5 Switch Input Clock PORTE.6 + * Switch Input High/Low PORTE.7 Switch Input Data PORTF.0 LED Row2 + * PORTF.1 LED Row1 PORTF.2 LED Col5 PORTF.3 LED Col4 PORTF.4 LED Col3 + * PORTF.5 LED Col2 PORTF.6 LED Col1 PORTF.7 LED Col0 PORTG.0 485 receive + * enable PORTG.1 485 Tx PORTG.2 485 Rx PORTG.3 LCD E PORTG.4 LED Row0 */ +#define LCD_BUSY PORTDbits.RD7 +#define LCD_E PORTGbits.RG3 +#define LCD_RW PORTAbits.RA5 +#define LCD_RS PORTEbits.RE2 +#define LCD_DATA PORTD +#define LCD_TRIS TRISD + +#define PILOT_LATCH PORTCbits.RC0 +#define PILOT_ENABLE PORTCbits.RC1 +#define PILOT_PORT PORTD +#define PILOT_PORT_TRIS TRISD + +#define PIEZO PORTCbits.RC2 +#define PIEZO_ON() TRISCbits.TRISC2 = 0 +#define PIEZO_OFF() TRISCbits.TRISC2 = 1 + +#define RS232_ENABLE PORTCbits.RC5 + +#define RS485_TX_ENABLE PORTEbits.RE3 +#define RS485_RX_DISABLE PORTGbits.RG0 + +#define SWITCH_LOAD PORTBbits.RB5 +#define SWITCH_CLK PORTEbits.RE5 +#define SWITCH_COM PORTEbits.RE6 +#define SWITCH_DATA PORTEbits.RE7 + +#define LEDPORT PORTF +#define LEDTRIS TRISF +#define LED_ROW1 PORTGbits.RG4 +#define LED_ROW2 PORTFbits.RF1 +#define LED_ROW3 PORTFbits.RF0 +#define LED_ROW4 PORTAbits.RA3 +#define LED_ROW5 PORTAbits.RA2 +#define LED_ROW6 PORTAbits.RA1 + +#define RELAY_PORT PORTD +#define RELAY_PORT_TRIS TRISD +#define RELAY_LATCH PORTEbits.RE4 + +#define KEYPAD_DATA PORTD +#define KEYPAD_TRIS TRISD +#define KEYPAD_COL_LATCH PORTBbits.RB5 +#define KEYPAD_ROW_ENABLE PORTBbits.RB3 +#define KEYPAD_ROW_LATCH PORTBbits.RB4 +#define KEYPAD_ROW1 0 b00000001 +#define KEYPAD_ROW2 0 b00000010 +#define KEYPAD_ROW3 0 b00000100 +#define KEYPAD_ROW4 0 b00001000 +#define KEYPAD_ROW5 0 b00010000 +#define KEYPAD_ROW6 0 b00100000 + +#define USB_RD_EMPTY PORTBbits.RB1 +#define USB_WR_FULL PORTBbits.RB2 +#define USB_RD PORTEbits.RE0 +#define USB_WR PORTEbits.RE1 +#define USB_PORT PORTD +#define USB_PORT_TRIS TRISD + +#define ZERO_CROSS PORTBbits.RB0 + +#define PORT_A_TRIS_MASK 0x11 /* 0b00010001 */ +#define PORT_B_TRIS_MASK 0xC7 /* 0b11000111 */ +#define PORT_C_TRIS_MASK 0x9C /* 0b10011100 */ +#define PORT_D_TRIS_MASK 0xFF /* 0b11111111 */ +#define PORT_E_TRIS_MASK 0x88 /* 0b10001000 */ +#define PORT_F_TRIS_MASK 0x00 /* 0b00000000 */ +#define PORT_G_TRIS_MASK 0x04 /* 0b00000100 */ + +#define TURN_OFF_COMPARATORS() CMCON = 0x07 + +#define SHORT_BEEP 50 +#define LONG_BEEP 250 + +#define CLICK() Hardware_Sound_Piezo(SHORT_BEEP); +#define BEEP() Hardware_Sound_Piezo(LONG_BEEP); + +typedef union { + struct { + uint8_t:1; + uint8_t:1; + uint8_t Thursday:1; + uint8_t Wednesday:1; + uint8_t Tuesday:1; + uint8_t Monday:1; + uint8_t Program:1; + uint8_t Run:1; + + uint8_t:1; + uint8_t:1; + uint8_t Input1:1; + uint8_t Input2:1; + uint8_t Input3:1; + uint8_t Input4:1; + uint8_t Input5:1; + uint8_t Input6:1; + + uint8_t:1; + uint8_t:1; + uint8_t:1; + uint8_t Input7:1; + uint8_t:1; + uint8_t:1; + uint8_t Input8:1; + uint8_t Photocell:1; + + uint8_t:1; + uint8_t:1; + uint8_t:1; + uint8_t:1; + uint8_t:1; + uint8_t:1; + uint8_t Remote:1; + uint8_t Relay8:1; + + uint8_t:1; + uint8_t:1; + uint8_t:1; + uint8_t Relay7:1; + uint8_t Relay6:1; + uint8_t Relay5:1; + uint8_t Relay4:1; + uint8_t Relay3:1; + + uint8_t:1; + uint8_t:1; + uint8_t Relay2:1; + uint8_t Relay1:1; + uint8_t Holiday:1; + uint8_t Sunday:1; + uint8_t Saturday:1; + uint8_t Friday:1; + }; + struct { + uint8_t row1; + uint8_t row2; + uint8_t row3; + uint8_t row4; + uint8_t row5; + uint8_t row6; + }; +} LED_REGS; + +union SWITCH_REGS { + struct { + uint8_t All_On:1; + uint8_t All_Off:1; + uint8_t Addr:4; + uint8_t Pilot_Fault:1; + uint8_t Master:1; + }; + uint8_t Sw_Byte; +}; + +enum INT_STATE { INT_DISABLED, INT_ENABLED, INT_RESTORE }; + +#define RESTART_WDT() { _asm CLRWDT _endasm } + +/* ************************************************************************* + define ENABLE_GLOBAL_INT() INTCONbits.GIE = 1 £ + #define DISABLE_GLOBAL_INT() INTCONbits.GIE = 0 £ + #define ENABLE_PERIPHERAL_INT() INTCONbits.PEIE = 1 £ + #define DISABLE_PERIPHERAL_INT() INTCONbits.PEIE = 0 + *************************************************************************** */ +#define ENABLE_HIGH_INT() INTCONbits.GIE = 1 +#define DISABLE_HIGH_INT() INTCONbits.GIE = 0 + +#define ENABLE_LOW_INT() INTCONbits.PEIE = 1 +#define DISABLE_LOW_INT() INTCONbits.PEIE = 0 + +#define ENABLE_TIMER0_INT() INTCONbits.TMR0IE = 1 +#define DISABLE_TIMER0_INT() INTCONbits.TMR0IE = 0 + +#define ENABLE_TIMER2_INT() PIE1bits.TMR2IE = 1 +#define DISABLE_TIMER2_INT() PIE1bits.TMR2IE = 0 + +#define ENABLE_TIMER4_INT() PIE3bits.TMR4IE = 1 +#define DISABLE_TIMER4_INT() PIE3bits.TMR4IE = 0 + +#define ENABLE_CCP2_INT() PIE2bits.CCP2IE = 1 +#define DISABLE_CCP2_INT() PIE2bits.CCP2IE = 0 + +#define ENABLE_CCP1_INT() PIE1bits.CCP1IE = 1 +#define DISABLE_CCP1_INT() PIE1bits.CCP1IE = 0 + +#define ENABLE_ABUS_INT() PIE1bits.SSPIE = 1 +#define DISABLE_ABUS_INT() PIE1bits.SSPIE = 0 +#define CLEAR_ABUS_FLAG() PIR1bits.SSPIF = 0 + +#define SETUP_CCP1(x) CCP1CON = x +#define SETUP_CCP2(x) CCP2CON = x + +#define DISABLE_RX_INT() PIE1bits.RCIE = 0 +#define ENABLE_RX_INT() PIE1bits.RCIE = 1 + +#define DISABLE_TX_INT() PIE1bits.TXIE = 0 +#define ENABLE_TX_INT() PIE1bits.TXIE = 1 + +#if CLOCKSPEED == 20 +#define DELAY_US(x) { _asm \ + MOVLW x \ + LOOP: \ + NOP \ + NOP \ + DECFSZ WREG, 1, 0 \ + BRA LOOP \ + _endasm } +#endif + +/* Global Vars */ +extern volatile LED_REGS LEDS; +extern volatile LED_REGS Blink; +extern uint8_t Piezo_Timer; +extern volatile bool DataPortLocked; + +#endif /* HARDWARE_H */ diff --git a/bacnet-stack/ports/pic18f6720/isr.c b/bacnet-stack/ports/pic18f6720/isr.c index 43e28bd2..ebd18e04 100644 --- a/bacnet-stack/ports/pic18f6720/isr.c +++ b/bacnet-stack/ports/pic18f6720/isr.c @@ -1,210 +1,192 @@ -/************************************************************************** -* -* Copyright (C) 2007 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ -#include -#include "stdint.h" -#include "hardware.h" -#include "rs485.h" -#include "dlmstp.h" - -/* from main.c */ -extern volatile uint8_t System_Seconds; -extern volatile uint8_t Milliseconds; - -void InterruptHandlerHigh(void); -void InterruptHandlerLow(void); -void Interrupt_Timer2(void); -void Interrupt_Timer3(void); -void Interrupt_Timer4(void); -void Interrupt_USART_Rx(void); -void Interrupt_USART_Tx(void); -void Interrupt_CCP2(void); -void INT0_Interrupt(void); - -#pragma code InterruptVectorHigh = 0x308 -void InterruptVectorHigh (void) -{ - _asm goto InterruptHandlerHigh /* jump to interrupt routine */ - _endasm -} -#pragma code - -#pragma code InterruptVectorLow = 0x318 -void InterruptVectorLow (void) -{ - _asm goto InterruptHandlerLow /* jump to interrupt routine */ - _endasm -} -#pragma code - -#pragma interrupt InterruptHandlerHigh -void InterruptHandlerHigh (void) -{ - #if 0 - /* check for USART Rx int */ - if ((PIR1bits.RCIF) && (PIE1bits.RCIE)) - { - if ((RCSTA1bits.FERR) || (RCSTA1bits.OERR)) - { - Comstat.Rx_Bufferoverrun = TRUE; - PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */ - } - else if (Comstat.Rx_Bytes++ < RX_BUFFER_SIZE - 1) - { - Rx_Buffer[Comstat.RxHead++] = RCREG1; - - /* Stick a Null on the end to let us use str functions on our - * buffer */ - Rx_Buffer[Comstat.RxHead] = 0; - } - else - { - Comstat.Rx_Bufferoverrun = TRUE; - PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */ - } - } - #endif - - /* check for timer0 int */ - if ((INTCONbits.TMR0IF) && (INTCONbits.TMR0IE)) - { - INTCONbits.TMR0IF = 0; - System_Seconds++; - } -} - -#pragma interruptlow InterruptHandlerLow save = PROD, section(".tmpdata"), TABLAT, TBLPTR, section \ - ("MATH_DATA") - -void InterruptHandlerLow(void) -{ - /* check for timer2 int */ - if ((PIR1bits.TMR2IF) && (PIE1bits.TMR2IE)) - { - PIR1bits.TMR2IF = 0; - Interrupt_Timer2(); - } - - /* check for timer3 int */ - if ((PIR2bits.TMR3IF) && (PIE2bits.TMR3IE)) - { - PIR2bits.TMR3IF = 0; - Interrupt_Timer3(); - } - - /* check for timer4 int */ - if ((PIR3bits.TMR4IF) && (PIE3bits.TMR4IE)) - { - PIR3bits.TMR4IF = 0; - dlmstp_millisecond_timer(); - Interrupt_Timer4(); - } - - /* check for compare int */ - if ((PIR2bits.CCP2IF) && (PIE2bits.CCP2IE)) - { - PIR2bits.CCP2IF = 0; - Interrupt_CCP2(); - } - - /* check for USART Tx int */ - if ((PIR3bits.TX2IF) && (PIE3bits.TX2IE)) - { - RS485_Interrupt_Tx(); - } - - /* check for USART Rx int */ - if ((PIR3bits.RC2IF) && (PIE3bits.RC2IE)) - { - RS485_Interrupt_Rx(); - } - -/* Unused Interrupts - //check for timer1 int - if ((PIR1bits.TMR1IF) && (PIE1bits.TMR1IE)) - { - PIR1bits.TMR1IF = 0; - Interrupt_Timer1(); - } - - //check for compare int - if ((PIR1bits.CCP1IF) && (PIE1bits.CCP1IE)) - { - PIR1bits.CCP1IF = 0; - Interrupt_CCP1(); - } - - //check for compare int - if ((PIR3bits.CCP3IF) && (PIE3bits.CCP3IE)) - { - PIR3bits.CCP3IF = 0; - Interrupt_CCP3(); - } - - //check for compare int - if ((PIR3bits.CCP4IF) && (PIE3bits.CCP4IE)) - { - PIR3bits.CCP4IF = 0; - - Interrupt_CCP4(); - } - - //check for AD int - if ((PIR1bits.ADIF) && (PIE1bits.ADIE)) - { - PIR1bits.ADIF = 0; - Interrupt_ADC(); - } - - //check for MSSP int - if ((PIR1bits.SSPIF) && (PIE1bits.SSPIE)) - { - PIR1bits.SSPIF = 0; - Interrupt_SSP(); - } - -*/ -} - -void Interrupt_Timer2(void) -{ -} - -void Interrupt_Timer3(void) -{ -} - -/* Timer4 is set to go off every 1ms. This is our system tick */ -void Interrupt_Timer4(void) -{ - /* Milisecond is our system tick */ - if (Milliseconds < 0xFF) - ++Milliseconds; -} - -void Interrupt_CCP2(void) -{ - -} - +/************************************************************************** +* +* Copyright (C) 2007 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ +#include +#include "stdint.h" +#include "hardware.h" +#include "rs485.h" +#include "dlmstp.h" + +/* from main.c */ +extern volatile uint8_t System_Seconds; +extern volatile uint8_t Milliseconds; + +void InterruptHandlerHigh(void); +void InterruptHandlerLow(void); +void Interrupt_Timer2(void); +void Interrupt_Timer3(void); +void Interrupt_Timer4(void); +void Interrupt_USART_Rx(void); +void Interrupt_USART_Tx(void); +void Interrupt_CCP2(void); +void INT0_Interrupt(void); + +#pragma code InterruptVectorHigh = 0x308 +void InterruptVectorHigh(void) +{ + _asm goto InterruptHandlerHigh /* jump to interrupt routine */ + _endasm} +#pragma code +#pragma code InterruptVectorLow = 0x318 +void InterruptVectorLow(void) +{ + _asm goto InterruptHandlerLow /* jump to interrupt routine */ + _endasm} +#pragma code +#pragma interrupt InterruptHandlerHigh +void InterruptHandlerHigh(void) +{ +#if 0 + /* check for USART Rx int */ + if ((PIR1bits.RCIF) && (PIE1bits.RCIE)) { + if ((RCSTA1bits.FERR) || (RCSTA1bits.OERR)) { + Comstat.Rx_Bufferoverrun = TRUE; + PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */ + } else if (Comstat.Rx_Bytes++ < RX_BUFFER_SIZE - 1) { + Rx_Buffer[Comstat.RxHead++] = RCREG1; + + /* Stick a Null on the end to let us use str functions on our + * buffer */ + Rx_Buffer[Comstat.RxHead] = 0; + } else { + Comstat.Rx_Bufferoverrun = TRUE; + PIE1bits.RC1IE = 0; /* Disable Interrupt on receipt */ + } + } +#endif + + /* check for timer0 int */ + if ((INTCONbits.TMR0IF) && (INTCONbits.TMR0IE)) { + INTCONbits.TMR0IF = 0; + System_Seconds++; + } +} + +#pragma interruptlow InterruptHandlerLow save = PROD, section(".tmpdata"), TABLAT, TBLPTR, section \ + ("MATH_DATA") + +void InterruptHandlerLow(void) +{ + /* check for timer2 int */ + if ((PIR1bits.TMR2IF) && (PIE1bits.TMR2IE)) { + PIR1bits.TMR2IF = 0; + Interrupt_Timer2(); + } + + /* check for timer3 int */ + if ((PIR2bits.TMR3IF) && (PIE2bits.TMR3IE)) { + PIR2bits.TMR3IF = 0; + Interrupt_Timer3(); + } + + /* check for timer4 int */ + if ((PIR3bits.TMR4IF) && (PIE3bits.TMR4IE)) { + PIR3bits.TMR4IF = 0; + dlmstp_millisecond_timer(); + Interrupt_Timer4(); + } + + /* check for compare int */ + if ((PIR2bits.CCP2IF) && (PIE2bits.CCP2IE)) { + PIR2bits.CCP2IF = 0; + Interrupt_CCP2(); + } + + /* check for USART Tx int */ + if ((PIR3bits.TX2IF) && (PIE3bits.TX2IE)) { + RS485_Interrupt_Tx(); + } + + /* check for USART Rx int */ + if ((PIR3bits.RC2IF) && (PIE3bits.RC2IE)) { + RS485_Interrupt_Rx(); + } + +/* Unused Interrupts + //check for timer1 int + if ((PIR1bits.TMR1IF) && (PIE1bits.TMR1IE)) + { + PIR1bits.TMR1IF = 0; + Interrupt_Timer1(); + } + + //check for compare int + if ((PIR1bits.CCP1IF) && (PIE1bits.CCP1IE)) + { + PIR1bits.CCP1IF = 0; + Interrupt_CCP1(); + } + + //check for compare int + if ((PIR3bits.CCP3IF) && (PIE3bits.CCP3IE)) + { + PIR3bits.CCP3IF = 0; + Interrupt_CCP3(); + } + + //check for compare int + if ((PIR3bits.CCP4IF) && (PIE3bits.CCP4IE)) + { + PIR3bits.CCP4IF = 0; + + Interrupt_CCP4(); + } + + //check for AD int + if ((PIR1bits.ADIF) && (PIE1bits.ADIE)) + { + PIR1bits.ADIF = 0; + Interrupt_ADC(); + } + + //check for MSSP int + if ((PIR1bits.SSPIF) && (PIE1bits.SSPIE)) + { + PIR1bits.SSPIF = 0; + Interrupt_SSP(); + } + +*/ +} + +void Interrupt_Timer2(void) +{ +} + +void Interrupt_Timer3(void) +{ +} + +/* Timer4 is set to go off every 1ms. This is our system tick */ +void Interrupt_Timer4(void) +{ + /* Milisecond is our system tick */ + if (Milliseconds < 0xFF) + ++Milliseconds; +} + +void Interrupt_CCP2(void) +{ + +} diff --git a/bacnet-stack/ports/pic18f6720/main.c b/bacnet-stack/ports/pic18f6720/main.c index 65815673..e820cbd3 100644 --- a/bacnet-stack/ports/pic18f6720/main.c +++ b/bacnet-stack/ports/pic18f6720/main.c @@ -1,169 +1,161 @@ -/************************************************************************** -* -* Copyright (C) 2007 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -#include -#include -#include /* for memmove */ -#include -#include -#include -#include "stdint.h" -#include "hardware.h" -/* BACnet */ -#include "apdu.h" -#include "datalink.h" -#include "dcc.h" -#include "handlers.h" -#include "iam.h" -#include "txbuf.h" - -volatile uint8_t Milliseconds = 0; -volatile uint8_t System_Seconds = 0; -volatile uint8_t Zero_Cross_Timeout = 0; - -static void BACnet_Service_Handlers_Init(void) -{ - /* 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. */ - /* We must implement read property - it's required! */ - apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, - handler_read_property); - //apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, - // handler_write_property); - apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE, - handler_reinitialize_device); - //apdu_set_unconfirmed_handler - // (SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION, - // handler_timesync_utc); - //apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION, - // handler_timesync); - /* handle communication so we can shutup when asked */ - apdu_set_confirmed_handler - (SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, - handler_device_communication_control); -} - -void Reinitialize(void) -{ - uint8_t i; - char name = 0; - - _asm reset _endasm -} - -void Global_Int( - enum INT_STATE state) /* FIX ME: add comment */ -{ - static uint8_t intstate = 0; - - switch (state) - { - case INT_DISABLED: - intstate >>= 2; - intstate |= (INTCON & 0xC0); - break; - case INT_ENABLED: - INTCONbits.GIE = 1; - INTCONbits.PEIE = 1; - intstate <<= 2; - break; - case INT_RESTORE: - INTCON |= (intstate & 0xC0); - intstate <<= 2; - break; - default: - break; - } -} - -void Initialize_Variables(void) -{ - /* Check to see if we need to initialize our eeproms */ - ENABLE_TIMER4_INT(); - /* interrupts must be enabled before we read our inputs */ - Global_Int(INT_ENABLED); - BACnet_Service_Handlers_Init(); - dlmstp_init(); - /* Start our time from now */ - Milliseconds = 0; - System_Seconds = 0; -} - -void Verify_Ints(void) -{ - /* Make sure the Abus data and clock lines are inputs. Also make sure - * that global interrupts are enabled. */ - if (!TRISCbits.TRISC3) - TRISCbits.TRISC3 = 1; - if (!TRISCbits.TRISC4) - TRISCbits.TRISC4 = 1; - if (!INTCONbits.GIE) - INTCONbits.GIE = 1; - if (!INTCONbits.PEIE) - INTCONbits.PEIE = 1; - /* if (!INTCONbits.INT0E) £ - * INTCONbits.INT0E=1; */ - if (!PIE1bits.TMR2IE) - PIE1bits.TMR2IE = 1; -} - -void MainTasks(void) -{ - /* Handle our millisecond counters */ - while (Milliseconds) - { - --Milliseconds; - } - /* Handle our seconds counters */ - while (System_Seconds) - { - dcc_timer_seconds(1); - System_Seconds--; - } -} - -void main(void) -{ - /* Note that before main is called, the SCL line is £ - * toggled 256 times to clear any I2C devices that £ - * may be holding the data line low £ - * Reset POR bit */ - RCONbits.NOT_POR = 1; - RCONbits.NOT_RI = 1; - Initialize_Variables(); - /* Handle anything that needs to be done on powerup */ - /* Greet the BACnet world! */ - iam_send(&Handler_Transmit_Buffer[0]); - /* Main loop */ - while (TRUE) - { - RESTART_WDT(); - Verify_Ints(); - dlmstp_task(); - MainTasks(); - } -} +/************************************************************************** +* +* Copyright (C) 2007 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +#include +#include +#include /* for memmove */ +#include +#include +#include +#include "stdint.h" +#include "hardware.h" +/* BACnet */ +#include "apdu.h" +#include "datalink.h" +#include "dcc.h" +#include "handlers.h" +#include "iam.h" +#include "txbuf.h" + +volatile uint8_t Milliseconds = 0; +volatile uint8_t System_Seconds = 0; +volatile uint8_t Zero_Cross_Timeout = 0; + +static void BACnet_Service_Handlers_Init(void) +{ + /* 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. */ + /* We must implement read property - it's required! */ + apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, + handler_read_property); + /*apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, */ + /* handler_write_property); */ + apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE, + handler_reinitialize_device); + /*apdu_set_unconfirmed_handler */ + /* (SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION, */ + /* handler_timesync_utc); */ + /*apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION, */ + /* handler_timesync); */ + /* handle communication so we can shutup when asked */ + apdu_set_confirmed_handler + (SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, + handler_device_communication_control); +} + +void Reinitialize(void) +{ + uint8_t i; + char name = 0; + +_asm reset _endasm} void Global_Int(enum INT_STATE state) +{ /* FIX ME: add comment */ + static uint8_t intstate = 0; + + switch (state) { + case INT_DISABLED: + intstate >>= 2; + intstate |= (INTCON & 0xC0); + break; + case INT_ENABLED: + INTCONbits.GIE = 1; + INTCONbits.PEIE = 1; + intstate <<= 2; + break; + case INT_RESTORE: + INTCON |= (intstate & 0xC0); + intstate <<= 2; + break; + default: + break; + } +} + +void Initialize_Variables(void) +{ + /* Check to see if we need to initialize our eeproms */ + ENABLE_TIMER4_INT(); + /* interrupts must be enabled before we read our inputs */ + Global_Int(INT_ENABLED); + BACnet_Service_Handlers_Init(); + dlmstp_init(); + /* Start our time from now */ + Milliseconds = 0; + System_Seconds = 0; +} + +void Verify_Ints(void) +{ + /* Make sure the Abus data and clock lines are inputs. Also make sure + * that global interrupts are enabled. */ + if (!TRISCbits.TRISC3) + TRISCbits.TRISC3 = 1; + if (!TRISCbits.TRISC4) + TRISCbits.TRISC4 = 1; + if (!INTCONbits.GIE) + INTCONbits.GIE = 1; + if (!INTCONbits.PEIE) + INTCONbits.PEIE = 1; + /* if (!INTCONbits.INT0E) £ + * INTCONbits.INT0E=1; */ + if (!PIE1bits.TMR2IE) + PIE1bits.TMR2IE = 1; +} + +void MainTasks(void) +{ + /* Handle our millisecond counters */ + while (Milliseconds) { + --Milliseconds; + } + /* Handle our seconds counters */ + while (System_Seconds) { + dcc_timer_seconds(1); + System_Seconds--; + } +} + +void main(void) +{ + /* Note that before main is called, the SCL line is £ + * toggled 256 times to clear any I2C devices that £ + * may be holding the data line low £ + * Reset POR bit */ + RCONbits.NOT_POR = 1; + RCONbits.NOT_RI = 1; + Initialize_Variables(); + /* Handle anything that needs to be done on powerup */ + /* Greet the BACnet world! */ + iam_send(&Handler_Transmit_Buffer[0]); + /* Main loop */ + while (TRUE) { + RESTART_WDT(); + Verify_Ints(); + dlmstp_task(); + MainTasks(); + } +} diff --git a/bacnet-stack/ports/pic18f6720/mstp.c b/bacnet-stack/ports/pic18f6720/mstp.c index 684e85cc..e586c210 100644 --- a/bacnet-stack/ports/pic18f6720/mstp.c +++ b/bacnet-stack/ports/pic18f6720/mstp.c @@ -1,1702 +1,1706 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2003 Steve Karg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307 - USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ - -/* This clause describes a Master-Slave/Token-Passing (MS/TP) data link */ -/* protocol, which provides the same services to the network layer as */ -/* ISO 8802-2 Logical Link Control. It uses services provided by the */ -/* EIA-485 physical layer. Relevant clauses of EIA-485 are deemed to be */ -/* included in this standard by reference. The following hardware is assumed: */ -/* (a) A UART (Universal Asynchronous Receiver/Transmitter) capable of */ -/* transmitting and receiving eight data bits with one stop bit */ -/* and no parity. */ -/* (b) An EIA-485 transceiver whose driver may be disabled. */ -/* (c) A timer with a resolution of five milliseconds or less */ - -#include -#include -#if PRINT_ENABLED -#include -#endif -#include "mstp.h" -#include "bytes.h" -#include "crc.h" -#include "rs485.h" - -/* debug print statements */ -#if PRINT_ENABLED - #define PRINT_ENABLED_RECEIVE 0 - #define PRINT_ENABLED_RECEIVE_DATA 1 - #define PRINT_ENABLED_MASTER 0 -#else - #define PRINT_ENABLED_RECEIVE 0 - #define PRINT_ENABLED_RECEIVE_DATA 0 - #define PRINT_ENABLED_MASTER 0 -#endif - -/* MS/TP Frame Format */ -/* All frames are of the following format: */ -/* */ -/* Preamble: two octet preamble: X`55', X`FF' */ -/* Frame Type: one octet */ -/* Destination Address: one octet address */ -/* Source Address: one octet address */ -/* Length: two octets, most significant octet first, of the Data field */ -/* Header CRC: one octet */ -/* Data: (present only if Length is non-zero) */ -/* Data CRC: (present only if Length is non-zero) two octets, */ -/* least significant octet first */ -/* (pad): (optional) at most one octet of padding: X'FF' */ - -/* The number of tokens received or used before a Poll For Master cycle */ -/* is executed: 50. */ -#define Npoll 50 - -/* The number of retries on sending Token: 1. */ -#define Nretry_token 1 - -/* The minimum number of DataAvailable or ReceiveError events that must be */ -/* seen by a receiving node in order to declare the line "active": 4. */ -#define Nmin_octets 4 - -/* The minimum time without a DataAvailable or ReceiveError event within */ -/* a frame before a receiving node may discard the frame: 60 bit times. */ -/* (Implementations may use larger values for this timeout, */ -/* not to exceed 100 milliseconds.) */ -/* At 9600 baud, 60 bit times would be about 6.25 milliseconds */ -/* const uint16_t Tframe_abort = 1 + ((1000 * 60) / 9600); */ -#define Tframe_abort 30 - -/* The maximum idle time a sending node may allow to elapse between octets */ -/* of a frame the node is transmitting: 20 bit times. */ -#define Tframe_gap 20 - -/* The time without a DataAvailable or ReceiveError event before declaration */ -/* of loss of token: 500 milliseconds. */ -#define Tno_token 500 - -/* The maximum time after the end of the stop bit of the final */ -/* octet of a transmitted frame before a node must disable its */ -/* EIA-485 driver: 15 bit times. */ -#define Tpostdrive 15 - -/* The maximum time a node may wait after reception of a frame that expects */ -/* a reply before sending the first octet of a reply or Reply Postponed */ -/* frame: 250 milliseconds. */ -/* note: we always send a reply postponed since a message other than - the reply may be in the transmit queue */ -#define Treply_delay 10 - -/* The minimum time without a DataAvailable or ReceiveError event */ -/* that a node must wait for a station to begin replying to a */ -/* confirmed request: 255 milliseconds. (Implementations may use */ -/* larger values for this timeout, not to exceed 300 milliseconds.) */ -#define Treply_timeout 255 - -/* Repeater turnoff delay. The duration of a continuous logical one state */ -/* at the active input port of an MS/TP repeater after which the repeater */ -/* will enter the IDLE state: 29 bit times < Troff < 40 bit times. */ -#define Troff 30 - -/* The width of the time slot within which a node may generate a token: */ -/* 10 milliseconds. */ -#define Tslot 10 - -/* The maximum time a node may wait after reception of the token or */ -/* a Poll For Master frame before sending the first octet of a frame: */ -/* 15 milliseconds. */ -#define Tusage_delay 15 - -/* The minimum time without a DataAvailable or ReceiveError event that a */ -/* node must wait for a remote node to begin using a token or replying to */ -/* a Poll For Master frame: 20 milliseconds. (Implementations may use */ -/* larger values for this timeout, not to exceed 100 milliseconds.) */ -#define Tusage_timeout 20 - -/* we need to be able to increment without rolling over */ -#define INCREMENT_AND_LIMIT_UINT8(x) {if (x < 0xFF) x++;} - -bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port) -{ - return (mstp_port->EventCount > Nmin_octets); -} - -unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */ - unsigned buffer_len, /* amount of space available */ - uint8_t frame_type, /* type of frame to send - see defines */ - uint8_t destination, /* destination address */ - uint8_t source, /* source address */ - uint8_t * data, /* any data to be sent - may be null */ - unsigned data_len) -{ /* number of bytes of data (up to 501) */ - uint8_t crc8 = 0xFF; /* used to calculate the crc value */ - uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */ - unsigned index = 0; /* used to load the data portion of the frame */ - - /* not enough to do a header */ - if (buffer_len < 8) - return 0; - - buffer[0] = 0x55; - buffer[1] = 0xFF; - buffer[2] = frame_type; - crc8 = CRC_Calc_Header(buffer[2], crc8); - buffer[3] = destination; - crc8 = CRC_Calc_Header(buffer[3], crc8); - buffer[4] = source; - crc8 = CRC_Calc_Header(buffer[4], crc8); - buffer[5] = data_len / 256; - crc8 = CRC_Calc_Header(buffer[5], crc8); - buffer[6] = data_len % 256; - crc8 = CRC_Calc_Header(buffer[6], crc8); - buffer[7] = ~crc8; - - index = 8; - while (data_len && data && (index < buffer_len)) { - buffer[index] = *data; - crc16 = CRC_Calc_Data(buffer[index], crc16); - data++; - index++; - data_len--; - } - /* append the data CRC if necessary */ - if (index > 8) { - if ((index + 2) <= buffer_len) { - crc16 = ~crc16; - buffer[index] = LO_BYTE(crc16); - index++; - buffer[index] = HI_BYTE(crc16); - index++; - } else - return 0; - } - - return index; /* returns the frame length */ -} - -void MSTP_Create_And_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port to send from */ - uint8_t frame_type, /* type of frame to send - see defines */ - uint8_t destination, /* destination address */ - uint8_t source, /* source address */ - uint8_t * data, /* any data to be sent - may be null */ - unsigned data_len) -{ /* number of bytes of data (up to 501) */ - uint8_t buffer[MAX_MPDU] = { 0 }; /* buffer for sending */ - uint16_t len = 0; /* number of bytes to send */ - - len = (uint16_t) MSTP_Create_Frame(&buffer[0], /* where frame is loaded */ - sizeof(buffer), /* amount of space available */ - frame_type, /* type of frame to send - see defines */ - destination, /* destination address */ - source, /* source address */ - data, /* any data to be sent - may be null */ - data_len); /* number of bytes of data (up to 501) */ - - RS485_Send_Frame(mstp_port, &buffer[0], len); - /* FIXME: be sure to reset SilenceTimer after each octet is sent! */ -} - -#if PRINT_ENABLED_RECEIVE -char *mstp_receive_state_text(int state) -{ - char *text = "unknown"; - - switch (state) { - case MSTP_RECEIVE_STATE_IDLE: - text = "IDLE"; - break; - case MSTP_RECEIVE_STATE_PREAMBLE: - text = "PREAMBLE"; - break; - case MSTP_RECEIVE_STATE_HEADER: - text = "HEADER"; - break; - case MSTP_RECEIVE_STATE_HEADER_CRC: - text = "HEADER_CRC"; - break; - case MSTP_RECEIVE_STATE_DATA: - text = "DATA"; - break; - default: - break; - } - - return text; -} -#endif - -void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port) -{ -#if PRINT_ENABLED_RECEIVE_DATA - static MSTP_RECEIVE_STATE receive_state = MSTP_RECEIVE_STATE_IDLE; -#endif -#if PRINT_ENABLED_RECEIVE - fprintf(stderr, - "MSTP Rx: State=%s Data=%02X hCRC=%02X Index=%u EC=%u DateLen=%u Silence=%u\n", - mstp_receive_state_text(mstp_port->receive_state), - mstp_port->DataRegister, mstp_port->HeaderCRC, mstp_port->Index, - mstp_port->EventCount, mstp_port->DataLength, - mstp_port->SilenceTimer); -#endif - switch (mstp_port->receive_state) { - /* In the IDLE state, the node waits for the beginning of a frame. */ - case MSTP_RECEIVE_STATE_IDLE: - /* EatAnError */ - if (mstp_port->ReceiveError == true) { - mstp_port->ReceiveError = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - /* wait for the start of a frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } else if (mstp_port->DataAvailable == true) { -#if PRINT_ENABLED_RECEIVE_DATA - fprintf(stderr, "MSTP Rx: %02X ", mstp_port->DataRegister); -#endif - /* Preamble1 */ - if (mstp_port->DataRegister == 0x55) { - mstp_port->DataAvailable = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - /* receive the remainder of the frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE; - } - /* EatAnOctet */ - else { -#if PRINT_ENABLED_RECEIVE_DATA - fprintf(stderr, "\n"); -#endif - mstp_port->DataAvailable = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - /* wait for the start of a frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - } - break; - /* In the PREAMBLE state, the node waits for the second octet of the preamble. */ - case MSTP_RECEIVE_STATE_PREAMBLE: - /* Timeout */ - if (mstp_port->SilenceTimer > Tframe_abort) { - /* a correct preamble has not been received */ - /* wait for the start of a frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - /* Error */ - else if (mstp_port->ReceiveError == true) { - mstp_port->ReceiveError = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - /* wait for the start of a frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } else if (mstp_port->DataAvailable == true) { -#if PRINT_ENABLED_RECEIVE_DATA - fprintf(stderr, "%02X ", mstp_port->DataRegister); -#endif - /* Preamble2 */ - if (mstp_port->DataRegister == 0xFF) { - mstp_port->DataAvailable = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - mstp_port->Index = 0; - mstp_port->HeaderCRC = 0xFF; - /* receive the remainder of the frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; - } - /* ignore RepeatedPreamble1 */ - else if (mstp_port->DataRegister == 0x55) { - mstp_port->DataAvailable = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - /* wait for the second preamble octet. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE; - } - /* NotPreamble */ - else { - mstp_port->DataAvailable = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - /* wait for the start of a frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - } - break; - /* In the HEADER state, the node waits for the fixed message header. */ - case MSTP_RECEIVE_STATE_HEADER: - /* Timeout */ - if (mstp_port->SilenceTimer > Tframe_abort) { - /* indicate that an error has occurred during the reception of a frame */ - mstp_port->ReceivedInvalidFrame = true; - /* wait for the start of a frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - /* Error */ - else if (mstp_port->ReceiveError == true) { - mstp_port->ReceiveError = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - /* indicate that an error has occurred during the reception of a frame */ - mstp_port->ReceivedInvalidFrame = true; - /* wait for the start of a frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } else if (mstp_port->DataAvailable == true) { -#if PRINT_ENABLED_RECEIVE_DATA - fprintf(stderr, "%02X ", mstp_port->DataRegister); -#endif - /* FrameType */ - if (mstp_port->Index == 0) { - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - mstp_port->HeaderCRC = - CRC_Calc_Header(mstp_port->DataRegister, - mstp_port->HeaderCRC); - mstp_port->FrameType = mstp_port->DataRegister; - mstp_port->DataAvailable = false; - mstp_port->Index = 1; - mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; - } - /* Destination */ - else if (mstp_port->Index == 1) { - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - mstp_port->HeaderCRC = - CRC_Calc_Header(mstp_port->DataRegister, - mstp_port->HeaderCRC); - mstp_port->DestinationAddress = mstp_port->DataRegister; - mstp_port->DataAvailable = false; - mstp_port->Index = 2; - mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; - } - /* Source */ - else if (mstp_port->Index == 2) { - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - mstp_port->HeaderCRC = - CRC_Calc_Header(mstp_port->DataRegister, - mstp_port->HeaderCRC); - mstp_port->SourceAddress = mstp_port->DataRegister; - mstp_port->DataAvailable = false; - mstp_port->Index = 3; - mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; - } - /* Length1 */ - else if (mstp_port->Index == 3) { - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - mstp_port->HeaderCRC = - CRC_Calc_Header(mstp_port->DataRegister, - mstp_port->HeaderCRC); - mstp_port->DataLength = mstp_port->DataRegister * 256; - mstp_port->DataAvailable = false; - mstp_port->Index = 4; - mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; - } - /* Length2 */ - else if (mstp_port->Index == 4) { - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - mstp_port->HeaderCRC = - CRC_Calc_Header(mstp_port->DataRegister, - mstp_port->HeaderCRC); - mstp_port->DataLength += mstp_port->DataRegister; - mstp_port->DataAvailable = false; - mstp_port->Index = 5; - mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; - } - /* HeaderCRC */ - else if (mstp_port->Index == 5) { - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - mstp_port->HeaderCRC = - CRC_Calc_Header(mstp_port->DataRegister, - mstp_port->HeaderCRC); - mstp_port->DataAvailable = false; - /* don't wait for next state - do it here */ - /* MSTP_RECEIVE_STATE_HEADER_CRC */ - if (mstp_port->HeaderCRC != 0x55) { - /* BadCRC */ - /* indicate that an error has occurred during the reception of a frame */ - mstp_port->ReceivedInvalidFrame = true; - /* wait for the start of the next frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } else { - if ((mstp_port->DestinationAddress == mstp_port->This_Station) - || (mstp_port->DestinationAddress == - MSTP_BROADCAST_ADDRESS)) { - /* FrameTooLong */ - if (mstp_port->DataLength > MAX_MPDU) { - /* indicate that a frame with an illegal or */ - /* unacceptable data length has been received */ - mstp_port->ReceivedInvalidFrame = true; - /* wait for the start of the next frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - /* NoData */ - else if (mstp_port->DataLength == 0) { - /* indicate that a frame with no data has been received */ - mstp_port->ReceivedValidFrame = true; - /* wait for the start of the next frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - /* Data */ - else { - mstp_port->Index = 0; - mstp_port->DataCRC = 0xFFFF; - /* receive the data portion of the frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; - } - } - /* NotForUs */ - else { - /* wait for the start of the next frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - } - - - } - /* not per MS/TP standard, but it is a case not covered */ - else { - mstp_port->ReceiveError = false; - mstp_port->SilenceTimer = 0; - INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); - /* indicate that an error has occurred during */ - /* the reception of a frame */ - mstp_port->ReceivedInvalidFrame = true; - /* wait for the start of a frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - } - break; - /* In the HEADER_CRC state, the node validates the CRC on the fixed */ - /* message header. */ - case MSTP_RECEIVE_STATE_HEADER_CRC: - break; - /* In the DATA state, the node waits for the data portion of a frame. */ - case MSTP_RECEIVE_STATE_DATA: - /* Timeout */ - if (mstp_port->SilenceTimer > Tframe_abort) { - /* indicate that an error has occurred during the reception of a frame */ - mstp_port->ReceivedInvalidFrame = true; - /* wait for the start of the next frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - /* Error */ - else if (mstp_port->ReceiveError == true) { - mstp_port->ReceiveError = false; - mstp_port->SilenceTimer = 0; - /* indicate that an error has occurred during the reception of a frame */ - mstp_port->ReceivedInvalidFrame = true; - /* wait for the start of the next frame. */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } else if (mstp_port->DataAvailable == true) { -#if PRINT_ENABLED_RECEIVE_DATA - fprintf(stderr, "%02X ", mstp_port->DataRegister); -#endif - /* DataOctet */ - if (mstp_port->Index < mstp_port->DataLength) { - mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister, - mstp_port->DataCRC); - mstp_port->InputBuffer[mstp_port->Index] = - mstp_port->DataRegister; - mstp_port->Index++; - mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; - } - /* CRC1 */ - else if (mstp_port->Index == mstp_port->DataLength) { - mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister, - mstp_port->DataCRC); - mstp_port->Index++; - mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; - } - /* CRC2 */ - else if (mstp_port->Index == (mstp_port->DataLength + 1)) { - mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister, - mstp_port->DataCRC); - /* STATE DATA CRC - no need for new state */ - /* indicate the complete reception of a valid frame */ - if (mstp_port->DataCRC == 0xF0B8) - mstp_port->ReceivedValidFrame = true; - else - mstp_port->ReceivedInvalidFrame = true; - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - } - mstp_port->DataAvailable = false; - mstp_port->SilenceTimer = 0; - } - break; - default: - /* shouldn't get here - but if we do... */ - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - break; - } -#if PRINT_ENABLED_RECEIVE_DATA - if ((receive_state != MSTP_RECEIVE_STATE_IDLE) && - (mstp_port->receive_state == MSTP_RECEIVE_STATE_IDLE)) { - fprintf(stderr, "\n"); - fflush(stderr); - } - receive_state = mstp_port->receive_state; -#endif - - return; -} - -#if PRINT_ENABLED -char *mstp_master_state_text(int state) -{ - char *text = "unknown"; - - switch (state) { - case MSTP_MASTER_STATE_INITIALIZE: - text = "INITIALIZE"; - break; - case MSTP_MASTER_STATE_IDLE: - text = "IDLE"; - break; - case MSTP_MASTER_STATE_USE_TOKEN: - text = "USE_TOKEN"; - break; - case MSTP_MASTER_STATE_WAIT_FOR_REPLY: - text = "WAIT_FOR_REPLY"; - break; - case MSTP_MASTER_STATE_DONE_WITH_TOKEN: - text = "IDLE"; - break; - case MSTP_MASTER_STATE_PASS_TOKEN: - text = "DONE_WITH_TOKEN"; - break; - case MSTP_MASTER_STATE_NO_TOKEN: - text = "NO_TOKEN"; - break; - case MSTP_MASTER_STATE_POLL_FOR_MASTER: - text = "POLL_FOR_MASTER"; - break; - case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: - text = "ANSWER_DATA_REQUEST"; - break; - default: - break; - } - - return text; -} -#endif - -#if PRINT_ENABLED -char *mstp_frame_type_text(int type) -{ - char *text = "unknown"; - - switch (type) { - case FRAME_TYPE_TOKEN: - text = "TOKEN"; - break; - case FRAME_TYPE_POLL_FOR_MASTER: - text = "POLL_FOR_MASTER"; - break; - case FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER: - text = "REPLY_TO_POLL_FOR_MASTER"; - break; - case FRAME_TYPE_TEST_REQUEST: - text = "TEST_REQUEST"; - break; - case FRAME_TYPE_TEST_RESPONSE: - text = "TEST_RESPONSE"; - break; - case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - text = "BACNET_DATA_EXPECTING_REPLY"; - break; - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - text = "BACNET_DATA_NOT_EXPECTING_REPLY"; - break; - case FRAME_TYPE_REPLY_POSTPONED: - text = "REPLY_POSTPONED"; - break; - default: - if ((type >= FRAME_TYPE_PROPRIETARY_MIN) && - (type <= FRAME_TYPE_PROPRIETARY_MAX)) - text = "PROPRIETARY"; - break; - } - - return text; -} -#endif - -/* returns true if we need to transition immediately */ -bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port) -{ - int mtu_len = 0; - int frame_type = 0; - uint8_t next_poll_station = 0; - uint8_t next_this_station = 0; - uint8_t next_next_station = 0; - uint16_t my_timeout = 10, ns_timeout = 0; - /* transition immediately to the next state */ - bool transition_now = false; -#if PRINT_ENABLED_MASTER - static MSTP_MASTER_STATE master_state = MSTP_MASTER_STATE_INITIALIZE; -#endif - - /* some calculations that several states need */ - next_poll_station = (mstp_port->Poll_Station + 1) % - (mstp_port->Nmax_master + 1); - next_this_station = (mstp_port->This_Station + 1) % - (mstp_port->Nmax_master + 1); - next_next_station = (mstp_port->Next_Station + 1) % - (mstp_port->Nmax_master + 1); -#if PRINT_ENABLED_MASTER - if (mstp_port->master_state != master_state) { - master_state = mstp_port->master_state; - fprintf(stderr, - "MSTP: TS=%02X[%02X] NS=%02X[%02X] PS=%02X[%02X] EC=%u TC=%u ST=%u %s\n", - mstp_port->This_Station, - next_this_station, - mstp_port->Next_Station, - next_next_station, - mstp_port->Poll_Station, - next_poll_station, - mstp_port->EventCount, - mstp_port->TokenCount, - mstp_port->SilenceTimer, - mstp_master_state_text(mstp_port->master_state)); - } -#endif - - switch (mstp_port->master_state) { - case MSTP_MASTER_STATE_INITIALIZE: - /* DoneInitializing */ - /* indicate that the next station is unknown */ - mstp_port->Next_Station = mstp_port->This_Station; - mstp_port->Poll_Station = mstp_port->This_Station; - /* cause a Poll For Master to be sent when this node first */ - /* receives the token */ - mstp_port->TokenCount = Npoll; - mstp_port->SoleMaster = false; - mstp_port->ReceivedValidFrame = false; - mstp_port->ReceivedInvalidFrame = false; - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - transition_now = true; - break; - /* In the IDLE state, the node waits for a frame. */ - case MSTP_MASTER_STATE_IDLE: - /* LostToken */ - if (mstp_port->SilenceTimer >= Tno_token) { - /* assume that the token has been lost */ - mstp_port->EventCount = 0; /* Addendum 135-2004d-8 */ - mstp_port->master_state = MSTP_MASTER_STATE_NO_TOKEN; - transition_now = true; - } - /* ReceivedInvalidFrame */ - else if (mstp_port->ReceivedInvalidFrame == true) { - /* invalid frame was received */ - mstp_port->ReceivedInvalidFrame = false; - /* wait for the next frame - remain in IDLE */ - } else if (mstp_port->ReceivedValidFrame == true) { -#if PRINT_ENABLED_MASTER - fprintf(stderr, - "MSTP: ReceivedValidFrame Src=%02X Dest=%02X DataLen=%u FC=%u ST=%u Type=%s\n", - mstp_port->SourceAddress, - mstp_port->DestinationAddress, - mstp_port->DataLength, - mstp_port->FrameCount, - mstp_port->SilenceTimer, - mstp_frame_type_text(mstp_port->FrameType)); -#endif - /* destined for me! */ - if ((mstp_port->DestinationAddress == - mstp_port->This_Station) || - (mstp_port->DestinationAddress == - MSTP_BROADCAST_ADDRESS)) { - switch (mstp_port->FrameType) { - /* ReceivedToken */ - case FRAME_TYPE_TOKEN: - /* tokens can't be broadcast */ - if (mstp_port->DestinationAddress == - MSTP_BROADCAST_ADDRESS) - break; - mstp_port->ReceivedValidFrame = false; - mstp_port->FrameCount = 0; - mstp_port->SoleMaster = false; - mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - break; - /* ReceivedPFM */ - case FRAME_TYPE_POLL_FOR_MASTER: - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, - mstp_port->SourceAddress, mstp_port->This_Station, - NULL, 0); - break; - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - /* indicate successful reception to the higher layers */ - dlmstp_put_receive(mstp_port->SourceAddress, - (uint8_t *) & mstp_port->InputBuffer[0], - mstp_port->DataLength); - break; - case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - //mstp_port->ReplyPostponedTimer = 0; - /* indicate successful reception to the higher layers */ - dlmstp_put_receive(mstp_port->SourceAddress, - (uint8_t *) & mstp_port->InputBuffer[0], - mstp_port->DataLength); - /* broadcast DER just remains IDLE */ - if (mstp_port->DestinationAddress != - MSTP_BROADCAST_ADDRESS) { - mstp_port->master_state = - MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; - } - break; - case FRAME_TYPE_TEST_REQUEST: - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_TEST_RESPONSE, - mstp_port->SourceAddress, mstp_port->This_Station, - NULL, 0); - break; - case FRAME_TYPE_TEST_RESPONSE: - default: - break; - } - } - mstp_port->ReceivedValidFrame = false; - } - break; - /* In the USE_TOKEN state, the node is allowed to send one or */ - /* more data frames. These may be BACnet Data frames or */ - /* proprietary frames. */ - case MSTP_MASTER_STATE_USE_TOKEN: - if (!mstp_port->TxReady) { - /* NothingToSend */ - mstp_port->FrameCount = mstp_port->Nmax_info_frames; - mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; - transition_now = true; - } else if (mstp_port->SilenceTimer > Tusage_delay) { - /* if we missed our timing deadline, another token will be sent */ - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - } else { - /* don't send it if we are too late in getting out */ - uint8_t destination = mstp_port->TxBuffer[3]; - RS485_Send_Frame(mstp_port, - (uint8_t *) & mstp_port->TxBuffer[0], mstp_port->TxLength); - mstp_port->FrameCount++; - switch (mstp_port->TxFrameType) { - case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - /* SendAndWait */ - if (destination == MSTP_BROADCAST_ADDRESS) - mstp_port->master_state = - MSTP_MASTER_STATE_DONE_WITH_TOKEN; - else - mstp_port->master_state = - MSTP_MASTER_STATE_WAIT_FOR_REPLY; - break; - case FRAME_TYPE_TEST_REQUEST: - mstp_port->master_state = MSTP_MASTER_STATE_WAIT_FOR_REPLY; - break; - case FRAME_TYPE_TEST_RESPONSE: - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - default: - /* SendNoWait */ - mstp_port->master_state = - MSTP_MASTER_STATE_DONE_WITH_TOKEN; - break; - } - mstp_port->TxReady = false; - } - break; - /* In the WAIT_FOR_REPLY state, the node waits for */ - /* a reply from another node. */ - case MSTP_MASTER_STATE_WAIT_FOR_REPLY: - if (mstp_port->SilenceTimer >= Treply_timeout) { - /* ReplyTimeout */ - /* assume that the request has failed */ - mstp_port->FrameCount = mstp_port->Nmax_info_frames; - mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; - /* Any retry of the data frame shall await the next entry */ - /* to the USE_TOKEN state. (Because of the length of the timeout, */ - /* this transition will cause the token to be passed regardless */ - /* of the initial value of FrameCount.) */ - transition_now = true; - } else { - if (mstp_port->ReceivedInvalidFrame == true) { - /* InvalidFrame */ - /* error in frame reception */ - mstp_port->ReceivedInvalidFrame = false; - mstp_port->master_state = - MSTP_MASTER_STATE_DONE_WITH_TOKEN; - transition_now = true; - } else if (mstp_port->ReceivedValidFrame == true) { - if (mstp_port->DestinationAddress == - mstp_port->This_Station) { - switch (mstp_port->TxFrameType) { - case FRAME_TYPE_REPLY_POSTPONED: - /* ReceivedReplyPostponed */ - mstp_port->master_state = - MSTP_MASTER_STATE_DONE_WITH_TOKEN; - break; - case FRAME_TYPE_TEST_RESPONSE: - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - break; - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - /* ReceivedReply */ - /* or a proprietary type that indicates a reply */ - /* indicate successful reception to the higher layers */ - dlmstp_put_receive(mstp_port->SourceAddress, /* source MS/TP address */ - (uint8_t *) & mstp_port->InputBuffer[0], - mstp_port->DataLength); - mstp_port->master_state = - MSTP_MASTER_STATE_DONE_WITH_TOKEN; - break; - default: - /* if proprietary frame was expected, you might - need to transition to DONE WITH TOKEN */ - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - break; - } - } else { - /* ReceivedUnexpectedFrame */ - /* an unexpected frame was received */ - /* This may indicate the presence of multiple tokens. */ - /* Synchronize with the network. */ - /* This action drops the token. */ - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - } - mstp_port->ReceivedValidFrame = false; - transition_now = true; - } - } - break; - /* The DONE_WITH_TOKEN state either sends another data frame, */ - /* passes the token, or initiates a Poll For Master cycle. */ - case MSTP_MASTER_STATE_DONE_WITH_TOKEN: - /* SendAnotherFrame */ - if (mstp_port->FrameCount < mstp_port->Nmax_info_frames) { - /* then this node may send another information frame */ - /* before passing the token. */ - mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - } - /* Npoll changed in Errata SSPC-135-2004 */ - else if (mstp_port->TokenCount < (Npoll - 1)) { - if ((mstp_port->SoleMaster == true) && - (mstp_port->Next_Station != next_this_station)) { - /* SoleMaster */ - /* there are no other known master nodes to */ - /* which the token may be sent (true master-slave operation). */ - mstp_port->FrameCount = 0; - mstp_port->TokenCount++; - mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - } else { - /* SendToken */ - /* Npoll changed in Errata SSPC-135-2004 */ - /* The comparison of NS and TS+1 eliminates the Poll For Master */ - /* if there are no addresses between TS and NS, since there is no */ - /* address at which a new master node may be found in that case. */ - mstp_port->TokenCount++; - /* transmit a Token frame to NS */ - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_TOKEN, - mstp_port->Next_Station, - mstp_port->This_Station, NULL, 0); - mstp_port->RetryCount = 0; - mstp_port->EventCount = 0; - mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; - } - } else if (next_poll_station == mstp_port->Next_Station) { - if (mstp_port->SoleMaster == true) { - /* SoleMasterRestartMaintenancePFM */ - mstp_port->Poll_Station = next_poll_station; - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_POLL_FOR_MASTER, mstp_port->Poll_Station, - mstp_port->This_Station, NULL, 0); - /* no known successor node */ - mstp_port->Next_Station = mstp_port->This_Station; - mstp_port->RetryCount = 0; - mstp_port->TokenCount = 1; /* changed in Errata SSPC-135-2004 */ - /* mstp_port->EventCount = 0; removed in Addendum 135-2004d-8 */ - /* find a new successor to TS */ - mstp_port->master_state = - MSTP_MASTER_STATE_POLL_FOR_MASTER; - } else { - /* ResetMaintenancePFM */ - mstp_port->Poll_Station = mstp_port->This_Station; - /* transmit a Token frame to NS */ - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_TOKEN, - mstp_port->Next_Station, - mstp_port->This_Station, NULL, 0); - mstp_port->RetryCount = 0; - mstp_port->TokenCount = 1; /* changed in Errata SSPC-135-2004 */ - mstp_port->EventCount = 0; - mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; - } - } else { - /* SendMaintenancePFM */ - mstp_port->Poll_Station = next_poll_station; - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_POLL_FOR_MASTER, - mstp_port->Poll_Station, mstp_port->This_Station, NULL, 0); - mstp_port->RetryCount = 0; - mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; - } - break; - /* The PASS_TOKEN state listens for a successor to begin using */ - /* the token that this node has just attempted to pass. */ - case MSTP_MASTER_STATE_PASS_TOKEN: - if (mstp_port->SilenceTimer < Tusage_timeout) { - if (mstp_port->EventCount > Nmin_octets) { - /* SawTokenUser */ - /* Assume that a frame has been sent by the new token user. */ - /* Enter the IDLE state to process the frame. */ - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - transition_now = true; - } - } else { - if (mstp_port->RetryCount < Nretry_token) { - /* RetrySendToken */ - mstp_port->RetryCount++; - /* Transmit a Token frame to NS */ - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_TOKEN, - mstp_port->Next_Station, mstp_port->This_Station, NULL, - 0); - mstp_port->EventCount = 0; - /* re-enter the current state to listen for NS */ - /* to begin using the token. */ - } else { - /* FindNewSuccessor */ - /* Assume that NS has failed. */ - mstp_port->Poll_Station = next_next_station; - /* Transmit a Poll For Master frame to PS. */ - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_POLL_FOR_MASTER, - mstp_port->Poll_Station, mstp_port->This_Station, NULL, - 0); - /* no known successor node */ - mstp_port->Next_Station = mstp_port->This_Station; - mstp_port->RetryCount = 0; - mstp_port->TokenCount = 0; - /* mstp_port->EventCount = 0; removed in Addendum 135-2004d-8 */ - /* find a new successor to TS */ - mstp_port->master_state = - MSTP_MASTER_STATE_POLL_FOR_MASTER; - } - } - break; - /* The NO_TOKEN state is entered if mstp_port->SilenceTimer becomes greater */ - /* than Tno_token, indicating that there has been no network activity */ - /* for that period of time. The timeout is continued to determine */ - /* whether or not this node may create a token. */ - case MSTP_MASTER_STATE_NO_TOKEN: - my_timeout = Tno_token + (Tslot * mstp_port->This_Station); - if (mstp_port->SilenceTimer < my_timeout) { - if (mstp_port->EventCount > Nmin_octets) { - /* SawFrame */ - /* Some other node exists at a lower address. */ - /* Enter the IDLE state to receive and process the incoming frame. */ - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - transition_now = true; - } - } else { - ns_timeout = - Tno_token + (Tslot * (mstp_port->This_Station + 1)); - if (mstp_port->SilenceTimer < ns_timeout) { - /* GenerateToken */ - /* Assume that this node is the lowest numerical address */ - /* on the network and is empowered to create a token. */ - mstp_port->Poll_Station = next_this_station; - /* Transmit a Poll For Master frame to PS. */ - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_POLL_FOR_MASTER, - mstp_port->Poll_Station, mstp_port->This_Station, NULL, - 0); - /* indicate that the next station is unknown */ - mstp_port->Next_Station = mstp_port->This_Station; - mstp_port->RetryCount = 0; - mstp_port->TokenCount = 0; - /* mstp_port->EventCount = 0; removed Addendum 135-2004d-8 */ - /* enter the POLL_FOR_MASTER state to find a new successor to TS. */ - mstp_port->master_state = - MSTP_MASTER_STATE_POLL_FOR_MASTER; - } - } - break; - /* In the POLL_FOR_MASTER state, the node listens for a reply to */ - /* a previously sent Poll For Master frame in order to find */ - /* a successor node. */ - case MSTP_MASTER_STATE_POLL_FOR_MASTER: - if (mstp_port->ReceivedValidFrame == true) { - if ((mstp_port->DestinationAddress == mstp_port->This_Station) - && (mstp_port->FrameType == - FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER)) { - /* ReceivedReplyToPFM */ - mstp_port->SoleMaster = false; - mstp_port->Next_Station = mstp_port->SourceAddress; - mstp_port->EventCount = 0; - /* Transmit a Token frame to NS */ - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_TOKEN, - mstp_port->Next_Station, mstp_port->This_Station, NULL, - 0); - mstp_port->Poll_Station = mstp_port->This_Station; - mstp_port->TokenCount = 0; - mstp_port->RetryCount = 0; - mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; - } else { - /* ReceivedUnexpectedFrame */ - /* An unexpected frame was received. */ - /* This may indicate the presence of multiple tokens. */ - /* enter the IDLE state to synchronize with the network. */ - /* This action drops the token. */ - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - transition_now = true; - } - mstp_port->ReceivedValidFrame = false; - } else if ((mstp_port->SilenceTimer >= Tusage_timeout) || - (mstp_port->ReceivedInvalidFrame == true)) { - if (mstp_port->SoleMaster == true) { - /* SoleMaster */ - /* There was no valid reply to the periodic poll */ - /* by the sole known master for other masters. */ - mstp_port->FrameCount = 0; - /* mstp_port->TokenCount++; removed in 2004 */ - mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - } else { - if (mstp_port->Next_Station != mstp_port->This_Station) { - /* DoneWithPFM */ - /* There was no valid reply to the maintenance */ - /* poll for a master at address PS. */ - mstp_port->EventCount = 0; - /* transmit a Token frame to NS */ - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_TOKEN, - mstp_port->Next_Station, mstp_port->This_Station, - NULL, 0); - mstp_port->RetryCount = 0; - mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; - } else { - if (next_poll_station != mstp_port->This_Station) { - /* SendNextPFM */ - mstp_port->Poll_Station = next_poll_station; - /* Transmit a Poll For Master frame to PS. */ - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_POLL_FOR_MASTER, - mstp_port->Poll_Station, - mstp_port->This_Station, NULL, 0); - mstp_port->RetryCount = 0; - /* Re-enter the current state. */ - } else { - /* DeclareSoleMaster */ - /* to indicate that this station is the only master */ - mstp_port->SoleMaster = true; - mstp_port->FrameCount = 0; - mstp_port->master_state = - MSTP_MASTER_STATE_USE_TOKEN; - transition_now = true; - } - } - } - mstp_port->ReceivedInvalidFrame = false; - } - break; - /* The ANSWER_DATA_REQUEST state is entered when a */ - /* BACnet Data Expecting Reply, a Test_Request, or */ - /* a proprietary frame that expects a reply is received. */ - case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: - /* FIXME: if we knew the APDU type received, we could - see if the next message was that same APDU type */ - if ((mstp_port->SilenceTimer <= Treply_delay) && - mstp_port->TxReady) { - /* Reply */ - /* If a reply is available from the higher layers */ - /* within Treply_delay after the reception of the */ - /* final octet of the requesting frame */ - /* (the mechanism used to determine this is a local matter), */ - /* then call MSTP_Create_And_Send_Frame to transmit the reply frame */ - /* and enter the IDLE state to wait for the next frame. */ - if ((mstp_port->FrameType == - FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) - && (mstp_port->TxReady)) { - RS485_Send_Frame(mstp_port, - (uint8_t *) & mstp_port->TxBuffer[0], - mstp_port->TxLength); - mstp_port->TxReady = false; - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - } - } - /* DeferredReply */ - /* If no reply will be available from the higher layers */ - /* within Treply_delay after the reception of the */ - /* final octet of the requesting frame (the mechanism */ - /* used to determine this is a local matter), */ - /* then an immediate reply is not possible. */ - /* Any reply shall wait until this node receives the token. */ - /* Call MSTP_Create_And_Send_Frame to transmit a Reply Postponed frame, */ - /* and enter the IDLE state. */ - else { - MSTP_Create_And_Send_Frame(mstp_port, - FRAME_TYPE_REPLY_POSTPONED, - mstp_port->SourceAddress, - mstp_port->This_Station, NULL, 0); - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - } - break; - default: - mstp_port->master_state = MSTP_MASTER_STATE_IDLE; - break; - } - - return transition_now; -} - -/* note: This_Station should be set with the MAC address */ -/* note: Nmax_info_frames should be set */ -/* note: Nmax_master should be set */ -void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port) -{ - int i; /*loop counter */ - - if (mstp_port) { - mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; - mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE; - mstp_port->ReceiveError = false; - mstp_port->DataAvailable = false; - mstp_port->DataRegister = 0; - mstp_port->DataCRC = 0; - mstp_port->DataCRC = 0; - mstp_port->DataLength = 0; - mstp_port->DestinationAddress = 0; - mstp_port->EventCount = 0; - mstp_port->FrameType = FRAME_TYPE_TOKEN; - mstp_port->FrameCount = 0; - mstp_port->HeaderCRC = 0; - mstp_port->Index = 0; - mstp_port->Index = 0; - for (i = 0; i < sizeof(mstp_port->InputBuffer); i++) { - mstp_port->InputBuffer[i] = 0; - } - mstp_port->Next_Station = mstp_port->This_Station; - mstp_port->Poll_Station = mstp_port->This_Station; - mstp_port->ReceivedInvalidFrame = false; - mstp_port->ReceivedValidFrame = false; - mstp_port->RetryCount = 0; - mstp_port->SilenceTimer = 0; -// mstp_port->ReplyPostponedTimer = 0; - mstp_port->SoleMaster = false; - mstp_port->SourceAddress = 0; - mstp_port->TokenCount = 0; - #if 0 - // these are adjustable, so should already be set - mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES; - mstp_port->Nmax_master = DEFAULT_MAX_MASTER; - #endif - - /* An array of octets, used to store PDU octets prior to being transmitted. */ - /* This array is only used for APDU messages */ - for (i = 0; i < sizeof(mstp_port->TxBuffer); i++) { - mstp_port->TxBuffer[i] = 0; - } - mstp_port->TxLength = 0; - mstp_port->TxReady = false; - mstp_port->TxFrameType = 0; - - } -} - -#ifdef TEST -#include -#include -#include "ctest.h" - -/* test stub functions */ -void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ - uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ - uint16_t nbytes) -{ /* number of bytes of data (up to 501) */ - (void) mstp_port; - (void) buffer; - (void) nbytes; -} - -#define RING_BUFFER_DATA_SIZE 1 -#define RING_BUFFER_SIZE MAX_MPDU -static RING_BUFFER Test_Buffer; -static uint8_t Test_Buffer_Data[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE]; -static void Load_Input_Buffer(uint8_t * buffer, size_t len) -{ - static bool initialized = false; /* tracks our init */ - - - if (!initialized) { - initialized = true; - Ringbuf_Init(&Test_Buffer, - (char *) Test_Buffer_Data, - RING_BUFFER_DATA_SIZE, RING_BUFFER_SIZE); - } - /* empty any the existing data */ - while (!Ringbuf_Empty(&Test_Buffer)) { - (void) Ringbuf_Pop_Front(&Test_Buffer); - } - - if (buffer) { - while (len) { - (void) Ringbuf_Put(&Test_Buffer, (char *) buffer); - len--; - buffer++; - } - } -} - -void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) -{ /* port specific data */ - char *data; - if (!Ringbuf_Empty(&Test_Buffer) && mstp_port && - (mstp_port->DataAvailable == false)) { - data = Ringbuf_Pop_Front(&Test_Buffer); - if (data) { - mstp_port->DataRegister = *data; - mstp_port->DataAvailable = true; - } - } -} - -void testReceiveNodeFSM(Test * pTest) -{ - volatile struct mstp_port_struct_t mstp_port; /* port data */ - unsigned EventCount = 0; /* local counter */ - uint8_t my_mac = 0x05; /* local MAC address */ - uint8_t HeaderCRC = 0; /* for local CRC calculation */ - uint8_t FrameType = 0; /* type of packet that was sent */ - unsigned len; /* used for the size of the message packet */ - size_t i; /* used to loop through the message bytes */ - uint8_t buffer[MAX_MPDU] = { 0 }; - uint8_t data[MAX_MPDU - 8 /*header */ - 2 /*CRC*/] = { 0 }; - - MSTP_Init(&mstp_port, my_mac); - - /* check the receive error during idle */ - mstp_port.receive_state = MSTP_RECEIVE_STATE_IDLE; - mstp_port.ReceiveError = true; - mstp_port.SilenceTimer = 255; - mstp_port.EventCount = 0; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.ReceiveError == false); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* check for bad packet header */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x11; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* check for good packet header, but timeout */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x55; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - /* force the timeout */ - mstp_port.SilenceTimer = Tframe_abort + 1; - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* check for good packet header preamble, but receive error */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x55; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - /* force the error */ - mstp_port.ReceiveError = true; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.ReceiveError == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* check for good packet header preamble1, but bad preamble2 */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x55; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - MSTP_Receive_Frame_FSM(&mstp_port); - /* no change of state if no data yet */ - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - /* repeated preamble1 */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x55; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - /* repeated preamble1 */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x55; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - /* bad data */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x11; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.ReceiveError == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* check for good packet header preamble, but timeout in packet */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x55; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - MSTP_Receive_Frame_FSM(&mstp_port); - /* preamble2 */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0xFF; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 0); - ct_test(pTest, mstp_port.HeaderCRC == 0xFF); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - /* force the timeout */ - mstp_port.SilenceTimer = Tframe_abort + 1; - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - ct_test(pTest, mstp_port.ReceivedInvalidFrame == true); - - /* check for good packet header preamble, but error in packet */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x55; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - MSTP_Receive_Frame_FSM(&mstp_port); - /* preamble2 */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0xFF; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 0); - ct_test(pTest, mstp_port.HeaderCRC == 0xFF); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - /* force the error */ - mstp_port.ReceiveError = true; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.ReceiveError == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* check for good packet header preamble */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x55; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); - MSTP_Receive_Frame_FSM(&mstp_port); - /* preamble2 */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0xFF; - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 0); - ct_test(pTest, mstp_port.HeaderCRC == 0xFF); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - /* no change of state if no data yet */ - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - /* Data is received - index is incremented */ - /* FrameType */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = FRAME_TYPE_TOKEN; - HeaderCRC = 0xFF; - HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 1); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - ct_test(pTest, FrameType == FRAME_TYPE_TOKEN); - /* Destination */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0x10; - HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 2); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - ct_test(pTest, mstp_port.DestinationAddress == 0x10); - /* Source */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = my_mac; - HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 3); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - ct_test(pTest, mstp_port.SourceAddress == my_mac); - /* Length1 = length*256 */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0; - HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 4); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - ct_test(pTest, mstp_port.DataLength == 0); - /* Length2 */ - mstp_port.DataAvailable = true; - mstp_port.DataRegister = 0; - HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 5); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); - ct_test(pTest, mstp_port.DataLength == 0); - /* HeaderCRC */ - mstp_port.DataAvailable = true; - ct_test(pTest, HeaderCRC == 0x73); /* per Annex G example */ - mstp_port.DataRegister = ~HeaderCRC; /* one's compliment of CRC is sent */ - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - ct_test(pTest, mstp_port.Index == 5); - ct_test(pTest, - mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); - ct_test(pTest, mstp_port.HeaderCRC == 0x55); - /* NotForUs */ - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* BadCRC in header check */ - mstp_port.ReceivedInvalidFrame = false; - mstp_port.ReceivedValidFrame = false; - len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, 0x10, /* destination */ - my_mac, /* source */ - NULL, /* data */ - 0); /* data size */ - ct_test(pTest, len > 0); - /* make the header CRC bad */ - buffer[7] = 0x00; - Load_Input_Buffer(buffer, len); - for (i = 0; i < len; i++) { - RS485_Check_UART_Data(&mstp_port); - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - } - ct_test(pTest, - mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.ReceivedInvalidFrame == true); - ct_test(pTest, mstp_port.ReceivedValidFrame == false); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* NoData for us */ - mstp_port.ReceivedInvalidFrame = false; - mstp_port.ReceivedValidFrame = false; - len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, my_mac, /* destination */ - my_mac, /* source */ - NULL, /* data */ - 0); /* data size */ - ct_test(pTest, len > 0); - Load_Input_Buffer(buffer, len); - for (i = 0; i < len; i++) { - RS485_Check_UART_Data(&mstp_port); - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - } - ct_test(pTest, - mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.ReceivedInvalidFrame == false); - ct_test(pTest, mstp_port.ReceivedValidFrame == true); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* FrameTooLong */ - mstp_port.ReceivedInvalidFrame = false; - mstp_port.ReceivedValidFrame = false; - len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, my_mac, /* destination */ - my_mac, /* source */ - NULL, /* data */ - 0); /* data size */ - ct_test(pTest, len > 0); - /* make the header data length bad */ - buffer[5] = 0x02; - Load_Input_Buffer(buffer, len); - for (i = 0; i < len; i++) { - RS485_Check_UART_Data(&mstp_port); - INCREMENT_AND_LIMIT_UINT8(EventCount); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.DataAvailable == false); - ct_test(pTest, mstp_port.SilenceTimer == 0); - ct_test(pTest, mstp_port.EventCount == EventCount); - } - ct_test(pTest, - mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); - MSTP_Receive_Frame_FSM(&mstp_port); - ct_test(pTest, mstp_port.ReceivedInvalidFrame == true); - ct_test(pTest, mstp_port.ReceivedValidFrame == false); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - /* Data */ - mstp_port.ReceivedInvalidFrame = false; - mstp_port.ReceivedValidFrame = false; - memset(data, 0, sizeof(data)); - len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_PROPRIETARY_MIN, my_mac, /* destination */ - my_mac, /* source */ - data, /* data */ - sizeof(data)); /* data size */ - ct_test(pTest, len > 0); - Load_Input_Buffer(buffer, len); - RS485_Check_UART_Data(&mstp_port); - MSTP_Receive_Frame_FSM(&mstp_port); - while (mstp_port.receive_state != MSTP_RECEIVE_STATE_IDLE) { - RS485_Check_UART_Data(&mstp_port); - MSTP_Receive_Frame_FSM(&mstp_port); - } - ct_test(pTest, mstp_port.DataLength == sizeof(data)); - ct_test(pTest, mstp_port.ReceivedInvalidFrame == false); - ct_test(pTest, mstp_port.ReceivedValidFrame == true); - ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); - - return; -} - -void testMasterNodeFSM(Test * pTest) -{ - volatile struct mstp_port_struct_t mstp_port; /* port data */ - uint8_t my_mac = 0x05; /* local MAC address */ - - MSTP_Init(&mstp_port, my_mac); - ct_test(pTest, mstp_port.master_state == MSTP_MASTER_STATE_INITIALIZE); - -} - -#endif - -#ifdef TEST_MSTP -int main(void) -{ - Test *pTest; - bool rc; - - pTest = ct_create("mstp", NULL); - - /* individual tests */ - rc = ct_addTestFunction(pTest, testReceiveNodeFSM); - assert(rc); - rc = ct_addTestFunction(pTest, testMasterNodeFSM); - assert(rc); - - ct_setStream(pTest, stdout); - ct_run(pTest); - (void) ct_report(pTest); - - ct_destroy(pTest); - - return 0; -} -#endif +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2003 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307 + USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ + +/* This clause describes a Master-Slave/Token-Passing (MS/TP) data link */ +/* protocol, which provides the same services to the network layer as */ +/* ISO 8802-2 Logical Link Control. It uses services provided by the */ +/* EIA-485 physical layer. Relevant clauses of EIA-485 are deemed to be */ +/* included in this standard by reference. The following hardware is assumed: */ +/* (a) A UART (Universal Asynchronous Receiver/Transmitter) capable of */ +/* transmitting and receiving eight data bits with one stop bit */ +/* and no parity. */ +/* (b) An EIA-485 transceiver whose driver may be disabled. */ +/* (c) A timer with a resolution of five milliseconds or less */ + +#include +#include +#if PRINT_ENABLED +#include +#endif +#include "mstp.h" +#include "bytes.h" +#include "crc.h" +#include "rs485.h" + +/* debug print statements */ +#if PRINT_ENABLED +#define PRINT_ENABLED_RECEIVE 0 +#define PRINT_ENABLED_RECEIVE_DATA 1 +#define PRINT_ENABLED_MASTER 0 +#else +#define PRINT_ENABLED_RECEIVE 0 +#define PRINT_ENABLED_RECEIVE_DATA 0 +#define PRINT_ENABLED_MASTER 0 +#endif + +/* MS/TP Frame Format */ +/* All frames are of the following format: */ +/* */ +/* Preamble: two octet preamble: X`55', X`FF' */ +/* Frame Type: one octet */ +/* Destination Address: one octet address */ +/* Source Address: one octet address */ +/* Length: two octets, most significant octet first, of the Data field */ +/* Header CRC: one octet */ +/* Data: (present only if Length is non-zero) */ +/* Data CRC: (present only if Length is non-zero) two octets, */ +/* least significant octet first */ +/* (pad): (optional) at most one octet of padding: X'FF' */ + +/* The number of tokens received or used before a Poll For Master cycle */ +/* is executed: 50. */ +#define Npoll 50 + +/* The number of retries on sending Token: 1. */ +#define Nretry_token 1 + +/* The minimum number of DataAvailable or ReceiveError events that must be */ +/* seen by a receiving node in order to declare the line "active": 4. */ +#define Nmin_octets 4 + +/* The minimum time without a DataAvailable or ReceiveError event within */ +/* a frame before a receiving node may discard the frame: 60 bit times. */ +/* (Implementations may use larger values for this timeout, */ +/* not to exceed 100 milliseconds.) */ +/* At 9600 baud, 60 bit times would be about 6.25 milliseconds */ +/* const uint16_t Tframe_abort = 1 + ((1000 * 60) / 9600); */ +#define Tframe_abort 30 + +/* The maximum idle time a sending node may allow to elapse between octets */ +/* of a frame the node is transmitting: 20 bit times. */ +#define Tframe_gap 20 + +/* The time without a DataAvailable or ReceiveError event before declaration */ +/* of loss of token: 500 milliseconds. */ +#define Tno_token 500 + +/* The maximum time after the end of the stop bit of the final */ +/* octet of a transmitted frame before a node must disable its */ +/* EIA-485 driver: 15 bit times. */ +#define Tpostdrive 15 + +/* The maximum time a node may wait after reception of a frame that expects */ +/* a reply before sending the first octet of a reply or Reply Postponed */ +/* frame: 250 milliseconds. */ +/* note: we always send a reply postponed since a message other than + the reply may be in the transmit queue */ +#define Treply_delay 10 + +/* The minimum time without a DataAvailable or ReceiveError event */ +/* that a node must wait for a station to begin replying to a */ +/* confirmed request: 255 milliseconds. (Implementations may use */ +/* larger values for this timeout, not to exceed 300 milliseconds.) */ +#define Treply_timeout 255 + +/* Repeater turnoff delay. The duration of a continuous logical one state */ +/* at the active input port of an MS/TP repeater after which the repeater */ +/* will enter the IDLE state: 29 bit times < Troff < 40 bit times. */ +#define Troff 30 + +/* The width of the time slot within which a node may generate a token: */ +/* 10 milliseconds. */ +#define Tslot 10 + +/* The maximum time a node may wait after reception of the token or */ +/* a Poll For Master frame before sending the first octet of a frame: */ +/* 15 milliseconds. */ +#define Tusage_delay 15 + +/* The minimum time without a DataAvailable or ReceiveError event that a */ +/* node must wait for a remote node to begin using a token or replying to */ +/* a Poll For Master frame: 20 milliseconds. (Implementations may use */ +/* larger values for this timeout, not to exceed 100 milliseconds.) */ +#define Tusage_timeout 20 + +/* we need to be able to increment without rolling over */ +#define INCREMENT_AND_LIMIT_UINT8(x) {if (x < 0xFF) x++;} + +bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port) +{ + return (mstp_port->EventCount > Nmin_octets); +} + +unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */ + unsigned buffer_len, /* amount of space available */ + uint8_t frame_type, /* type of frame to send - see defines */ + uint8_t destination, /* destination address */ + uint8_t source, /* source address */ + uint8_t * data, /* any data to be sent - may be null */ + unsigned data_len) +{ /* number of bytes of data (up to 501) */ + uint8_t crc8 = 0xFF; /* used to calculate the crc value */ + uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */ + unsigned index = 0; /* used to load the data portion of the frame */ + + /* not enough to do a header */ + if (buffer_len < 8) + return 0; + + buffer[0] = 0x55; + buffer[1] = 0xFF; + buffer[2] = frame_type; + crc8 = CRC_Calc_Header(buffer[2], crc8); + buffer[3] = destination; + crc8 = CRC_Calc_Header(buffer[3], crc8); + buffer[4] = source; + crc8 = CRC_Calc_Header(buffer[4], crc8); + buffer[5] = data_len / 256; + crc8 = CRC_Calc_Header(buffer[5], crc8); + buffer[6] = data_len % 256; + crc8 = CRC_Calc_Header(buffer[6], crc8); + buffer[7] = ~crc8; + + index = 8; + while (data_len && data && (index < buffer_len)) { + buffer[index] = *data; + crc16 = CRC_Calc_Data(buffer[index], crc16); + data++; + index++; + data_len--; + } + /* append the data CRC if necessary */ + if (index > 8) { + if ((index + 2) <= buffer_len) { + crc16 = ~crc16; + buffer[index] = LO_BYTE(crc16); + index++; + buffer[index] = HI_BYTE(crc16); + index++; + } else + return 0; + } + + return index; /* returns the frame length */ +} + +void MSTP_Create_And_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port to send from */ + uint8_t frame_type, /* type of frame to send - see defines */ + uint8_t destination, /* destination address */ + uint8_t source, /* source address */ + uint8_t * data, /* any data to be sent - may be null */ + unsigned data_len) +{ /* number of bytes of data (up to 501) */ + uint8_t buffer[MAX_MPDU] = { 0 }; /* buffer for sending */ + uint16_t len = 0; /* number of bytes to send */ + + len = (uint16_t) MSTP_Create_Frame(&buffer[0], /* where frame is loaded */ + sizeof(buffer), /* amount of space available */ + frame_type, /* type of frame to send - see defines */ + destination, /* destination address */ + source, /* source address */ + data, /* any data to be sent - may be null */ + data_len); /* number of bytes of data (up to 501) */ + + RS485_Send_Frame(mstp_port, &buffer[0], len); + /* FIXME: be sure to reset SilenceTimer after each octet is sent! */ +} + +#if PRINT_ENABLED_RECEIVE +char *mstp_receive_state_text(int state) +{ + char *text = "unknown"; + + switch (state) { + case MSTP_RECEIVE_STATE_IDLE: + text = "IDLE"; + break; + case MSTP_RECEIVE_STATE_PREAMBLE: + text = "PREAMBLE"; + break; + case MSTP_RECEIVE_STATE_HEADER: + text = "HEADER"; + break; + case MSTP_RECEIVE_STATE_HEADER_CRC: + text = "HEADER_CRC"; + break; + case MSTP_RECEIVE_STATE_DATA: + text = "DATA"; + break; + default: + break; + } + + return text; +} +#endif + +void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port) +{ +#if PRINT_ENABLED_RECEIVE_DATA + static MSTP_RECEIVE_STATE receive_state = MSTP_RECEIVE_STATE_IDLE; +#endif +#if PRINT_ENABLED_RECEIVE + fprintf(stderr, + "MSTP Rx: State=%s Data=%02X hCRC=%02X Index=%u EC=%u DateLen=%u Silence=%u\n", + mstp_receive_state_text(mstp_port->receive_state), + mstp_port->DataRegister, mstp_port->HeaderCRC, mstp_port->Index, + mstp_port->EventCount, mstp_port->DataLength, + mstp_port->SilenceTimer); +#endif + switch (mstp_port->receive_state) { + /* In the IDLE state, the node waits for the beginning of a frame. */ + case MSTP_RECEIVE_STATE_IDLE: + /* EatAnError */ + if (mstp_port->ReceiveError == true) { + mstp_port->ReceiveError = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + /* wait for the start of a frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } else if (mstp_port->DataAvailable == true) { +#if PRINT_ENABLED_RECEIVE_DATA + fprintf(stderr, "MSTP Rx: %02X ", mstp_port->DataRegister); +#endif + /* Preamble1 */ + if (mstp_port->DataRegister == 0x55) { + mstp_port->DataAvailable = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + /* receive the remainder of the frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE; + } + /* EatAnOctet */ + else { +#if PRINT_ENABLED_RECEIVE_DATA + fprintf(stderr, "\n"); +#endif + mstp_port->DataAvailable = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + /* wait for the start of a frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + /* In the PREAMBLE state, the node waits for the second octet of the preamble. */ + case MSTP_RECEIVE_STATE_PREAMBLE: + /* Timeout */ + if (mstp_port->SilenceTimer > Tframe_abort) { + /* a correct preamble has not been received */ + /* wait for the start of a frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + /* Error */ + else if (mstp_port->ReceiveError == true) { + mstp_port->ReceiveError = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + /* wait for the start of a frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } else if (mstp_port->DataAvailable == true) { +#if PRINT_ENABLED_RECEIVE_DATA + fprintf(stderr, "%02X ", mstp_port->DataRegister); +#endif + /* Preamble2 */ + if (mstp_port->DataRegister == 0xFF) { + mstp_port->DataAvailable = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + mstp_port->Index = 0; + mstp_port->HeaderCRC = 0xFF; + /* receive the remainder of the frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + /* ignore RepeatedPreamble1 */ + else if (mstp_port->DataRegister == 0x55) { + mstp_port->DataAvailable = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + /* wait for the second preamble octet. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE; + } + /* NotPreamble */ + else { + mstp_port->DataAvailable = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + /* wait for the start of a frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + /* In the HEADER state, the node waits for the fixed message header. */ + case MSTP_RECEIVE_STATE_HEADER: + /* Timeout */ + if (mstp_port->SilenceTimer > Tframe_abort) { + /* indicate that an error has occurred during the reception of a frame */ + mstp_port->ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + /* Error */ + else if (mstp_port->ReceiveError == true) { + mstp_port->ReceiveError = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + /* indicate that an error has occurred during the reception of a frame */ + mstp_port->ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } else if (mstp_port->DataAvailable == true) { +#if PRINT_ENABLED_RECEIVE_DATA + fprintf(stderr, "%02X ", mstp_port->DataRegister); +#endif + /* FrameType */ + if (mstp_port->Index == 0) { + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + mstp_port->HeaderCRC = + CRC_Calc_Header(mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->FrameType = mstp_port->DataRegister; + mstp_port->DataAvailable = false; + mstp_port->Index = 1; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + /* Destination */ + else if (mstp_port->Index == 1) { + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + mstp_port->HeaderCRC = + CRC_Calc_Header(mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DestinationAddress = mstp_port->DataRegister; + mstp_port->DataAvailable = false; + mstp_port->Index = 2; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + /* Source */ + else if (mstp_port->Index == 2) { + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + mstp_port->HeaderCRC = + CRC_Calc_Header(mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->SourceAddress = mstp_port->DataRegister; + mstp_port->DataAvailable = false; + mstp_port->Index = 3; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + /* Length1 */ + else if (mstp_port->Index == 3) { + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + mstp_port->HeaderCRC = + CRC_Calc_Header(mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataLength = mstp_port->DataRegister * 256; + mstp_port->DataAvailable = false; + mstp_port->Index = 4; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + /* Length2 */ + else if (mstp_port->Index == 4) { + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + mstp_port->HeaderCRC = + CRC_Calc_Header(mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataLength += mstp_port->DataRegister; + mstp_port->DataAvailable = false; + mstp_port->Index = 5; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + /* HeaderCRC */ + else if (mstp_port->Index == 5) { + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + mstp_port->HeaderCRC = + CRC_Calc_Header(mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataAvailable = false; + /* don't wait for next state - do it here */ + /* MSTP_RECEIVE_STATE_HEADER_CRC */ + if (mstp_port->HeaderCRC != 0x55) { + /* BadCRC */ + /* indicate that an error has occurred during the reception of a frame */ + mstp_port->ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } else { + if ((mstp_port->DestinationAddress == + mstp_port->This_Station) + || (mstp_port->DestinationAddress == + MSTP_BROADCAST_ADDRESS)) { + /* FrameTooLong */ + if (mstp_port->DataLength > MAX_MPDU) { + /* indicate that a frame with an illegal or */ + /* unacceptable data length has been received */ + mstp_port->ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + mstp_port->receive_state = + MSTP_RECEIVE_STATE_IDLE; + } + /* NoData */ + else if (mstp_port->DataLength == 0) { + /* indicate that a frame with no data has been received */ + mstp_port->ReceivedValidFrame = true; + /* wait for the start of the next frame. */ + mstp_port->receive_state = + MSTP_RECEIVE_STATE_IDLE; + } + /* Data */ + else { + mstp_port->Index = 0; + mstp_port->DataCRC = 0xFFFF; + /* receive the data portion of the frame. */ + mstp_port->receive_state = + MSTP_RECEIVE_STATE_DATA; + } + } + /* NotForUs */ + else { + /* wait for the start of the next frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + + + } + /* not per MS/TP standard, but it is a case not covered */ + else { + mstp_port->ReceiveError = false; + mstp_port->SilenceTimer = 0; + INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount); + /* indicate that an error has occurred during */ + /* the reception of a frame */ + mstp_port->ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + /* In the HEADER_CRC state, the node validates the CRC on the fixed */ + /* message header. */ + case MSTP_RECEIVE_STATE_HEADER_CRC: + break; + /* In the DATA state, the node waits for the data portion of a frame. */ + case MSTP_RECEIVE_STATE_DATA: + /* Timeout */ + if (mstp_port->SilenceTimer > Tframe_abort) { + /* indicate that an error has occurred during the reception of a frame */ + mstp_port->ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + /* Error */ + else if (mstp_port->ReceiveError == true) { + mstp_port->ReceiveError = false; + mstp_port->SilenceTimer = 0; + /* indicate that an error has occurred during the reception of a frame */ + mstp_port->ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } else if (mstp_port->DataAvailable == true) { +#if PRINT_ENABLED_RECEIVE_DATA + fprintf(stderr, "%02X ", mstp_port->DataRegister); +#endif + /* DataOctet */ + if (mstp_port->Index < mstp_port->DataLength) { + mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister, + mstp_port->DataCRC); + mstp_port->InputBuffer[mstp_port->Index] = + mstp_port->DataRegister; + mstp_port->Index++; + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; + } + /* CRC1 */ + else if (mstp_port->Index == mstp_port->DataLength) { + mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister, + mstp_port->DataCRC); + mstp_port->Index++; + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; + } + /* CRC2 */ + else if (mstp_port->Index == (mstp_port->DataLength + 1)) { + mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister, + mstp_port->DataCRC); + /* STATE DATA CRC - no need for new state */ + /* indicate the complete reception of a valid frame */ + if (mstp_port->DataCRC == 0xF0B8) + mstp_port->ReceivedValidFrame = true; + else + mstp_port->ReceivedInvalidFrame = true; + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + mstp_port->DataAvailable = false; + mstp_port->SilenceTimer = 0; + } + break; + default: + /* shouldn't get here - but if we do... */ + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + break; + } +#if PRINT_ENABLED_RECEIVE_DATA + if ((receive_state != MSTP_RECEIVE_STATE_IDLE) && + (mstp_port->receive_state == MSTP_RECEIVE_STATE_IDLE)) { + fprintf(stderr, "\n"); + fflush(stderr); + } + receive_state = mstp_port->receive_state; +#endif + + return; +} + +#if PRINT_ENABLED +char *mstp_master_state_text(int state) +{ + char *text = "unknown"; + + switch (state) { + case MSTP_MASTER_STATE_INITIALIZE: + text = "INITIALIZE"; + break; + case MSTP_MASTER_STATE_IDLE: + text = "IDLE"; + break; + case MSTP_MASTER_STATE_USE_TOKEN: + text = "USE_TOKEN"; + break; + case MSTP_MASTER_STATE_WAIT_FOR_REPLY: + text = "WAIT_FOR_REPLY"; + break; + case MSTP_MASTER_STATE_DONE_WITH_TOKEN: + text = "IDLE"; + break; + case MSTP_MASTER_STATE_PASS_TOKEN: + text = "DONE_WITH_TOKEN"; + break; + case MSTP_MASTER_STATE_NO_TOKEN: + text = "NO_TOKEN"; + break; + case MSTP_MASTER_STATE_POLL_FOR_MASTER: + text = "POLL_FOR_MASTER"; + break; + case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: + text = "ANSWER_DATA_REQUEST"; + break; + default: + break; + } + + return text; +} +#endif + +#if PRINT_ENABLED +char *mstp_frame_type_text(int type) +{ + char *text = "unknown"; + + switch (type) { + case FRAME_TYPE_TOKEN: + text = "TOKEN"; + break; + case FRAME_TYPE_POLL_FOR_MASTER: + text = "POLL_FOR_MASTER"; + break; + case FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER: + text = "REPLY_TO_POLL_FOR_MASTER"; + break; + case FRAME_TYPE_TEST_REQUEST: + text = "TEST_REQUEST"; + break; + case FRAME_TYPE_TEST_RESPONSE: + text = "TEST_RESPONSE"; + break; + case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: + text = "BACNET_DATA_EXPECTING_REPLY"; + break; + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + text = "BACNET_DATA_NOT_EXPECTING_REPLY"; + break; + case FRAME_TYPE_REPLY_POSTPONED: + text = "REPLY_POSTPONED"; + break; + default: + if ((type >= FRAME_TYPE_PROPRIETARY_MIN) && + (type <= FRAME_TYPE_PROPRIETARY_MAX)) + text = "PROPRIETARY"; + break; + } + + return text; +} +#endif + +/* returns true if we need to transition immediately */ +bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port) +{ + int mtu_len = 0; + int frame_type = 0; + uint8_t next_poll_station = 0; + uint8_t next_this_station = 0; + uint8_t next_next_station = 0; + uint16_t my_timeout = 10, ns_timeout = 0; + /* transition immediately to the next state */ + bool transition_now = false; +#if PRINT_ENABLED_MASTER + static MSTP_MASTER_STATE master_state = MSTP_MASTER_STATE_INITIALIZE; +#endif + + /* some calculations that several states need */ + next_poll_station = (mstp_port->Poll_Station + 1) % + (mstp_port->Nmax_master + 1); + next_this_station = (mstp_port->This_Station + 1) % + (mstp_port->Nmax_master + 1); + next_next_station = (mstp_port->Next_Station + 1) % + (mstp_port->Nmax_master + 1); +#if PRINT_ENABLED_MASTER + if (mstp_port->master_state != master_state) { + master_state = mstp_port->master_state; + fprintf(stderr, + "MSTP: TS=%02X[%02X] NS=%02X[%02X] PS=%02X[%02X] EC=%u TC=%u ST=%u %s\n", + mstp_port->This_Station, + next_this_station, + mstp_port->Next_Station, + next_next_station, + mstp_port->Poll_Station, + next_poll_station, + mstp_port->EventCount, + mstp_port->TokenCount, + mstp_port->SilenceTimer, + mstp_master_state_text(mstp_port->master_state)); + } +#endif + + switch (mstp_port->master_state) { + case MSTP_MASTER_STATE_INITIALIZE: + /* DoneInitializing */ + /* indicate that the next station is unknown */ + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->Poll_Station = mstp_port->This_Station; + /* cause a Poll For Master to be sent when this node first */ + /* receives the token */ + mstp_port->TokenCount = Npoll; + mstp_port->SoleMaster = false; + mstp_port->ReceivedValidFrame = false; + mstp_port->ReceivedInvalidFrame = false; + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + transition_now = true; + break; + /* In the IDLE state, the node waits for a frame. */ + case MSTP_MASTER_STATE_IDLE: + /* LostToken */ + if (mstp_port->SilenceTimer >= Tno_token) { + /* assume that the token has been lost */ + mstp_port->EventCount = 0; /* Addendum 135-2004d-8 */ + mstp_port->master_state = MSTP_MASTER_STATE_NO_TOKEN; + transition_now = true; + } + /* ReceivedInvalidFrame */ + else if (mstp_port->ReceivedInvalidFrame == true) { + /* invalid frame was received */ + mstp_port->ReceivedInvalidFrame = false; + /* wait for the next frame - remain in IDLE */ + } else if (mstp_port->ReceivedValidFrame == true) { +#if PRINT_ENABLED_MASTER + fprintf(stderr, + "MSTP: ReceivedValidFrame Src=%02X Dest=%02X DataLen=%u FC=%u ST=%u Type=%s\n", + mstp_port->SourceAddress, + mstp_port->DestinationAddress, + mstp_port->DataLength, + mstp_port->FrameCount, + mstp_port->SilenceTimer, + mstp_frame_type_text(mstp_port->FrameType)); +#endif + /* destined for me! */ + if ((mstp_port->DestinationAddress == + mstp_port->This_Station) || + (mstp_port->DestinationAddress == + MSTP_BROADCAST_ADDRESS)) { + switch (mstp_port->FrameType) { + /* ReceivedToken */ + case FRAME_TYPE_TOKEN: + /* tokens can't be broadcast */ + if (mstp_port->DestinationAddress == + MSTP_BROADCAST_ADDRESS) + break; + mstp_port->ReceivedValidFrame = false; + mstp_port->FrameCount = 0; + mstp_port->SoleMaster = false; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + break; + /* ReceivedPFM */ + case FRAME_TYPE_POLL_FOR_MASTER: + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, + mstp_port->SourceAddress, mstp_port->This_Station, + NULL, 0); + break; + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + /* indicate successful reception to the higher layers */ + dlmstp_put_receive(mstp_port->SourceAddress, + (uint8_t *) & mstp_port->InputBuffer[0], + mstp_port->DataLength); + break; + case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: + /*mstp_port->ReplyPostponedTimer = 0; */ + /* indicate successful reception to the higher layers */ + dlmstp_put_receive(mstp_port->SourceAddress, + (uint8_t *) & mstp_port->InputBuffer[0], + mstp_port->DataLength); + /* broadcast DER just remains IDLE */ + if (mstp_port->DestinationAddress != + MSTP_BROADCAST_ADDRESS) { + mstp_port->master_state = + MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; + } + break; + case FRAME_TYPE_TEST_REQUEST: + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_TEST_RESPONSE, + mstp_port->SourceAddress, mstp_port->This_Station, + NULL, 0); + break; + case FRAME_TYPE_TEST_RESPONSE: + default: + break; + } + } + mstp_port->ReceivedValidFrame = false; + } + break; + /* In the USE_TOKEN state, the node is allowed to send one or */ + /* more data frames. These may be BACnet Data frames or */ + /* proprietary frames. */ + case MSTP_MASTER_STATE_USE_TOKEN: + if (!mstp_port->TxReady) { + /* NothingToSend */ + mstp_port->FrameCount = mstp_port->Nmax_info_frames; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + transition_now = true; + } else if (mstp_port->SilenceTimer > Tusage_delay) { + /* if we missed our timing deadline, another token will be sent */ + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } else { + /* don't send it if we are too late in getting out */ + uint8_t destination = mstp_port->TxBuffer[3]; + RS485_Send_Frame(mstp_port, + (uint8_t *) & mstp_port->TxBuffer[0], mstp_port->TxLength); + mstp_port->FrameCount++; + switch (mstp_port->TxFrameType) { + case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: + /* SendAndWait */ + if (destination == MSTP_BROADCAST_ADDRESS) + mstp_port->master_state = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + else + mstp_port->master_state = + MSTP_MASTER_STATE_WAIT_FOR_REPLY; + break; + case FRAME_TYPE_TEST_REQUEST: + mstp_port->master_state = MSTP_MASTER_STATE_WAIT_FOR_REPLY; + break; + case FRAME_TYPE_TEST_RESPONSE: + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + default: + /* SendNoWait */ + mstp_port->master_state = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + } + mstp_port->TxReady = false; + } + break; + /* In the WAIT_FOR_REPLY state, the node waits for */ + /* a reply from another node. */ + case MSTP_MASTER_STATE_WAIT_FOR_REPLY: + if (mstp_port->SilenceTimer >= Treply_timeout) { + /* ReplyTimeout */ + /* assume that the request has failed */ + mstp_port->FrameCount = mstp_port->Nmax_info_frames; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + /* Any retry of the data frame shall await the next entry */ + /* to the USE_TOKEN state. (Because of the length of the timeout, */ + /* this transition will cause the token to be passed regardless */ + /* of the initial value of FrameCount.) */ + transition_now = true; + } else { + if (mstp_port->ReceivedInvalidFrame == true) { + /* InvalidFrame */ + /* error in frame reception */ + mstp_port->ReceivedInvalidFrame = false; + mstp_port->master_state = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + transition_now = true; + } else if (mstp_port->ReceivedValidFrame == true) { + if (mstp_port->DestinationAddress == + mstp_port->This_Station) { + switch (mstp_port->TxFrameType) { + case FRAME_TYPE_REPLY_POSTPONED: + /* ReceivedReplyPostponed */ + mstp_port->master_state = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + case FRAME_TYPE_TEST_RESPONSE: + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + break; + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + /* ReceivedReply */ + /* or a proprietary type that indicates a reply */ + /* indicate successful reception to the higher layers */ + dlmstp_put_receive(mstp_port->SourceAddress, /* source MS/TP address */ + (uint8_t *) & mstp_port->InputBuffer[0], + mstp_port->DataLength); + mstp_port->master_state = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + default: + /* if proprietary frame was expected, you might + need to transition to DONE WITH TOKEN */ + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + break; + } + } else { + /* ReceivedUnexpectedFrame */ + /* an unexpected frame was received */ + /* This may indicate the presence of multiple tokens. */ + /* Synchronize with the network. */ + /* This action drops the token. */ + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + mstp_port->ReceivedValidFrame = false; + transition_now = true; + } + } + break; + /* The DONE_WITH_TOKEN state either sends another data frame, */ + /* passes the token, or initiates a Poll For Master cycle. */ + case MSTP_MASTER_STATE_DONE_WITH_TOKEN: + /* SendAnotherFrame */ + if (mstp_port->FrameCount < mstp_port->Nmax_info_frames) { + /* then this node may send another information frame */ + /* before passing the token. */ + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } + /* Npoll changed in Errata SSPC-135-2004 */ + else if (mstp_port->TokenCount < (Npoll - 1)) { + if ((mstp_port->SoleMaster == true) && + (mstp_port->Next_Station != next_this_station)) { + /* SoleMaster */ + /* there are no other known master nodes to */ + /* which the token may be sent (true master-slave operation). */ + mstp_port->FrameCount = 0; + mstp_port->TokenCount++; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } else { + /* SendToken */ + /* Npoll changed in Errata SSPC-135-2004 */ + /* The comparison of NS and TS+1 eliminates the Poll For Master */ + /* if there are no addresses between TS and NS, since there is no */ + /* address at which a new master node may be found in that case. */ + mstp_port->TokenCount++; + /* transmit a Token frame to NS */ + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, NULL, 0); + mstp_port->RetryCount = 0; + mstp_port->EventCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + } else if (next_poll_station == mstp_port->Next_Station) { + if (mstp_port->SoleMaster == true) { + /* SoleMasterRestartMaintenancePFM */ + mstp_port->Poll_Station = next_poll_station; + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, mstp_port->Poll_Station, + mstp_port->This_Station, NULL, 0); + /* no known successor node */ + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 1; /* changed in Errata SSPC-135-2004 */ + /* mstp_port->EventCount = 0; removed in Addendum 135-2004d-8 */ + /* find a new successor to TS */ + mstp_port->master_state = + MSTP_MASTER_STATE_POLL_FOR_MASTER; + } else { + /* ResetMaintenancePFM */ + mstp_port->Poll_Station = mstp_port->This_Station; + /* transmit a Token frame to NS */ + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, NULL, 0); + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 1; /* changed in Errata SSPC-135-2004 */ + mstp_port->EventCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + } else { + /* SendMaintenancePFM */ + mstp_port->Poll_Station = next_poll_station; + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, mstp_port->This_Station, NULL, 0); + mstp_port->RetryCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + break; + /* The PASS_TOKEN state listens for a successor to begin using */ + /* the token that this node has just attempted to pass. */ + case MSTP_MASTER_STATE_PASS_TOKEN: + if (mstp_port->SilenceTimer < Tusage_timeout) { + if (mstp_port->EventCount > Nmin_octets) { + /* SawTokenUser */ + /* Assume that a frame has been sent by the new token user. */ + /* Enter the IDLE state to process the frame. */ + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + } else { + if (mstp_port->RetryCount < Nretry_token) { + /* RetrySendToken */ + mstp_port->RetryCount++; + /* Transmit a Token frame to NS */ + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, mstp_port->This_Station, NULL, + 0); + mstp_port->EventCount = 0; + /* re-enter the current state to listen for NS */ + /* to begin using the token. */ + } else { + /* FindNewSuccessor */ + /* Assume that NS has failed. */ + mstp_port->Poll_Station = next_next_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, mstp_port->This_Station, NULL, + 0); + /* no known successor node */ + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + /* mstp_port->EventCount = 0; removed in Addendum 135-2004d-8 */ + /* find a new successor to TS */ + mstp_port->master_state = + MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + } + break; + /* The NO_TOKEN state is entered if mstp_port->SilenceTimer becomes greater */ + /* than Tno_token, indicating that there has been no network activity */ + /* for that period of time. The timeout is continued to determine */ + /* whether or not this node may create a token. */ + case MSTP_MASTER_STATE_NO_TOKEN: + my_timeout = Tno_token + (Tslot * mstp_port->This_Station); + if (mstp_port->SilenceTimer < my_timeout) { + if (mstp_port->EventCount > Nmin_octets) { + /* SawFrame */ + /* Some other node exists at a lower address. */ + /* Enter the IDLE state to receive and process the incoming frame. */ + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + } else { + ns_timeout = + Tno_token + (Tslot * (mstp_port->This_Station + 1)); + if (mstp_port->SilenceTimer < ns_timeout) { + /* GenerateToken */ + /* Assume that this node is the lowest numerical address */ + /* on the network and is empowered to create a token. */ + mstp_port->Poll_Station = next_this_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, mstp_port->This_Station, NULL, + 0); + /* indicate that the next station is unknown */ + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + /* mstp_port->EventCount = 0; removed Addendum 135-2004d-8 */ + /* enter the POLL_FOR_MASTER state to find a new successor to TS. */ + mstp_port->master_state = + MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + } + break; + /* In the POLL_FOR_MASTER state, the node listens for a reply to */ + /* a previously sent Poll For Master frame in order to find */ + /* a successor node. */ + case MSTP_MASTER_STATE_POLL_FOR_MASTER: + if (mstp_port->ReceivedValidFrame == true) { + if ((mstp_port->DestinationAddress == mstp_port->This_Station) + && (mstp_port->FrameType == + FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER)) { + /* ReceivedReplyToPFM */ + mstp_port->SoleMaster = false; + mstp_port->Next_Station = mstp_port->SourceAddress; + mstp_port->EventCount = 0; + /* Transmit a Token frame to NS */ + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, mstp_port->This_Station, NULL, + 0); + mstp_port->Poll_Station = mstp_port->This_Station; + mstp_port->TokenCount = 0; + mstp_port->RetryCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } else { + /* ReceivedUnexpectedFrame */ + /* An unexpected frame was received. */ + /* This may indicate the presence of multiple tokens. */ + /* enter the IDLE state to synchronize with the network. */ + /* This action drops the token. */ + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + mstp_port->ReceivedValidFrame = false; + } else if ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == true)) { + if (mstp_port->SoleMaster == true) { + /* SoleMaster */ + /* There was no valid reply to the periodic poll */ + /* by the sole known master for other masters. */ + mstp_port->FrameCount = 0; + /* mstp_port->TokenCount++; removed in 2004 */ + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } else { + if (mstp_port->Next_Station != mstp_port->This_Station) { + /* DoneWithPFM */ + /* There was no valid reply to the maintenance */ + /* poll for a master at address PS. */ + mstp_port->EventCount = 0; + /* transmit a Token frame to NS */ + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, mstp_port->This_Station, + NULL, 0); + mstp_port->RetryCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } else { + if (next_poll_station != mstp_port->This_Station) { + /* SendNextPFM */ + mstp_port->Poll_Station = next_poll_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, NULL, 0); + mstp_port->RetryCount = 0; + /* Re-enter the current state. */ + } else { + /* DeclareSoleMaster */ + /* to indicate that this station is the only master */ + mstp_port->SoleMaster = true; + mstp_port->FrameCount = 0; + mstp_port->master_state = + MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } + } + } + mstp_port->ReceivedInvalidFrame = false; + } + break; + /* The ANSWER_DATA_REQUEST state is entered when a */ + /* BACnet Data Expecting Reply, a Test_Request, or */ + /* a proprietary frame that expects a reply is received. */ + case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: + /* FIXME: if we knew the APDU type received, we could + see if the next message was that same APDU type */ + if ((mstp_port->SilenceTimer <= Treply_delay) && + mstp_port->TxReady) { + /* Reply */ + /* If a reply is available from the higher layers */ + /* within Treply_delay after the reception of the */ + /* final octet of the requesting frame */ + /* (the mechanism used to determine this is a local matter), */ + /* then call MSTP_Create_And_Send_Frame to transmit the reply frame */ + /* and enter the IDLE state to wait for the next frame. */ + if ((mstp_port->FrameType == + FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) + && (mstp_port->TxReady)) { + RS485_Send_Frame(mstp_port, + (uint8_t *) & mstp_port->TxBuffer[0], + mstp_port->TxLength); + mstp_port->TxReady = false; + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + } + /* DeferredReply */ + /* If no reply will be available from the higher layers */ + /* within Treply_delay after the reception of the */ + /* final octet of the requesting frame (the mechanism */ + /* used to determine this is a local matter), */ + /* then an immediate reply is not possible. */ + /* Any reply shall wait until this node receives the token. */ + /* Call MSTP_Create_And_Send_Frame to transmit a Reply Postponed frame, */ + /* and enter the IDLE state. */ + else { + MSTP_Create_And_Send_Frame(mstp_port, + FRAME_TYPE_REPLY_POSTPONED, + mstp_port->SourceAddress, + mstp_port->This_Station, NULL, 0); + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + break; + default: + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + break; + } + + return transition_now; +} + +/* note: This_Station should be set with the MAC address */ +/* note: Nmax_info_frames should be set */ +/* note: Nmax_master should be set */ +void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port) +{ + int i; /*loop counter */ + + if (mstp_port) { + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE; + mstp_port->ReceiveError = false; + mstp_port->DataAvailable = false; + mstp_port->DataRegister = 0; + mstp_port->DataCRC = 0; + mstp_port->DataCRC = 0; + mstp_port->DataLength = 0; + mstp_port->DestinationAddress = 0; + mstp_port->EventCount = 0; + mstp_port->FrameType = FRAME_TYPE_TOKEN; + mstp_port->FrameCount = 0; + mstp_port->HeaderCRC = 0; + mstp_port->Index = 0; + mstp_port->Index = 0; + for (i = 0; i < sizeof(mstp_port->InputBuffer); i++) { + mstp_port->InputBuffer[i] = 0; + } + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->Poll_Station = mstp_port->This_Station; + mstp_port->ReceivedInvalidFrame = false; + mstp_port->ReceivedValidFrame = false; + mstp_port->RetryCount = 0; + mstp_port->SilenceTimer = 0; +/* mstp_port->ReplyPostponedTimer = 0; */ + mstp_port->SoleMaster = false; + mstp_port->SourceAddress = 0; + mstp_port->TokenCount = 0; +#if 0 + /* these are adjustable, so should already be set */ + mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES; + mstp_port->Nmax_master = DEFAULT_MAX_MASTER; +#endif + + /* An array of octets, used to store PDU octets prior to being transmitted. */ + /* This array is only used for APDU messages */ + for (i = 0; i < sizeof(mstp_port->TxBuffer); i++) { + mstp_port->TxBuffer[i] = 0; + } + mstp_port->TxLength = 0; + mstp_port->TxReady = false; + mstp_port->TxFrameType = 0; + + } +} + +#ifdef TEST +#include +#include +#include "ctest.h" + +/* test stub functions */ +void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ + uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ + uint16_t nbytes) +{ /* number of bytes of data (up to 501) */ + (void) mstp_port; + (void) buffer; + (void) nbytes; +} + +#define RING_BUFFER_DATA_SIZE 1 +#define RING_BUFFER_SIZE MAX_MPDU +static RING_BUFFER Test_Buffer; +static uint8_t Test_Buffer_Data[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE]; +static void Load_Input_Buffer(uint8_t * buffer, size_t len) +{ + static bool initialized = false; /* tracks our init */ + + + if (!initialized) { + initialized = true; + Ringbuf_Init(&Test_Buffer, + (char *) Test_Buffer_Data, + RING_BUFFER_DATA_SIZE, RING_BUFFER_SIZE); + } + /* empty any the existing data */ + while (!Ringbuf_Empty(&Test_Buffer)) { + (void) Ringbuf_Pop_Front(&Test_Buffer); + } + + if (buffer) { + while (len) { + (void) Ringbuf_Put(&Test_Buffer, (char *) buffer); + len--; + buffer++; + } + } +} + +void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) +{ /* port specific data */ + char *data; + if (!Ringbuf_Empty(&Test_Buffer) && mstp_port && + (mstp_port->DataAvailable == false)) { + data = Ringbuf_Pop_Front(&Test_Buffer); + if (data) { + mstp_port->DataRegister = *data; + mstp_port->DataAvailable = true; + } + } +} + +void testReceiveNodeFSM(Test * pTest) +{ + volatile struct mstp_port_struct_t mstp_port; /* port data */ + unsigned EventCount = 0; /* local counter */ + uint8_t my_mac = 0x05; /* local MAC address */ + uint8_t HeaderCRC = 0; /* for local CRC calculation */ + uint8_t FrameType = 0; /* type of packet that was sent */ + unsigned len; /* used for the size of the message packet */ + size_t i; /* used to loop through the message bytes */ + uint8_t buffer[MAX_MPDU] = { 0 }; + uint8_t data[MAX_MPDU - 8 /*header */ - 2 /*CRC*/] = { 0 }; + + MSTP_Init(&mstp_port, my_mac); + + /* check the receive error during idle */ + mstp_port.receive_state = MSTP_RECEIVE_STATE_IDLE; + mstp_port.ReceiveError = true; + mstp_port.SilenceTimer = 255; + mstp_port.EventCount = 0; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.ReceiveError == false); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* check for bad packet header */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x11; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* check for good packet header, but timeout */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x55; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + /* force the timeout */ + mstp_port.SilenceTimer = Tframe_abort + 1; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* check for good packet header preamble, but receive error */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x55; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + /* force the error */ + mstp_port.ReceiveError = true; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.ReceiveError == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* check for good packet header preamble1, but bad preamble2 */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x55; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + /* no change of state if no data yet */ + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + /* repeated preamble1 */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x55; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + /* repeated preamble1 */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x55; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + /* bad data */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x11; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.ReceiveError == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* check for good packet header preamble, but timeout in packet */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x55; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + /* preamble2 */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0xFF; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 0); + ct_test(pTest, mstp_port.HeaderCRC == 0xFF); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + /* force the timeout */ + mstp_port.SilenceTimer = Tframe_abort + 1; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + ct_test(pTest, mstp_port.ReceivedInvalidFrame == true); + + /* check for good packet header preamble, but error in packet */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x55; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + /* preamble2 */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0xFF; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 0); + ct_test(pTest, mstp_port.HeaderCRC == 0xFF); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + /* force the error */ + mstp_port.ReceiveError = true; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.ReceiveError == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* check for good packet header preamble */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x55; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + /* preamble2 */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0xFF; + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 0); + ct_test(pTest, mstp_port.HeaderCRC == 0xFF); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + /* no change of state if no data yet */ + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + /* Data is received - index is incremented */ + /* FrameType */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = FRAME_TYPE_TOKEN; + HeaderCRC = 0xFF; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 1); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest, FrameType == FRAME_TYPE_TOKEN); + /* Destination */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0x10; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 2); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest, mstp_port.DestinationAddress == 0x10); + /* Source */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = my_mac; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 3); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest, mstp_port.SourceAddress == my_mac); + /* Length1 = length*256 */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 4); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest, mstp_port.DataLength == 0); + /* Length2 */ + mstp_port.DataAvailable = true; + mstp_port.DataRegister = 0; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC); + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 5); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest, mstp_port.DataLength == 0); + /* HeaderCRC */ + mstp_port.DataAvailable = true; + ct_test(pTest, HeaderCRC == 0x73); /* per Annex G example */ + mstp_port.DataRegister = ~HeaderCRC; /* one's compliment of CRC is sent */ + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + ct_test(pTest, mstp_port.Index == 5); + ct_test(pTest, + mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + ct_test(pTest, mstp_port.HeaderCRC == 0x55); + /* NotForUs */ + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* BadCRC in header check */ + mstp_port.ReceivedInvalidFrame = false; + mstp_port.ReceivedValidFrame = false; + len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, 0x10, /* destination */ + my_mac, /* source */ + NULL, /* data */ + 0); /* data size */ + ct_test(pTest, len > 0); + /* make the header CRC bad */ + buffer[7] = 0x00; + Load_Input_Buffer(buffer, len); + for (i = 0; i < len; i++) { + RS485_Check_UART_Data(&mstp_port); + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + } + ct_test(pTest, + mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.ReceivedInvalidFrame == true); + ct_test(pTest, mstp_port.ReceivedValidFrame == false); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* NoData for us */ + mstp_port.ReceivedInvalidFrame = false; + mstp_port.ReceivedValidFrame = false; + len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, my_mac, /* destination */ + my_mac, /* source */ + NULL, /* data */ + 0); /* data size */ + ct_test(pTest, len > 0); + Load_Input_Buffer(buffer, len); + for (i = 0; i < len; i++) { + RS485_Check_UART_Data(&mstp_port); + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + } + ct_test(pTest, + mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.ReceivedInvalidFrame == false); + ct_test(pTest, mstp_port.ReceivedValidFrame == true); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* FrameTooLong */ + mstp_port.ReceivedInvalidFrame = false; + mstp_port.ReceivedValidFrame = false; + len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, my_mac, /* destination */ + my_mac, /* source */ + NULL, /* data */ + 0); /* data size */ + ct_test(pTest, len > 0); + /* make the header data length bad */ + buffer[5] = 0x02; + Load_Input_Buffer(buffer, len); + for (i = 0; i < len; i++) { + RS485_Check_UART_Data(&mstp_port); + INCREMENT_AND_LIMIT_UINT8(EventCount); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.DataAvailable == false); + ct_test(pTest, mstp_port.SilenceTimer == 0); + ct_test(pTest, mstp_port.EventCount == EventCount); + } + ct_test(pTest, + mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest, mstp_port.ReceivedInvalidFrame == true); + ct_test(pTest, mstp_port.ReceivedValidFrame == false); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + /* Data */ + mstp_port.ReceivedInvalidFrame = false; + mstp_port.ReceivedValidFrame = false; + memset(data, 0, sizeof(data)); + len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_PROPRIETARY_MIN, my_mac, /* destination */ + my_mac, /* source */ + data, /* data */ + sizeof(data)); /* data size */ + ct_test(pTest, len > 0); + Load_Input_Buffer(buffer, len); + RS485_Check_UART_Data(&mstp_port); + MSTP_Receive_Frame_FSM(&mstp_port); + while (mstp_port.receive_state != MSTP_RECEIVE_STATE_IDLE) { + RS485_Check_UART_Data(&mstp_port); + MSTP_Receive_Frame_FSM(&mstp_port); + } + ct_test(pTest, mstp_port.DataLength == sizeof(data)); + ct_test(pTest, mstp_port.ReceivedInvalidFrame == false); + ct_test(pTest, mstp_port.ReceivedValidFrame == true); + ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + return; +} + +void testMasterNodeFSM(Test * pTest) +{ + volatile struct mstp_port_struct_t mstp_port; /* port data */ + uint8_t my_mac = 0x05; /* local MAC address */ + + MSTP_Init(&mstp_port, my_mac); + ct_test(pTest, mstp_port.master_state == MSTP_MASTER_STATE_INITIALIZE); + +} + +#endif + +#ifdef TEST_MSTP +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("mstp", NULL); + + /* individual tests */ + rc = ct_addTestFunction(pTest, testReceiveNodeFSM); + assert(rc); + rc = ct_addTestFunction(pTest, testMasterNodeFSM); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void) ct_report(pTest); + + ct_destroy(pTest); + + return 0; +} +#endif diff --git a/bacnet-stack/ports/pic18f6720/mstp.h b/bacnet-stack/ports/pic18f6720/mstp.h index 5fd2a15a..3a658cdd 100644 --- a/bacnet-stack/ports/pic18f6720/mstp.h +++ b/bacnet-stack/ports/pic18f6720/mstp.h @@ -1,246 +1,246 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2004 Steve Karg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307 - USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ - -#ifndef MSTP_H -#define MSTP_H - -#include -#include -#include -#include "bacdef.h" -#include "dlmstp.h" - -/* The value 255 is used to denote broadcast when used as a */ -/* destination address but is not allowed as a value for a station. */ -/* Station addresses for master nodes can be 0-127. */ -/* Station addresses for slave nodes can be 127-254. */ -#define MSTP_BROADCAST_ADDRESS 255 - -/* MS/TP Frame Type */ -/* Frame Types 8 through 127 are reserved by ASHRAE. */ -#define FRAME_TYPE_TOKEN 0 -#define FRAME_TYPE_POLL_FOR_MASTER 1 -#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2 -#define FRAME_TYPE_TEST_REQUEST 3 -#define FRAME_TYPE_TEST_RESPONSE 4 -#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5 -#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6 -#define FRAME_TYPE_REPLY_POSTPONED 7 -/* Frame Types 128 through 255: Proprietary Frames */ -/* These frames are available to vendors as proprietary (non-BACnet) frames. */ -/* The first two octets of the Data field shall specify the unique vendor */ -/* identification code, most significant octet first, for the type of */ -/* vendor-proprietary frame to be conveyed. The length of the data portion */ -/* of a Proprietary frame shall be in the range of 2 to 501 octets. */ -#define FRAME_TYPE_PROPRIETARY_MIN 128 -#define FRAME_TYPE_PROPRIETARY_MAX 255 -/* The initial CRC16 checksum value */ -#define CRC16_INITIAL_VALUE (0xFFFF) - - -/* receive FSM states */ -typedef enum { - MSTP_RECEIVE_STATE_IDLE = 0, - MSTP_RECEIVE_STATE_PREAMBLE = 1, - MSTP_RECEIVE_STATE_HEADER = 2, - MSTP_RECEIVE_STATE_HEADER_CRC = 3, - MSTP_RECEIVE_STATE_DATA = 4 -} MSTP_RECEIVE_STATE; - -/* master node FSM states */ -typedef enum { - MSTP_MASTER_STATE_INITIALIZE = 0, - MSTP_MASTER_STATE_IDLE = 1, - MSTP_MASTER_STATE_USE_TOKEN = 2, - MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3, - MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4, - MSTP_MASTER_STATE_PASS_TOKEN = 5, - MSTP_MASTER_STATE_NO_TOKEN = 6, - MSTP_MASTER_STATE_POLL_FOR_MASTER = 7, - MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8 -} MSTP_MASTER_STATE; - -struct mstp_port_struct_t { - MSTP_RECEIVE_STATE receive_state; - /* When a master node is powered up or reset, */ - /* it shall unconditionally enter the INITIALIZE state. */ - MSTP_MASTER_STATE master_state; - /* A Boolean flag set to TRUE by the Receive State Machine */ - /* if an error is detected during the reception of a frame. */ - /* Set to FALSE by the main state machine. */ - unsigned ReceiveError:1; - /* There is data in the buffer */ - unsigned DataAvailable:1; - unsigned ReceivedInvalidFrame:1; - /* A Boolean flag set to TRUE by the Receive State Machine */ - /* if a valid frame is received. */ - /* Set to FALSE by the main state machine. */ - unsigned ReceivedValidFrame:1; - /* A Boolean flag set to TRUE by the master machine if this node is the */ - /* only known master node. */ - unsigned SoleMaster:1; - /* stores the latest received data */ - uint8_t DataRegister; - /* Used to accumulate the CRC on the data field of a frame. */ - uint16_t DataCRC; - /* Used to store the data length of a received frame. */ - unsigned DataLength; - /* Used to store the destination address of a received frame. */ - uint8_t DestinationAddress; - /* Used to count the number of received octets or errors. */ - /* This is used in the detection of link activity. */ - /* Compared to Nmin_octets */ - uint8_t EventCount; - /* Used to store the frame type of a received frame. */ - uint8_t FrameType; - /* The number of frames sent by this node during a single token hold. */ - /* When this counter reaches the value Nmax_info_frames, the node must */ - /* pass the token. */ - unsigned FrameCount; - /* Used to accumulate the CRC on the header of a frame. */ - uint8_t HeaderCRC; - /* Used as an index by the Receive State Machine, up to a maximum value of */ - /* InputBufferSize. */ - unsigned Index; - /* An array of octets, used to store octets as they are received. */ - /* InputBuffer is indexed from 0 to InputBufferSize-1. */ - /* The maximum size of a frame is 501 octets. */ - uint8_t *InputBuffer; - /* "Next Station," the MAC address of the node to which This Station passes */ - /* the token. If the Next_Station is unknown, Next_Station shall be equal to */ - /* This_Station. */ - uint8_t Next_Station; - /* "Poll Station," the MAC address of the node to which This Station last */ - /* sent a Poll For Master. This is used during token maintenance. */ - uint8_t Poll_Station; - /* A counter of transmission retries used for Token and Poll For Master */ - /* transmission. */ - unsigned RetryCount; - /* A timer with nominal 5 millisecond resolution used to measure and */ - /* generate silence on the medium between octets. It is incremented by a */ - /* timer process and is cleared by the Receive State Machine when activity */ - /* is detected and by the SendFrame procedure as each octet is transmitted. */ - /* Since the timer resolution is limited and the timer is not necessarily */ - /* synchronized to other machine events, a timer value of N will actually */ - /* denote intervals between N-1 and N */ - uint16_t SilenceTimer; - - /* A timer used to measure and generate Reply Postponed frames. It is */ - /* incremented by a timer process and is cleared by the Master Node State */ - /* Machine when a Data Expecting Reply Answer activity is completed. */ -/* note: we always send a reply postponed since a message other than - the reply may be in the transmit queue */ -// uint16_t ReplyPostponedTimer; - - /* Used to store the Source Address of a received frame. */ - uint8_t SourceAddress; - - /* The number of tokens received by this node. When this counter reaches the */ - /* value Npoll, the node polls the address range between TS and NS for */ - /* additional master nodes. TokenCount is set to zero at the end of the */ - /* polling process. */ - unsigned TokenCount; - - /* "This Station," the MAC address of this node. TS is generally read from a */ - /* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */ - /* 0 to 254. The value 255 is used to denote broadcast when used as a */ - /* destination address but is not allowed as a value for TS. */ - uint8_t This_Station; - - /* This parameter represents the value of the Max_Info_Frames property of */ - /* the node's Device object. The value of Max_Info_Frames specifies the */ - /* maximum number of information frames the node may send before it must */ - /* pass the token. Max_Info_Frames may have different values on different */ - /* nodes. This may be used to allocate more or less of the available link */ - /* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ - /* node, its value shall be 1. */ - unsigned Nmax_info_frames; - - /* This parameter represents the value of the Max_Master property of the */ - /* node's Device object. The value of Max_Master specifies the highest */ - /* allowable address for master nodes. The value of Max_Master shall be */ - /* less than or equal to 127. If Max_Master is not writable in a node, */ - /* its value shall be 127. */ - unsigned Nmax_master; - - /* An array of octets, used to store PDU octets prior to being transmitted. */ - /* This array is only used for APDU messages */ - uint8_t TxBuffer[MAX_MPDU]; - unsigned TxLength; - bool TxReady; /* true if ready to be sent or received */ - uint8_t TxFrameType; /* type of message - needed by MS/TP */ -}; - -#define DEFAULT_MAX_INFO_FRAMES 1 -#define DEFAULT_MAX_MASTER 127 -#define DEFAULT_MAC_ADDRESS 127 - -/* The minimum time after the end of the stop bit of the final octet of a */ -/* received frame before a node may enable its EIA-485 driver: 40 bit times. */ -/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */ -/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */ -/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */ -/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */ -/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */ -/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */ -/* 40 bits is 4 octets including a start and stop bit with each octet */ -#define Tturnaround 40 - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port); - void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t - *mstp_port); - bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t - *mstp_port); - - /* returns true if line is active */ - bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port); - - unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */ - unsigned buffer_len, /* amount of space available */ - uint8_t frame_type, /* type of frame to send - see defines */ - uint8_t destination, /* destination address */ - uint8_t source, /* source address */ - uint8_t * data, /* any data to be sent - may be null */ - unsigned data_len); /* number of bytes of data (up to 501) */ - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2004 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307 + USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ + +#ifndef MSTP_H +#define MSTP_H + +#include +#include +#include +#include "bacdef.h" +#include "dlmstp.h" + +/* The value 255 is used to denote broadcast when used as a */ +/* destination address but is not allowed as a value for a station. */ +/* Station addresses for master nodes can be 0-127. */ +/* Station addresses for slave nodes can be 127-254. */ +#define MSTP_BROADCAST_ADDRESS 255 + +/* MS/TP Frame Type */ +/* Frame Types 8 through 127 are reserved by ASHRAE. */ +#define FRAME_TYPE_TOKEN 0 +#define FRAME_TYPE_POLL_FOR_MASTER 1 +#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2 +#define FRAME_TYPE_TEST_REQUEST 3 +#define FRAME_TYPE_TEST_RESPONSE 4 +#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5 +#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6 +#define FRAME_TYPE_REPLY_POSTPONED 7 +/* Frame Types 128 through 255: Proprietary Frames */ +/* These frames are available to vendors as proprietary (non-BACnet) frames. */ +/* The first two octets of the Data field shall specify the unique vendor */ +/* identification code, most significant octet first, for the type of */ +/* vendor-proprietary frame to be conveyed. The length of the data portion */ +/* of a Proprietary frame shall be in the range of 2 to 501 octets. */ +#define FRAME_TYPE_PROPRIETARY_MIN 128 +#define FRAME_TYPE_PROPRIETARY_MAX 255 +/* The initial CRC16 checksum value */ +#define CRC16_INITIAL_VALUE (0xFFFF) + + +/* receive FSM states */ +typedef enum { + MSTP_RECEIVE_STATE_IDLE = 0, + MSTP_RECEIVE_STATE_PREAMBLE = 1, + MSTP_RECEIVE_STATE_HEADER = 2, + MSTP_RECEIVE_STATE_HEADER_CRC = 3, + MSTP_RECEIVE_STATE_DATA = 4 +} MSTP_RECEIVE_STATE; + +/* master node FSM states */ +typedef enum { + MSTP_MASTER_STATE_INITIALIZE = 0, + MSTP_MASTER_STATE_IDLE = 1, + MSTP_MASTER_STATE_USE_TOKEN = 2, + MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3, + MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4, + MSTP_MASTER_STATE_PASS_TOKEN = 5, + MSTP_MASTER_STATE_NO_TOKEN = 6, + MSTP_MASTER_STATE_POLL_FOR_MASTER = 7, + MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8 +} MSTP_MASTER_STATE; + +struct mstp_port_struct_t { + MSTP_RECEIVE_STATE receive_state; + /* When a master node is powered up or reset, */ + /* it shall unconditionally enter the INITIALIZE state. */ + MSTP_MASTER_STATE master_state; + /* A Boolean flag set to TRUE by the Receive State Machine */ + /* if an error is detected during the reception of a frame. */ + /* Set to FALSE by the main state machine. */ + unsigned ReceiveError:1; + /* There is data in the buffer */ + unsigned DataAvailable:1; + unsigned ReceivedInvalidFrame:1; + /* A Boolean flag set to TRUE by the Receive State Machine */ + /* if a valid frame is received. */ + /* Set to FALSE by the main state machine. */ + unsigned ReceivedValidFrame:1; + /* A Boolean flag set to TRUE by the master machine if this node is the */ + /* only known master node. */ + unsigned SoleMaster:1; + /* stores the latest received data */ + uint8_t DataRegister; + /* Used to accumulate the CRC on the data field of a frame. */ + uint16_t DataCRC; + /* Used to store the data length of a received frame. */ + unsigned DataLength; + /* Used to store the destination address of a received frame. */ + uint8_t DestinationAddress; + /* Used to count the number of received octets or errors. */ + /* This is used in the detection of link activity. */ + /* Compared to Nmin_octets */ + uint8_t EventCount; + /* Used to store the frame type of a received frame. */ + uint8_t FrameType; + /* The number of frames sent by this node during a single token hold. */ + /* When this counter reaches the value Nmax_info_frames, the node must */ + /* pass the token. */ + unsigned FrameCount; + /* Used to accumulate the CRC on the header of a frame. */ + uint8_t HeaderCRC; + /* Used as an index by the Receive State Machine, up to a maximum value of */ + /* InputBufferSize. */ + unsigned Index; + /* An array of octets, used to store octets as they are received. */ + /* InputBuffer is indexed from 0 to InputBufferSize-1. */ + /* The maximum size of a frame is 501 octets. */ + uint8_t *InputBuffer; + /* "Next Station," the MAC address of the node to which This Station passes */ + /* the token. If the Next_Station is unknown, Next_Station shall be equal to */ + /* This_Station. */ + uint8_t Next_Station; + /* "Poll Station," the MAC address of the node to which This Station last */ + /* sent a Poll For Master. This is used during token maintenance. */ + uint8_t Poll_Station; + /* A counter of transmission retries used for Token and Poll For Master */ + /* transmission. */ + unsigned RetryCount; + /* A timer with nominal 5 millisecond resolution used to measure and */ + /* generate silence on the medium between octets. It is incremented by a */ + /* timer process and is cleared by the Receive State Machine when activity */ + /* is detected and by the SendFrame procedure as each octet is transmitted. */ + /* Since the timer resolution is limited and the timer is not necessarily */ + /* synchronized to other machine events, a timer value of N will actually */ + /* denote intervals between N-1 and N */ + uint16_t SilenceTimer; + + /* A timer used to measure and generate Reply Postponed frames. It is */ + /* incremented by a timer process and is cleared by the Master Node State */ + /* Machine when a Data Expecting Reply Answer activity is completed. */ +/* note: we always send a reply postponed since a message other than + the reply may be in the transmit queue */ +/* uint16_t ReplyPostponedTimer; */ + + /* Used to store the Source Address of a received frame. */ + uint8_t SourceAddress; + + /* The number of tokens received by this node. When this counter reaches the */ + /* value Npoll, the node polls the address range between TS and NS for */ + /* additional master nodes. TokenCount is set to zero at the end of the */ + /* polling process. */ + unsigned TokenCount; + + /* "This Station," the MAC address of this node. TS is generally read from a */ + /* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */ + /* 0 to 254. The value 255 is used to denote broadcast when used as a */ + /* destination address but is not allowed as a value for TS. */ + uint8_t This_Station; + + /* This parameter represents the value of the Max_Info_Frames property of */ + /* the node's Device object. The value of Max_Info_Frames specifies the */ + /* maximum number of information frames the node may send before it must */ + /* pass the token. Max_Info_Frames may have different values on different */ + /* nodes. This may be used to allocate more or less of the available link */ + /* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ + /* node, its value shall be 1. */ + unsigned Nmax_info_frames; + + /* This parameter represents the value of the Max_Master property of the */ + /* node's Device object. The value of Max_Master specifies the highest */ + /* allowable address for master nodes. The value of Max_Master shall be */ + /* less than or equal to 127. If Max_Master is not writable in a node, */ + /* its value shall be 127. */ + unsigned Nmax_master; + + /* An array of octets, used to store PDU octets prior to being transmitted. */ + /* This array is only used for APDU messages */ + uint8_t TxBuffer[MAX_MPDU]; + unsigned TxLength; + bool TxReady; /* true if ready to be sent or received */ + uint8_t TxFrameType; /* type of message - needed by MS/TP */ +}; + +#define DEFAULT_MAX_INFO_FRAMES 1 +#define DEFAULT_MAX_MASTER 127 +#define DEFAULT_MAC_ADDRESS 127 + +/* The minimum time after the end of the stop bit of the final octet of a */ +/* received frame before a node may enable its EIA-485 driver: 40 bit times. */ +/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */ +/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */ +/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */ +/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */ +/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */ +/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */ +/* 40 bits is 4 octets including a start and stop bit with each octet */ +#define Tturnaround 40 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port); + void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t + *mstp_port); + bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t + *mstp_port); + + /* returns true if line is active */ + bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port); + + unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */ + unsigned buffer_len, /* amount of space available */ + uint8_t frame_type, /* type of frame to send - see defines */ + uint8_t destination, /* destination address */ + uint8_t source, /* source address */ + uint8_t * data, /* any data to be sent - may be null */ + unsigned data_len); /* number of bytes of data (up to 501) */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/pic18f6720/rs485.c b/bacnet-stack/ports/pic18f6720/rs485.c index dcc0c9ed..bc9f792d 100644 --- a/bacnet-stack/ports/pic18f6720/rs485.c +++ b/bacnet-stack/ports/pic18f6720/rs485.c @@ -1,385 +1,377 @@ -/************************************************************************** -* -* Copyright (C) 2005 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ - -/* The module handles sending data out the RS-485 port */ -/* and handles receiving data from the RS-485 port. */ -/* Customize this file for your specific hardware */ -#include -#include -#include -#include -#include "hardware.h" -#include "mstp.h" -#include "rs485.h" - -/* public port info */ -extern volatile struct mstp_port_struct_t MSTP_Port; - -/* the baud rate is adjustable */ -uint32_t RS485_Baud_Rate = 9600; - -/* the ISR and other use this for status and control */ -COMSTAT RS485_Comstat; - -//#pragma udata MSTPPortData -/* the buffer for receiving characters */ -volatile uint8_t RS485_Rx_Buffer[MAX_MPDU]; - -/* UART transmission buffer and index */ -volatile uint8_t RS485_Tx_Buffer[MAX_MPDU]; - -/**************************************************************************** -* DESCRIPTION: Transmits a frame using the UART -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ - uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ - uint16_t nbytes) /* number of bytes of data (up to 501) */ -{ - uint16_t i = 0; /* loop counter */ - uint8_t turnaround_time; - - if (!buffer) - return; - - /* bounds check */ - if (nbytes >= sizeof(RS485_Tx_Buffer)) - return; - - /* buffer is full. Wait for ISR to transmit. */ - while (RS485_Comstat.Tx_Bytes) {}; - - /* wait 40 bit times since reception */ - if (RS485_Baud_Rate == 9600) - turnaround_time = 4; - else if (RS485_Baud_Rate == 19200) - turnaround_time = 2; - else - turnaround_time = 1; - - while (mstp_port->SilenceTimer < turnaround_time) {}; - - RS485_Comstat.TxHead = 0; - memcpy((void *)&RS485_Tx_Buffer[0], (void *)buffer, nbytes); - - //for (i = 0; i < nbytes; i++) { - // /* put the data into the buffer */ - // RS485_Tx_Buffer[i] = *buffer; - // buffer++; - //} - RS485_Comstat.Tx_Bytes = nbytes; - /* disable the receiver */ - PIE3bits.RC2IE = 0; - RCSTA2bits.CREN = 0; - /* enable the transceiver */ - RS485_TX_ENABLE = 1; - RS485_RX_DISABLE = 1; - /* enable the transmitter */ - TXSTA2bits.TXEN = 1; - PIE3bits.TX2IE = 1; - /* per MSTP spec, sort of */ - mstp_port->SilenceTimer = 0; - - return; -} - -/**************************************************************************** -* DESCRIPTION: Checks for data on the receive UART, and handles errors -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port) -{ - /* check for data */ - if (RS485_Comstat.Rx_Bytes) - { - mstp_port->DataRegister = RS485_Rx_Buffer[RS485_Comstat.RxTail]; - if (RS485_Comstat.RxTail >= (sizeof(RS485_Rx_Buffer)-1)) - RS485_Comstat.RxTail = 0; - else - RS485_Comstat.RxTail++; - RS485_Comstat.Rx_Bytes--; - /* errors? let the state machine know */ - if (RS485_Comstat.Rx_Bufferoverrun) - { - RS485_Comstat.Rx_Bufferoverrun = FALSE; - mstp_port->ReceiveError = TRUE; - } - /* We read a good byte */ - else - mstp_port->DataAvailable = TRUE; - } - - return RS485_Comstat.Rx_Bytes; -} -/* ************************************************************************* - DESCRIPTION: Receives RS485 data stream - - RETURN: none - - ALGORITHM: none - - NOTES: none - *************************************************************************** */ -void RS485_Interrupt_Rx(void) -{ - char dummy; - - if ((RCSTA2bits.FERR) || (RCSTA2bits.OERR)) - { - /* Clear the error */ - RCSTA2bits.CREN = 0; - RCSTA2bits.CREN = 1; - RS485_Comstat.Rx_Bufferoverrun = TRUE; - dummy = RCREG2; - } - else if (RS485_Comstat.Rx_Bytes < sizeof(RS485_Rx_Buffer)) - { - RS485_Rx_Buffer[RS485_Comstat.RxHead] = RCREG2; - if (RS485_Comstat.RxHead >= (sizeof(RS485_Rx_Buffer)-1)) - RS485_Comstat.RxHead = 0; - else - RS485_Comstat.RxHead++; - RS485_Comstat.Rx_Bytes++; - } - else - { - RS485_Comstat.Rx_Bufferoverrun = TRUE; - dummy = RCREG2; - (void)dummy; - } -} - -/* ************************************************************************* - DESCRIPTION: Transmits a byte using the UART out the RS485 port - - RETURN: none - - ALGORITHM: none - - NOTES: none - *************************************************************************** */ -void RS485_Interrupt_Tx(void) -{ - if (RS485_Comstat.Tx_Bytes) - { - /* Get the data byte */ - TXREG2 = RS485_Tx_Buffer[RS485_Comstat.TxHead]; - /* point to the next byte */ - RS485_Comstat.TxHead++; - /* reduce the buffer size */ - RS485_Comstat.Tx_Bytes--; - } - else - { - /* wait for the USART to be empty */ - while (!TXSTA2bits.TRMT); - /* disable this interrupt */ - PIE3bits.TX2IE = 0; - /* enable the receiver */ - RS485_TX_ENABLE = 0; - RS485_RX_DISABLE = 0; - // FIXME: might not be necessary - PIE3bits.RC2IE = 1; - RCSTA2bits.CREN = 1; - } -} - -/**************************************************************************** -* DESCRIPTION: Returns the baud rate that we are currently running at -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -uint32_t RS485_Get_Baud_Rate(void) -{ - return RS485_Baud_Rate; -} - -/**************************************************************************** -* DESCRIPTION: Sets the baud rate for the chip USART -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -bool RS485_Set_Baud_Rate(uint32_t baud) -{ - bool valid = true; - - switch (baud) - { - case 9600: - case 19200: - case 38400: - case 57600: - case 76800: - case 115200: - RS485_Baud_Rate = baud; - break; - default: - valid = false; - break; - } - - if (valid) { - /* FIXME: store the baud rate */ - /* I2C_Write_Block( - EEPROM_DEVICE_ADDRESS, - (char *)&RS485_Baud_Rate, - sizeof(RS485_Baud_Rate), - EEPROM_MSTP_BAUD_RATE_ADDR); */ -} - - return valid; -} - -/**************************************************************************** -* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in -* receive mode. -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -void RS485_Initialize_Port(void) -{ - - /* Reset USART registers to POR state */ - TXSTA2 = 0; - RCSTA2 = 0; - /* configure USART for receiving */ - /* since the TX will handle setting up for transmit */ - RCSTA2bits.CREN = 1; - /* Interrupt on receipt */ - PIE3bits.RC2IE = 1; - /* enable the transmitter, disable its interrupt */ - TXSTA2bits.TXEN = 1; - PIE3bits.TX2IE = 0; - /* setup USART Baud Rate Generator */ - /* see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book */ - /* Fosc=20MHz - BRGH=1 BRGH=0 - Rate SPBRG Rate SPBRG - ------- ----- ------- ----- - 9615 129 9469 32 - 19230 64 19530 15 - 37878 32 78130 3 - 56818 21 104200 2 - 113630 10 312500 0 - 250000 4 - 625000 1 - 1250000 0 - */ - switch (RS485_Baud_Rate) - { - case 19200: - SPBRG2 = 64; - TXSTA2bits.BRGH = 1; - break; - case 38400: - SPBRG2 = 32; - TXSTA2bits.BRGH = 1; - break; - case 57600: - SPBRG2 = 21; - TXSTA2bits.BRGH = 1; - break; - case 76800: - SPBRG2 = 3; - TXSTA2bits.BRGH = 0; - break; - case 115200: - SPBRG2 = 10; - TXSTA2bits.BRGH = 1; - break; - case 9600: - SPBRG2 = 129; - TXSTA2bits.BRGH = 1; - break; - default: - SPBRG2 = 129; - TXSTA2bits.BRGH = 1; - RS485_Set_Baud_Rate(9600); - break; - } - /* select async mode */ - TXSTA2bits.SYNC = 0; - /* enable transmitter */ - TXSTA2bits.TXEN = 1; - /* serial port enable */ - RCSTA2bits.SPEN = 1; - /* since we are using RS485, - we need to explicitly say - transmit enable or not */ - RS485_RX_DISABLE = 0; - RS485_TX_ENABLE = 0; -} - -/**************************************************************************** -* DESCRIPTION: Disables the RS485 hardware -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -void RS485_Disable_Port(void) -{ - RCSTA2 &= 0x4F; /* Disable the receiver */ - TXSTA2bits.TXEN = 0; /* and transmitter */ - PIE3 &= 0xCF; /* Disable both interrupts */ -} - -void RS485_Reinit(void) -{ - RS485_Set_Baud_Rate(9600); -} - -/**************************************************************************** -* DESCRIPTION: Initializes the data and the port -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -void RS485_Initialize(void) -{ - /* Init the Rs485 buffers */ - RS485_Comstat.RxHead = 0; - RS485_Comstat.RxTail = 0; - RS485_Comstat.Rx_Bytes = 0; - RS485_Comstat.Rx_Bufferoverrun = FALSE; - RS485_Comstat.TxHead = 0; - RS485_Comstat.TxTail = 0; - RS485_Comstat.Tx_Bytes = 0; - - /* FIXME: read the data from storage */ - /* I2C_Read_Block( - EEPROM_DEVICE_ADDRESS, - (char *)&RS485_Baud_Rate, - sizeof(RS485_Baud_Rate), - EEPROM_MSTP_BAUD_RATE_ADDR); */ - - RS485_Initialize_Port(); -} +/************************************************************************** +* +* Copyright (C) 2005 Steve Karg +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +*********************************************************************/ + +/* The module handles sending data out the RS-485 port */ +/* and handles receiving data from the RS-485 port. */ +/* Customize this file for your specific hardware */ +#include +#include +#include +#include +#include "hardware.h" +#include "mstp.h" +#include "rs485.h" + +/* public port info */ +extern volatile struct mstp_port_struct_t MSTP_Port; + +/* the baud rate is adjustable */ +uint32_t RS485_Baud_Rate = 9600; + +/* the ISR and other use this for status and control */ +COMSTAT RS485_Comstat; + +/*#pragma udata MSTPPortData */ +/* the buffer for receiving characters */ +volatile uint8_t RS485_Rx_Buffer[MAX_MPDU]; + +/* UART transmission buffer and index */ +volatile uint8_t RS485_Tx_Buffer[MAX_MPDU]; + +/**************************************************************************** +* DESCRIPTION: Transmits a frame using the UART +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ + uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ + uint16_t nbytes) +{ /* number of bytes of data (up to 501) */ + uint16_t i = 0; /* loop counter */ + uint8_t turnaround_time; + + if (!buffer) + return; + + /* bounds check */ + if (nbytes >= sizeof(RS485_Tx_Buffer)) + return; + + /* buffer is full. Wait for ISR to transmit. */ + while (RS485_Comstat.Tx_Bytes) { + }; + + /* wait 40 bit times since reception */ + if (RS485_Baud_Rate == 9600) + turnaround_time = 4; + else if (RS485_Baud_Rate == 19200) + turnaround_time = 2; + else + turnaround_time = 1; + + while (mstp_port->SilenceTimer < turnaround_time) { + }; + + RS485_Comstat.TxHead = 0; + memcpy((void *) &RS485_Tx_Buffer[0], (void *) buffer, nbytes); + + /*for (i = 0; i < nbytes; i++) { */ + /* /* put the data into the buffer */ */ + /* RS485_Tx_Buffer[i] = *buffer; */ + /* buffer++; */ + /*} */ + RS485_Comstat.Tx_Bytes = nbytes; + /* disable the receiver */ + PIE3bits.RC2IE = 0; + RCSTA2bits.CREN = 0; + /* enable the transceiver */ + RS485_TX_ENABLE = 1; + RS485_RX_DISABLE = 1; + /* enable the transmitter */ + TXSTA2bits.TXEN = 1; + PIE3bits.TX2IE = 1; + /* per MSTP spec, sort of */ + mstp_port->SilenceTimer = 0; + + return; +} + +/**************************************************************************** +* DESCRIPTION: Checks for data on the receive UART, and handles errors +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t * + mstp_port) +{ + /* check for data */ + if (RS485_Comstat.Rx_Bytes) { + mstp_port->DataRegister = RS485_Rx_Buffer[RS485_Comstat.RxTail]; + if (RS485_Comstat.RxTail >= (sizeof(RS485_Rx_Buffer) - 1)) + RS485_Comstat.RxTail = 0; + else + RS485_Comstat.RxTail++; + RS485_Comstat.Rx_Bytes--; + /* errors? let the state machine know */ + if (RS485_Comstat.Rx_Bufferoverrun) { + RS485_Comstat.Rx_Bufferoverrun = FALSE; + mstp_port->ReceiveError = TRUE; + } + /* We read a good byte */ + else + mstp_port->DataAvailable = TRUE; + } + + return RS485_Comstat.Rx_Bytes; +} + +/* ************************************************************************* + DESCRIPTION: Receives RS485 data stream + + RETURN: none + + ALGORITHM: none + + NOTES: none + *************************************************************************** */ +void RS485_Interrupt_Rx(void) +{ + char dummy; + + if ((RCSTA2bits.FERR) || (RCSTA2bits.OERR)) { + /* Clear the error */ + RCSTA2bits.CREN = 0; + RCSTA2bits.CREN = 1; + RS485_Comstat.Rx_Bufferoverrun = TRUE; + dummy = RCREG2; + } else if (RS485_Comstat.Rx_Bytes < sizeof(RS485_Rx_Buffer)) { + RS485_Rx_Buffer[RS485_Comstat.RxHead] = RCREG2; + if (RS485_Comstat.RxHead >= (sizeof(RS485_Rx_Buffer) - 1)) + RS485_Comstat.RxHead = 0; + else + RS485_Comstat.RxHead++; + RS485_Comstat.Rx_Bytes++; + } else { + RS485_Comstat.Rx_Bufferoverrun = TRUE; + dummy = RCREG2; + (void) dummy; + } +} + +/* ************************************************************************* + DESCRIPTION: Transmits a byte using the UART out the RS485 port + + RETURN: none + + ALGORITHM: none + + NOTES: none + *************************************************************************** */ +void RS485_Interrupt_Tx(void) +{ + if (RS485_Comstat.Tx_Bytes) { + /* Get the data byte */ + TXREG2 = RS485_Tx_Buffer[RS485_Comstat.TxHead]; + /* point to the next byte */ + RS485_Comstat.TxHead++; + /* reduce the buffer size */ + RS485_Comstat.Tx_Bytes--; + } else { + /* wait for the USART to be empty */ + while (!TXSTA2bits.TRMT); + /* disable this interrupt */ + PIE3bits.TX2IE = 0; + /* enable the receiver */ + RS485_TX_ENABLE = 0; + RS485_RX_DISABLE = 0; + /* FIXME: might not be necessary */ + PIE3bits.RC2IE = 1; + RCSTA2bits.CREN = 1; + } +} + +/**************************************************************************** +* DESCRIPTION: Returns the baud rate that we are currently running at +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +uint32_t RS485_Get_Baud_Rate(void) +{ + return RS485_Baud_Rate; +} + +/**************************************************************************** +* DESCRIPTION: Sets the baud rate for the chip USART +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +bool RS485_Set_Baud_Rate(uint32_t baud) +{ + bool valid = true; + + switch (baud) { + case 9600: + case 19200: + case 38400: + case 57600: + case 76800: + case 115200: + RS485_Baud_Rate = baud; + break; + default: + valid = false; + break; + } + + if (valid) { + /* FIXME: store the baud rate */ + /* I2C_Write_Block( + EEPROM_DEVICE_ADDRESS, + (char *)&RS485_Baud_Rate, + sizeof(RS485_Baud_Rate), + EEPROM_MSTP_BAUD_RATE_ADDR); */ + } + + return valid; +} + +/**************************************************************************** +* DESCRIPTION: Initializes the RS485 hardware and variables, and starts in +* receive mode. +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Initialize_Port(void) +{ + + /* Reset USART registers to POR state */ + TXSTA2 = 0; + RCSTA2 = 0; + /* configure USART for receiving */ + /* since the TX will handle setting up for transmit */ + RCSTA2bits.CREN = 1; + /* Interrupt on receipt */ + PIE3bits.RC2IE = 1; + /* enable the transmitter, disable its interrupt */ + TXSTA2bits.TXEN = 1; + PIE3bits.TX2IE = 0; + /* setup USART Baud Rate Generator */ + /* see BAUD RATES FOR ASYNCHRONOUS MODE in Data Book */ + /* Fosc=20MHz + BRGH=1 BRGH=0 + Rate SPBRG Rate SPBRG + ------- ----- ------- ----- + 9615 129 9469 32 + 19230 64 19530 15 + 37878 32 78130 3 + 56818 21 104200 2 + 113630 10 312500 0 + 250000 4 + 625000 1 + 1250000 0 + */ + switch (RS485_Baud_Rate) { + case 19200: + SPBRG2 = 64; + TXSTA2bits.BRGH = 1; + break; + case 38400: + SPBRG2 = 32; + TXSTA2bits.BRGH = 1; + break; + case 57600: + SPBRG2 = 21; + TXSTA2bits.BRGH = 1; + break; + case 76800: + SPBRG2 = 3; + TXSTA2bits.BRGH = 0; + break; + case 115200: + SPBRG2 = 10; + TXSTA2bits.BRGH = 1; + break; + case 9600: + SPBRG2 = 129; + TXSTA2bits.BRGH = 1; + break; + default: + SPBRG2 = 129; + TXSTA2bits.BRGH = 1; + RS485_Set_Baud_Rate(9600); + break; + } + /* select async mode */ + TXSTA2bits.SYNC = 0; + /* enable transmitter */ + TXSTA2bits.TXEN = 1; + /* serial port enable */ + RCSTA2bits.SPEN = 1; + /* since we are using RS485, + we need to explicitly say + transmit enable or not */ + RS485_RX_DISABLE = 0; + RS485_TX_ENABLE = 0; +} + +/**************************************************************************** +* DESCRIPTION: Disables the RS485 hardware +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Disable_Port(void) +{ + RCSTA2 &= 0x4F; /* Disable the receiver */ + TXSTA2bits.TXEN = 0; /* and transmitter */ + PIE3 &= 0xCF; /* Disable both interrupts */ +} + +void RS485_Reinit(void) +{ + RS485_Set_Baud_Rate(9600); +} + +/**************************************************************************** +* DESCRIPTION: Initializes the data and the port +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Initialize(void) +{ + /* Init the Rs485 buffers */ + RS485_Comstat.RxHead = 0; + RS485_Comstat.RxTail = 0; + RS485_Comstat.Rx_Bytes = 0; + RS485_Comstat.Rx_Bufferoverrun = FALSE; + RS485_Comstat.TxHead = 0; + RS485_Comstat.TxTail = 0; + RS485_Comstat.Tx_Bytes = 0; + + /* FIXME: read the data from storage */ + /* I2C_Read_Block( + EEPROM_DEVICE_ADDRESS, + (char *)&RS485_Baud_Rate, + sizeof(RS485_Baud_Rate), + EEPROM_MSTP_BAUD_RATE_ADDR); */ + + RS485_Initialize_Port(); +} diff --git a/bacnet-stack/ports/pic18f6720/rs485.h b/bacnet-stack/ports/pic18f6720/rs485.h index 90a95902..b4dc293c 100644 --- a/bacnet-stack/ports/pic18f6720/rs485.h +++ b/bacnet-stack/ports/pic18f6720/rs485.h @@ -1,85 +1,84 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2004 Steve Karg - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307 - USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ - -#ifndef RS485_H -#define RS485_H - -#include -#include "mstp.h" - -typedef struct -{ - uint8_t RxHead; - uint8_t RxTail; - uint8_t Rx_Bytes; - uint8_t TxHead; - uint8_t TxTail; - uint8_t Tx_Bytes; - uint8_t Rx_Bufferoverrun : 1; - uint8_t Tx_Bufferoverrun : 1; -} COMSTAT; - -extern COMSTAT RS485_Comstat; -extern volatile uint8_t RS485_Rx_Buffer[MAX_MPDU]; -extern volatile uint8_t RS485_Tx_Buffer[MAX_MPDU]; -extern uint32_t RS485_Baud_Rate; - - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - void RS485_Reinit(void); - void RS485_Initialize(void); - - void RS485_Disable(void); - - void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ - uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ - uint16_t nbytes); /* number of bytes of data (up to 501) */ - - uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); /* port specific data */ - - void RS485_Interrupt_Rx(void); - - void RS485_Interrupt_Tx(void); - - uint32_t RS485_Get_Baud_Rate(void); - bool RS485_Set_Baud_Rate(uint32_t baud); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2004 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307 + USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ + +#ifndef RS485_H +#define RS485_H + +#include +#include "mstp.h" + +typedef struct { + uint8_t RxHead; + uint8_t RxTail; + uint8_t Rx_Bytes; + uint8_t TxHead; + uint8_t TxTail; + uint8_t Tx_Bytes; + uint8_t Rx_Bufferoverrun:1; + uint8_t Tx_Bufferoverrun:1; +} COMSTAT; + +extern COMSTAT RS485_Comstat; +extern volatile uint8_t RS485_Rx_Buffer[MAX_MPDU]; +extern volatile uint8_t RS485_Tx_Buffer[MAX_MPDU]; +extern uint32_t RS485_Baud_Rate; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + void RS485_Reinit(void); + void RS485_Initialize(void); + + void RS485_Disable(void); + + void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */ + uint8_t * buffer, /* frame to send (up to 501 bytes of data) */ + uint16_t nbytes); /* number of bytes of data (up to 501) */ + + uint8_t RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port); /* port specific data */ + + void RS485_Interrupt_Rx(void); + + void RS485_Interrupt_Tx(void); + + uint32_t RS485_Get_Baud_Rate(void); + bool RS485_Set_Baud_Rate(uint32_t baud); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/bacnet-stack/ports/pic18f6720/stdbool.h b/bacnet-stack/ports/pic18f6720/stdbool.h index 716b66e0..696ffd85 100644 --- a/bacnet-stack/ports/pic18f6720/stdbool.h +++ b/bacnet-stack/ports/pic18f6720/stdbool.h @@ -1,28 +1,28 @@ -#ifndef STDBOOL_H -#define STDBOOL_H - -/* C99 Boolean types for compilers without C99 support */ - -#ifndef __cplusplus -typedef char _Bool; -#ifndef bool -#define bool _Bool -#endif -#ifndef true -#define true 1 -#endif -#ifndef false -#define false 0 -#endif -#define __bool_true_false_are_defined 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#endif +#ifndef STDBOOL_H +#define STDBOOL_H + +/* C99 Boolean types for compilers without C99 support */ + +#ifndef __cplusplus +typedef char _Bool; +#ifndef bool +#define bool _Bool +#endif +#ifndef true +#define true 1 +#endif +#ifndef false +#define false 0 +#endif +#define __bool_true_false_are_defined 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#endif diff --git a/bacnet-stack/ports/pic18f6720/stdint.h b/bacnet-stack/ports/pic18f6720/stdint.h index 427414c1..e9629b20 100644 --- a/bacnet-stack/ports/pic18f6720/stdint.h +++ b/bacnet-stack/ports/pic18f6720/stdint.h @@ -1,18 +1,18 @@ -/* Defines the standard integer types that are used in code */ - -#ifndef STDINT_H -#define STDINT_H 1 - -#include - -typedef unsigned char uint8_t; /* 1 byte 0 to 255 */ -typedef signed char int8_t; /* 1 byte -127 to 127 */ -typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */ -typedef signed short int16_t; /* 2 bytes -32767 to 32767 */ -/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */ -typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */ -typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */ -/* typedef signed long long int64_t; */ -/* typedef unsigned long long uint64_t; */ - -#endif /* STDINT_H */ +/* Defines the standard integer types that are used in code */ + +#ifndef STDINT_H +#define STDINT_H 1 + +#include + +typedef unsigned char uint8_t; /* 1 byte 0 to 255 */ +typedef signed char int8_t; /* 1 byte -127 to 127 */ +typedef unsigned short uint16_t; /* 2 bytes 0 to 65535 */ +typedef signed short int16_t; /* 2 bytes -32767 to 32767 */ +/*typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215 */ +typedef unsigned long uint32_t; /* 4 bytes 0 to 4294967295 */ +typedef signed long int32_t; /* 4 bytes -2147483647 to 2147483647 */ +/* typedef signed long long int64_t; */ +/* typedef unsigned long long uint64_t; */ + +#endif /* STDINT_H */ diff --git a/bacnet-stack/tsm.c b/bacnet-stack/tsm.c index 103dded5..434d1cdf 100644 --- a/bacnet-stack/tsm.c +++ b/bacnet-stack/tsm.c @@ -298,12 +298,9 @@ bool tsm_invoke_id_failed(uint8_t invokeID) bool I_Am_Request = true; /* dummy function stubs */ -int datalink_send_pdu( - BACNET_ADDRESS * dest, - BACNET_NPDU_DATA * npdu_data, - uint8_t * pdu, - unsigned pdu_len) -{ +int datalink_send_pdu(BACNET_ADDRESS * dest, + BACNET_NPDU_DATA * npdu_data, uint8_t * pdu, unsigned pdu_len) +{ (void) dest; (void) npdu_data; (void) pdu; @@ -315,7 +312,7 @@ int datalink_send_pdu( /* dummy function stubs */ void datalink_get_broadcast_address(BACNET_ADDRESS * dest) { - (void)dest; + (void) dest; } void testTSM(Test * pTest) diff --git a/bacnet-stack/wp.c b/bacnet-stack/wp.c index be643cae..7499f757 100644 --- a/bacnet-stack/wp.c +++ b/bacnet-stack/wp.c @@ -68,7 +68,7 @@ int wp_encode_apdu(uint8_t * apdu, len = encode_opening_tag(&apdu[apdu_len], 3); apdu_len += len; for (len = 0; len < data->application_data_len; len++) { - apdu[apdu_len+len] = data->application_data[len]; + apdu[apdu_len + len] = data->application_data[len]; } apdu_len += data->application_data_len; len = encode_closing_tag(&apdu[apdu_len], 3); @@ -97,7 +97,7 @@ int wp_decode_service_request(uint8_t * apdu, int type = 0; /* for decoding */ int property = 0; /* for decoding */ uint32_t unsigned_value = 0; - int i = 0; /* loop counter */ + int i = 0; /* loop counter */ /* check for value pointers */ if (apdu_len && data) { @@ -128,13 +128,13 @@ int wp_decode_service_request(uint8_t * apdu, if (!decode_is_opening_tag_number(&apdu[len], 3)) return -1; /* determine the length of the data blob */ - data->application_data_len = bacapp_data_len(&apdu[len], - apdu_len-len, property); + data->application_data_len = bacapp_data_len(&apdu[len], + apdu_len - len, property); /* a tag number of 3 is not extended so only one octet */ len++; /* copy the data from the APDU */ for (i = 0; i < data->application_data_len; i++) { - data->application_data[i] = apdu[len+i]; + data->application_data[i] = apdu[len + i]; } /* add on the data length */ len += data->application_data_len; @@ -195,7 +195,8 @@ int wp_decode_apdu(uint8_t * apdu, return len; } -void testWritePropertyTag(Test * pTest, BACNET_APPLICATION_DATA_VALUE * value) +void testWritePropertyTag(Test * pTest, + BACNET_APPLICATION_DATA_VALUE * value) { BACNET_WRITE_PROPERTY_DATA data = { 0 }; BACNET_WRITE_PROPERTY_DATA test_data = { 0 }; @@ -207,7 +208,7 @@ void testWritePropertyTag(Test * pTest, BACNET_APPLICATION_DATA_VALUE * value) uint8_t test_invoke_id = 0; data.application_data_len = - bacapp_encode_application_data(&data.application_data[0],value); + bacapp_encode_application_data(&data.application_data[0], value); len = wp_encode_apdu(&apdu[0], invoke_id, &data); ct_test(pTest, len != 0); /* decode the data */ @@ -219,17 +220,14 @@ void testWritePropertyTag(Test * pTest, BACNET_APPLICATION_DATA_VALUE * value) ct_test(pTest, test_data.object_property == data.object_property); ct_test(pTest, test_data.array_index == data.array_index); /* decode the application value of the request */ - len = bacapp_decode_application_data( - test_data.application_data, - test_data.application_data_len, - &test_value); + len = bacapp_decode_application_data(test_data.application_data, + test_data.application_data_len, &test_value); ct_test(pTest, test_value.tag == value->tag); switch (test_value.tag) { case BACNET_APPLICATION_TAG_NULL: break; case BACNET_APPLICATION_TAG_BOOLEAN: - ct_test(pTest, test_value.type.Boolean == - value->type.Boolean); + ct_test(pTest, test_value.type.Boolean == value->type.Boolean); break; case BACNET_APPLICATION_TAG_UNSIGNED_INT: ct_test(pTest, test_value.type.Unsigned_Int == @@ -247,22 +245,16 @@ void testWritePropertyTag(Test * pTest, BACNET_APPLICATION_DATA_VALUE * value) value->type.Enumerated); break; case BACNET_APPLICATION_TAG_DATE: - ct_test(pTest, test_value.type.Date.year == - value->type.Date.year); + ct_test(pTest, test_value.type.Date.year == value->type.Date.year); ct_test(pTest, test_value.type.Date.month == value->type.Date.month); - ct_test(pTest, test_value.type.Date.day == - value->type.Date.day); - ct_test(pTest, test_value.type.Date.wday == - value->type.Date.wday); + ct_test(pTest, test_value.type.Date.day == value->type.Date.day); + ct_test(pTest, test_value.type.Date.wday == value->type.Date.wday); break; case BACNET_APPLICATION_TAG_TIME: - ct_test(pTest, test_value.type.Time.hour == - value->type.Time.hour); - ct_test(pTest, test_value.type.Time.min == - value->type.Time.min); - ct_test(pTest, test_value.type.Time.sec == - value->type.Time.sec); + ct_test(pTest, test_value.type.Time.hour == value->type.Time.hour); + ct_test(pTest, test_value.type.Time.min == value->type.Time.min); + ct_test(pTest, test_value.type.Time.sec == value->type.Time.sec); ct_test(pTest, test_value.type.Time.hundredths == value->type.Time.hundredths); break;