SDK enhancements for multiple components

Document created by cdnadmin on Jan 24, 2014
Version 1Show Document
  • View in full screen mode
This document was generated from CDN thread

Created by: Charles Schoening on 02-08-2010 08:09:54 PM
Below is a draft of our new SDK header file for managing components within an EndPoint. The primary changes are:

* Get/set callback functions have added an index argument

* energywise_configIdentity() has new entityVector and vectorSize parameters which together define the indices 
of child entities.

* Attributes for name, role, keywords, type, and importance have been removed from energywise_configIdentity() 
and become callbacks. The callbacks added are:
fn_get_name fn_set_name
fn_get_role fn_set_role
fn_get_keywords fn_set_keywords
fn_get_importance fn_set_importance
fn_get_deviceType

* energywise_modified_attribute has been removed as these attributes are now callbacks

* fn_get_usageCategory is a new callback to define usage as a Producer, Consumer, or Meter 


/*
============================================================================
Name : SvcApi.h
Author : Brad Schoening
Description : Service definitions for EnergyWise EndPoint API
============================================================================

Copyright (c) 2009-2010 by Cisco Systems, Inc.
*/

/**
* @file
* EnergyWise SDK function signatures and descriptions 
*/
#ifndef SVCAPI_H_
#define SVCAPI_H_

#include "EnergyWise.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* energywise_svc_status
* * DOWN initially
* * INITIALIZING when energywise_svc_startup() is called, 
* then UP after broadcast of discovery event
* * ACTIVE after receiving ACK from discovery broadcast
*/
typedef enum energywise_svc_status {
SVC_STATUS_ERROR = -1,
SVC_STATUS_DOWN = 0, // Engine is not running, either not started or shutdown
SVC_STATUS_INITIALIZING = 2, // Engine is starting up
SVC_STATUS_UP = 1, // Engine is up and advertising, but has not received an ACK
SVC_STATUS_ACTIVE = 3, // Engine is up and advertising and has been acknowledged (ACK)
SVC_STATUS_REQUESTED_SHUTDOWN = 4 // Engine will shutdown at next discovery interval
} energywise_svc_status_t;

/*
* This section defines function signatures types used in the energywise_svc_registry
*/

typedef int (*service_energywise_next_seqid_type) ();
typedef void (*service_energywise_notify_port) (unsigned short port);
typedef void* (*energywise_svc_get_var_binary) (uint32_t index, int *length);

typedef int (*energywise_svc_get_int) (uint32_t index);
typedef int8_t (*energywise_svc_get_int8) (uint32_t index);
typedef uint8_t (*energywise_svc_get_uint8) (uint32_t index);
typedef uint16_t (*energywise_svc_get_uint16) (uint32_t index);
typedef char* (*energywise_svc_get_string) (uint32_t index);
typedef int (*energywise_svc_set_uint8) (uint32_t index, uint8_t value);
typedef char* (*energywise_svc_set_string) (uint32_t index, char* value);
typedef int (*energywise_svc_fill_int_array) (uint32_t index, int* arg);
typedef int (*energywise_svc_fill_ushort_array) (uint32_t index, uint16_t* arg);

