From 5a99f0662cdf896cced9b8243baa3b11e46c1f60 Mon Sep 17 00:00:00 2001 From: tbrennan3 Date: Tue, 23 Mar 2010 04:55:11 +0000 Subject: [PATCH] Commented the demo/server in a new module. Embedded its PICS in the server documentation (hopefully a good idea). Added a PrettyPrintPropertyValue() function to the epics program (hopefully OK format). Added a function apdu_service_supported_to_index() to the apdu code to translate a SERVICE_SUPPORTED_ enum to its SERVICE_CONFIRMED_ or SERVICE_UNCONFIRMED_ index, and used it when PrettyPrinting services. --- bacnet-stack/demo/epics/main.c | 87 ++++++++++++++++++++++++++++++++- bacnet-stack/demo/server/main.c | 80 +++++++++++++++++++++++++++++- bacnet-stack/include/apdu.h | 9 ++++ bacnet-stack/src/apdu.c | 44 +++++++++++++++++ 4 files changed, 218 insertions(+), 2 deletions(-) diff --git a/bacnet-stack/demo/epics/main.c b/bacnet-stack/demo/epics/main.c index 5169f3bc..1b2585be 100644 --- a/bacnet-stack/demo/epics/main.c +++ b/bacnet-stack/demo/epics/main.c @@ -135,6 +135,85 @@ void MyRejectHandler( Error_Detected = true; } +/** Provide a nicer output for Supported Services and Object Types. + * + * @param stream + * @param value + * @param property + * @return + */ + + bool PrettyPrintPropertyValue( + FILE * stream, + BACNET_APPLICATION_DATA_VALUE * value, + BACNET_PROPERTY_ID property) +{ + bool status = true; /*return value */ + size_t len = 0, i = 0, j = 0; + + if ( (value != NULL) && (value->tag == BACNET_APPLICATION_TAG_BIT_STRING) && + ( (property == PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED) || + (property == PROP_PROTOCOL_SERVICES_SUPPORTED) ) ) + { + len = bitstring_bits_used(&value->type.Bit_String); + fprintf(stream, "{ \r\n "); + for (i = 0; i < len; i++) { + fprintf(stream, "%s", + bitstring_bit(&value->type.Bit_String, + (uint8_t) i) ? " true" : "false"); + if (i < len - 1) + fprintf(stream, ","); + else + fprintf(stream, " "); + if ( (i == (len-1) ) || ( (i % 8) == 7 ) ) // line break every 8 + { + fprintf(stream, " # "); + // Now rerun the same 8 bits, but print labels for true ones + for ( j = i - (i%8); j <= i; j++) + { + if ( bitstring_bit(&value->type.Bit_String, (uint8_t) j) ) + { + if (property == PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED) + fprintf( stream, " %s,", bactext_object_type_name(j) ); + // PROP_PROTOCOL_SERVICES_SUPPORTED + else + { + bool bIsConfirmed; + size_t newIndex; + if ( apdu_service_supported_to_index( j, + &newIndex, &bIsConfirmed ) ) + { + if ( bIsConfirmed ) + fprintf( stream, " %s,", + bactext_confirmed_service_name(newIndex) ); + + else + fprintf( stream, " %s,", + bactext_unconfirmed_service_name( + (newIndex) ) ); + + } + } + } + else // not supported + fprintf( stream, "," ); + } + fprintf(stream, "\r\n "); + } + } + fprintf(stream, "}"); + } + else + { + /* How did I get here? Fix your code. */ + /* Meanwhile, a safe fallback plan */ + status = bacapp_print_value(stdout, value, property); + } + + return status; +} + + void PrintReadPropertyData( BACNET_READ_PROPERTY_DATA * data) { @@ -198,7 +277,13 @@ void PrintReadPropertyData( fprintf(stdout, "\r\n"); } } - } else { + } + else if ( (data->object_property == PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED) || + (data->object_property == PROP_PROTOCOL_SERVICES_SUPPORTED) ) + { + PrettyPrintPropertyValue(stdout, &value, data->object_property); + } + else { bacapp_print_value(stdout, &value, data->object_property); } if (len) { diff --git a/bacnet-stack/demo/server/main.c b/bacnet-stack/demo/server/main.c index 0a774124..bf7feaf3 100644 --- a/bacnet-stack/demo/server/main.c +++ b/bacnet-stack/demo/server/main.c @@ -52,9 +52,76 @@ /** @file server/main.c Example server application using the BACnet Stack */ -/* buffers used for receiving */ +/** @defgroup Demos Demos of Servers and Clients + * Most of the folders under the /demo folder contain demonstration (ie, sample) + * code that implements the name functionality. + * + * The exceptions to this general rule, /handler and /object folders, are + * described in the various BIBBs and Object Framework modules. + */ + +/** @defgroup ServerDemo Demo of a BACnet Server (Device) + * @ingroup Demos + * This is a basic demonstration of a simple BACnet Device consisting of + * the services and properties shown in its PICS (output provided by + * the demo/epics/epics program): + * @verbatim +List of Objects in test device: +{ + object-identifier: (Device, 1234) + object-name: "SimpleServer" + object-type: Device + system-status: operational + vendor-name: "BACnet Stack at SourceForge" + vendor-identifier: 260 + model-name: "GNU" + firmware-version: "0.5.5" + application-software-version: "1.0" + protocol-version: 1 + protocol-revision: 5 + protocol-services-supported: { + false,false,false,false,false, true, true, true, # ,,,,, Subscribe-COV, Atomic-Read-File, Atomic-Write-File, + false,false,false,false, true,false, true, true, # ,,,, Read-Property,, Read-Property-Multiple, Write-Property, + false, true,false,false, true,false,false,false, # , Device-Communication-Control,,, Reinitialize-Device,,,, + false,false,false,false, true,false,false,false, # ,,,, COV-Notification,,,, + true, true, true,false, true,false,false,false # Time-Synchronization, Who-Has, Who-Is,, UTC-Time-Synchronization,,,, + } + protocol-object-types-supported: { + true, true, true, true, true, true,false,false, # Analog Input, Analog Output, Analog Value, Binary Input, Binary Output, Binary Value,,, + true,false, true,false,false, true, true,false, # Device,, File,,, Multi-State Input, Multi-State Output,, + false,false,false,false, true, true,false,false, # ,,,, Trendlog, Life Safety Point,,, + false,false,false,false, true,false,false,false, # ,,,, Load-Control,,,, + false,false,false,false,false,false # ,,,,,, + } + object-list: {(Device, 1234),(Analog Input, 0),(Analog Input, 1), + (Analog Input, 2),(Analog Input, 3),(Analog Output, 0),(Analog Output, 1), + (Analog Output, 2),(Analog Output, 3),(Analog Value, 0),(Analog Value, 1), + (Analog Value, 2),(Analog Value, 3),(Binary Input, 0),(Binary Input, 1), + (Binary Input, 2),(Binary Input, 3),(Binary Input, 4),(Binary Output, 0), + (Binary Output, 1),(Binary Output, 2),(Binary Output, 3),(Binary Value, 0), + (Binary Value, 1),(Binary Value, 2),(Binary Value, 3),(Binary Value, 4), + (Binary Value, 5),(Binary Value, 6),(Binary Value, 7),(Binary Value, 8), + (Binary Value, 9),(Life Safety Point, 0),(Life Safety Point, 1),(Life Safety Point, 2), + (Life Safety Point, 3),(Life Safety Point, 4),(Life Safety Point, 5),(Life Safety Point, 6), + (Load-Control, 0),(Load-Control, 1),(Load-Control, 2),(Load-Control, 3), + (Multi-State Output, 0),(Multi-State Output, 1),(Multi-State Output, 2),(Multi-State Output, 3), + (Multi-State Input, 0),(Trendlog, 0),(Trendlog, 1),(Trendlog, 2), + (Trendlog, 3),(Trendlog, 4),(Trendlog, 5),(Trendlog, 6), + (Trendlog, 7),(File, 0),(File, 1),(File, 2)} + max-apdu-length-accepted: 1476 + segmentation-supported: no-segmentation + apdu-timeout: 3000 + number-of-APDU-retries: 3 + device-address-binding: Null + database-revision: 1 +} @endverbatim + */ +/*@{*/ + +/** Buffer used for receiving */ static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; +/** Initialize the handlers we will utilize. */ static void Init_Service_Handlers( void) { @@ -95,12 +162,21 @@ static void Init_Service_Handlers( handler_device_communication_control); } +/** Handler registered with atexit() inside main function to, well, cleanup. + * Especially if we don't end normally. + */ static void cleanup( void) { datalink_cleanup(); } +/** Main function of server demo. + * + * @param argc [in] Arg count. + * @param argv [in] Takes one argument: the Device Instance #. + * @return 0 on success. + */ int main( int argc, char *argv[]) @@ -158,3 +234,5 @@ int main( /* blink LEDs, Turn on or off outputs, etc */ } } + +/*@}*/ /* End group ServerDemo */ diff --git a/bacnet-stack/include/apdu.h b/bacnet-stack/include/apdu.h index 3d7386fe..947a86f9 100644 --- a/bacnet-stack/include/apdu.h +++ b/bacnet-stack/include/apdu.h @@ -158,6 +158,15 @@ extern "C" { bool apdu_service_supported( BACNET_SERVICES_SUPPORTED service_supported); +/* Function to translate a SERVICE_SUPPORTED_ enum to its SERVICE_CONFIRMED_ + * or SERVICE_UNCONFIRMED_ index. + */ + bool apdu_service_supported_to_index( + BACNET_SERVICES_SUPPORTED service_supported, + size_t *index, + bool *bIsConfirmed ); + + void apdu_set_error_handler( BACNET_CONFIRMED_SERVICE service_choice, error_function pFunction); diff --git a/bacnet-stack/src/apdu.c b/bacnet-stack/src/apdu.c index 30ab0924..51fca6c6 100644 --- a/bacnet-stack/src/apdu.c +++ b/bacnet-stack/src/apdu.c @@ -166,6 +166,50 @@ bool apdu_service_supported( return status; } +/** Function to translate a SERVICE_SUPPORTED_ enum to its SERVICE_CONFIRMED_ + * or SERVICE_UNCONFIRMED_ index. + * Useful with the bactext_confirmed_service_name() functions. + * + * @param service_supported [in] The SERVICE_SUPPORTED_ enum value to convert. + * @param index [out] The SERVICE_CONFIRMED_ or SERVICE_UNCONFIRMED_ index, + * if found. + * @param bIsConfirmed [out] True if index is a SERVICE_CONFIRMED_ type. + * @return True if a match was found and index and bIsConfirmed are valid. + */ +bool apdu_service_supported_to_index( + BACNET_SERVICES_SUPPORTED service_supported, + size_t *index, + bool *bIsConfirmed ) +{ + int i = 0; + *bIsConfirmed = false; + bool found = false; + + if (service_supported < MAX_BACNET_SERVICES_SUPPORTED) { + /* is it a confirmed service? */ + for (i = 0; i < MAX_BACNET_CONFIRMED_SERVICE; i++) { + if (confirmed_service_supported[i] == service_supported) { + found = true; + *index = i; + *bIsConfirmed = true; + break; + } + } + + if (!found) { + /* is it an unconfirmed service? */ + for (i = 0; i < MAX_BACNET_UNCONFIRMED_SERVICE; i++) { + if (unconfirmed_service_supported[i] == service_supported) { + found = true; + *index = i; + break; + } + } + } + } + return found; +} + /* Confirmed ACK Function Handlers */ static void *Confirmed_ACK_Function[MAX_BACNET_CONFIRMED_SERVICE];