/**
* This structure holds callback services for the SDK. Each callback should be
* initialized and then the structure passed to energywise_svc_configRegistry.
*/
typedef struct energywise_svc_registry {

/**
* These callback functions are used to retrieve the units, usage, caliber,
* and level information from your system. They are required by the system
* and must return back the correct datatype. Each callback function must be 
* supplied an index value in order to specify which entity to get from.
*
* Additional Note: These callbacks are issued once for every discovery
* interval for the system (default 3 minutes), as well as whenever an 
* EnergyWise query requests them.
*/
energywise_svc_get_int8 fn_get_units;
energywise_svc_get_uint16 fn_get_usage;
energywise_svc_get_int fn_get_usageCaliber;
energywise_svc_get_uint8 fn_get_level;
energywise_svc_get_string fn_get_name;
energywise_svc_get_string fn_get_role;
energywise_svc_get_string fn_get_keywords;
energywise_svc_get_string fn_get_deviceType;
energywise_svc_get_uint8 fn_get_importance;

/**
* These callback functions are used to set the level, name, role, keywords, deviceType, and importance
* from your system. They are required by the system and must be sent the correct datatype. 
* Each callback function must be supplied an index value in order to specify the appropriate entity
* to set.

*/
energywise_svc_set_uint8 fn_set_level;
energywise_svc_set_string fn_set_name;
energywise_svc_set_string fn_set_role;
energywise_svc_set_string fn_set_keywords;
energywise_svc_set_uint8 fn_set_importance;

/**
* These callbacks are used to fill in the appropriate vector that has
* been requested by the system. The call will provide an address
* of an already existing array. Your callback must fill in the array
* with the corresponding values.
*
* UsageVector[0..10] represents the maximum power usage for a given level
* DeltaVector[0..10] represents UsageVector<em style="font-style: italic;"> - current_usage for a level
*/
energywise_svc_fill_ushort_array fn_fill_usageVector;
energywise_svc_fill_int_array fn_fill_deltaVector;

/**
* This callback must supply the system with the next sequence ID to use
* for the next EnergyWise event. It is recommended that your application
* persist the last sequence number so that it can be retrieved in case of
* restart or system going down.
*/
service_energywise_next_seqid_type energywise_next_seqid;

/**
* This callback is provided to notify the application which TCP listening
* port has been opened for communication. This is provided as information
* in case you must notify any other systems or configure anything else for
* security (i.e. firewall).
*/
service_energywise_notify_port energywise_listen_port;

/**
* This callback is used to request variable binary data from the client.
* This generic data type defined as EW_ATTRIBUTE_TYPE_VARIABLE_BINARY_DATA 
* and can be used to pass any type of information from the client SDK to
* the management API. The management API can bind to this and read out
* the data. The user can define their own data structure and place any
* type of information they would like in this buffer.
*
* The callback shall return a pointer to the buffer and pass back the
* length of the buffer through the pointer in the argument list. The
* SDK will make a deep copy of the buffer before sending out.
*
* This variable binary data is limited to a MAX size of 1024 bytes.
*
* As a reference, this variable binary data would be the SQL equivalent
* of: varbinary(1024).
*/
energywise_svc_get_var_binary fn_get_variable_binary_data;
} energywise_svc_registry_t;

/* forward declaration of internal session structure type */

typedef struct enw_svc_session enw_svc_session_t;

/**
* Allocates and initializes a session structure and establishes network 
* configurations.
*
* @param *localaddr The local host address in dotted quad notation ("x.x.x.x").
*
* @param remote_port The Remote EnergyWise port that the connected switch
* is configured to run EnergyWise on. If zero, the default value of IANA
* 43440 will be used.
*
* @param *id A 36-byte EnergyWise ID. Includes a 32-byte representaiton of 
* a UUID or Cisco UDI and a 4-byte physical index.
*
* @param *key A compiled security key used for authentication that has 
* been generated using the provided utility function. Can be NULL if 
* endpoint security has been set to "security none".
*
* @param key_len Length, in bytes, of the uchar* key passed in. Should be
* 0 if *key is NULL in case of security none.
*
* @param listen_port Optionally specify the local TCP port to listen for
* EnergyWise events on. If 0, then the system will choose any available TCP port.

* @return session A handle to the structure holding all information used by the
* SDK to establish and run its internal processing. This is NULL if an error
* occured.
*
* @usage
* This must be used to create and initialize the client SDK session. Note
* that when endpoint security is set to shared-secret, you must first 
* generate the security key using the provided utility function. However,
* if the endpoint security is set to none, then key should be NULL with
* key_len set to 0.
*
* @codeexample
* Provide that I already have a UUID and have created a key in variable my_key,
* create a session with my local ip:port of 10.10.10.1:43440.
* @code
* session = energywise_svc_create ("10.10.10.1", 43440, my_uuid 
* my_key, key_len, 0);
* @endcode 
*/
enw_svc_session_t*
energywise_svc_create(const char* localaddr, unsigned short remote_port, const energywise_sender_id_t *id, const unsigned char* key, int key_len,
unsigned short listen_port);

/**
* Configures the callback registry functions. The passed registry structure 
* must remain allocated in memory until the discovery engine is shutdown.
*
* @param *session A handle to the structure holding all information used by
* the SDK to establish and run its internal processing.
*
* @param *callbackRegistry A pointer to a fully configured registry for the
* EnergyWise callback functions.
*
* @retval 0 Success
* @retval -1 Failure
*
* @usage
* Use this once you have created the session and setup your callback registry.
* This must be configured for the function callbacks to work properly.
*
* @todo Need code example here
*/
int
energywise_svc_configRegistry(enw_svc_session_t* session, const energywise_svc_registry_t* callbackRegistry);

/**
* Starts the discovery engine. This call will not return until the engine
* is shutdown.
*
* @param *session A handle to the structure holding all information used by
* the SDK to establish and run its internal processing.
*
* @retval 0 Success
* @retval -1 Failure
*
* @usage
* This must be executed to actually startup the service and begin the client.
*/
int
energywise_svc_startup(enw_svc_session_t* session);

/**
* Posts a request for the engine to shutdown. The engine will shutdown on or before the next
* scheduled discovery event broadcast. Must be called from a different thread than the one
* that invoked startup.
*
* @param *session A handle to the structure holding all information used by
* the SDK to establish and run its internal processing.
*
* @retval 0 Request to shutdown was sent.
* @retval -1 Request failed, could not send request to shutdown.
*
* @usage 
* This function is to be used when a nice shutdown of the service is desired.
* It will cause the client to be disconnected from the switch it is connected
* to.
*/
int
energywise_svc_shutdown(enw_svc_session_t* session);

/**
* Answer the discovery engine status. See the status enum for possible values.
*
* @param *session A handle to the structure holding all information used by
* the SDK to establish and run its internal processing.
*
* @return An energywise_svc_status_t enum value indicating the status.
*
* @usage
* Use this when you need to know the current status of the running service.
*/
energywise_svc_status_t
energywise_svc_getStatus(enw_svc_session_t* session);

/**
* Set the number of seconds to wait between discovery advertisements once an
* initial discovery has been ACK-ed.
*
* @param *session A handle to the structure holding all information used by
* the SDK to establish and run its internal processing.
*
* @param seconds The number of seconds to wait between updates.
*
* @retval 0 Value was set properly
* @retval -1 Value was not set because it was outside the limits.
*
* @usage
* This is to be used if you would like the client to send updates to the
* switch more often or less often. The default is 180 seconds.
*/
int
energywise_svc_setDiscoveryInterval(enw_svc_session_t* session, int seconds);

/**
* Configures the shared attributes of a EnergywWise Midpoint and its children.
*
* @param *session A handle to the struture holding all information used by
* the SDK to establish and run its internal processing.
*
* @param *domain The EnergyWise domain name. This must match the domain
* name of the target switch the SDK is communicating with.
*
* @param entityVector The array of entities that are children of the EnergyWise
* Midpoint. Index values must be positive, non-zero values. For example, a Midpoint 
* with 4 children would create an entityVector array, assign four specific index 
* values to the array
* entityVector[0] = 10;
* entityVector[1] = 20;
* entityVector[2] = 30;
* entityVector[3] = 40;
* and pass the array to the function. In this case, the index values of 10, 20, 30
* and 40 correspond to the 4 different indicies associated with the Midpoint's children. 
* Passing an empty array, or a NULL value, with size of 0, corresponds to an Endpoint with
* no children.

* @param vectorSize The size, in number of elements, of the entityVector. This value 
* should equal the number of children controlled by the Midpoint.

* @retval 0 Success
* @retval -1 Failure
*
* @usage
* Use this to initialize the shared attributes associated with this host.
*/
int
energywise_configIdentity(enw_svc_session_t *session, const char* domain, uint32_t entityVector[], int vectorSize);

#ifdef __cplusplus
}
#endif

#endif /* SVCAPI_H_ */

Subject: RE: SDK enhancements for multiple components
Replied by: Christopher Verges on 02-08-2010 10:33:44 PM
Below is a draft of our new SDK header file for managing components within an EndPoint. The primary changes are:

* Get/set callback functions have added an index argument

* energywise_configIdentity() has new entityVector and vectorSize parameters which together define the indices 
of child entities.

* Attributes for name, role, keywords, type, and importance have been removed from energywise_configIdentity() 
and become callbacks. The callbacks added are:
fn_get_name fn_set_name
fn_get_role fn_set_role
fn_get_keywords fn_set_keywords
fn_get_importance fn_set_importance
fn_get_deviceType

* energywise_modified_attribute has been removed as these attributes are now callbacks

* fn_get_usageCategory is a new callback to define usage as a Producer, Consumer, or Meter

 
Hi Brad,
 
Would you mind touching on the hierarchical nature that this new index-based SDK allows?  For example, let's assume that there is a EndPoint of type METER which has an aggregate meter as well as several child meters.
 
One question that comes to mind relates to naming.  Let's further assume that the legacy SDK would call such an EndPoint "name."  What should fn_get_name() return -- "child", "child.name", "child.aggregate.name", etc.?
 
How deep can the aggregate/child hierarchy be?
 
How will this power information be consumed to ensure that power metrics aren't counted twice?  (Querying the all children + the aggregate would result in duplication of power metrics.)
 
What other considerations do we need to keep in mind while implementing the new SDK modifications?
 
Thanks,
Chris

Subject: RE: SDK enhancements for multiple components
Replied by: Brad Schoening on 20-08-2010 02:29:08 PM
 
Here is some feedback we received from one user of the SDK+ Alpha :
 
I would prefer if the svc_get_string  callback provide address of memory and size where
we, users, copy data instead of expecting a pointer to a memory where we keep
data. That way it would be clear what is the max size of those string and also
it would be safer because we would not mess up each others memory.

 

Subject: RE: SDK enhancements for multiple components
Replied by: Christopher Verges on 21-08-2010 10:35:04 AM
I would prefer if the svc_get_string  callback provide address of memory and size where we, users, copy data instead of expecting a pointer to a memory where we keep data

 
This is a good suggestion.  It separates memory management responsibilities between the EnergyWise library and the vendor-specific code, which should result in a more simplified and stable platform overall.  We'd most likely use snprintf() or a language-equivalent function to copy the data from our databases/buffers into the EW library's buffer in a safe manner.
 
This would also help in that it provides a good, clear boundary on the maximum size of some of these parameters.
 
Chris

Subject: RE: SDK enhancements for multiple components
Replied by: Christopher Verges on 21-08-2010 05:15:56 PM
Upon more reflection, I'm going to question my own posting.  There is a classic trade-off between performance and memory usage here.  On one hand, maintaining a static array in memory and simply giving pointers to that is the best for performance and efficiency, yet costs a fixed amount of memory that may be larger than what is needed for any one transaction.  Allowing the SDK+ to manage its own internal memory would help to reduce memory (slightly?), but may have a small impact on performance.
 
I propose that you ignore my previous posting and instead adopt a hybrid model that allows the specific vendor to implement whatever he/she needs for the target platform.  If the platform has extra memory to spare, then let it boost its performance.  Otherwise, let it optimize for memory usage.
 
The existing SDK+ proposal makes sense with this hybrid model.  If the implementer wants to do any specialized memory management, they would be responsible for it.  The SDK+ simply says "give me a pointer to memory, and I don't care how you manage it."  This poses some interesting synchronization challenges when it comes to freeing dynamically malloc'd memory, for example, but they will be statically known, based on the implementation.  Perhaps there needs to be a #define flag such as follows:
 

#define FREE_GET_STRING_POINTERS        (0) /* or (1) */
 
#if FREE_GET_STRING_POINTERS
     #define FREE_GET_STRING(ptr) do { free((ptr)); } while (0)
#else
     #define FREE_GET_STRING(ptr) do { } while (0)
#endif
 
void some_sdk_function(void)
{
     uint32_t index;
     char *name = registry.fn_get_name(index);
 
     FREE_GET_STRING(name);
}

 
In this way, memory can be dynamically allocated by the vendor's code and free'd by the vendor-specific compile of the SDK+.  Alternatively, memory can be statically allocated by the vendor's code and left along for reuse purposes.  This gives great flexibility to the vendor on the specific implementation choice.
 
The existing SDK+ headers should work as-is with this proposal, with the only change being the addition of the FREE_GET_STRING* macros described above.
 
Thoughts?  Since this affects vendors who are implementing the SDK+ so heavily, I'd really like to hear from those of you out there in the partner community.
 
Thanks,
Chris

Attachments

    Outcomes