<!-- ...................................................................... -->
<!-- $Id: plugin_guide.sgml,v 1.10 2009/01/19 07:36:20 subrata_modak Exp $ ........................................ -->
<!-- 
        (C) Copyright Intel Corporation. 2003
 
        Authors:
            Tariq Shureih <tariq.shureih@intel.com>

        This material may be distributed only subject to the terms and 
        conditions set forth in the Open Publication License, v1.0 or later 
        (the latest version is currently available at 
        http://www.opencontent.org/openpub/).  Distribution of substantively 
        modified version of this document is prohibited without the explicit 
        permission of the copyright holder.

        Other company, product, or service names may be trademarks or service 
        marks of others.
-->

<chapter>
  <title>OpenHPI Plugin Development Guide</title>
  <para>
	This chapter is a developer's guide to writing an openhpi plug-in.
	The hope is that by providing this documentation in addition to
	the source code in CVS, developers will have all the tools needed
	to enable support for a given platform under openhpi.
  </para>

  <sect1>

    <title>General plug-in concepts</title>

    <para>
	As explained earlier in this manual, plug-ins are at the heart of openhpi.
	They serve as the proxy to hardware management interfaces and protocols.
	A plug-in has two main roles.
	First, to interface with the hardware management interface and gather data.
	Second, format that data into HPI data structures and send them up to the
	main openHpi library.
	
	Further, as openHpi based application need to communicate commands to the
	hardware, the infrastructure library uses the 'abi' interface functions
	to communicate with a plug-in and send commands and/or data to the hardware.
    </para>

    <para>
	Every plug-in in openhpi requires the following:
	<literal>struct oh_abi_v2</literal> declaration such as:
    </para>

    <para>
    <programlisting role="C">

static struct oh_abi_v2 my_plugin = {
	.open				= my_open,
	.close				= my_close,
	.get_event			= my_get_event,
	.discover_resources     	= my_discover_resources,
	.get_self_id			= my_get_self_id,
	.get_sel_info			= my_get_sel_info,
	.set_sel_time			= my_set_sel_time,
	.add_sel_entry			= my_add_sel_entry,
	.del_sel_entry			= my_del_sel_entry,
	.get_sel_entry			= my_get_sel_entry,
	.get_sensor_data		= my_get_sensor_data,
	.get_sensor_thresholds		= my_get_sensor_thresholds,
	.set_sensor_thresholds		= my_set_sensor_thresholds,
	.get_sensor_event_enables	= my_get_sensor_event_enables,
	.set_sensor_event_enables	= my_set_sensor_event_enables,
	.get_control_state		= my_get_control_state,
	.set_control_state		= my_set_control_state,
};
    </programlisting>
    </para>

    <para>
	This C99 style structure relates to the function pointers defined
	in <literal>plugin.h</literal> and is the entry point into plug-in functions.

	The sesond requirement is the get_interface function which is called
	when a plug-in is initialized by the infrastructure.
	It exposes the internal (above) functions a plug-in supports/implements.

	The functions looks like:
    </para>

    <para>
    <programlisting role="C">
int get_interface(void **pp, uuid_t uuid)
{
	if (uuid_compare(uuid, UUID_OH_ABI_V2)==0) {
		*pp = &<literal>oh_my_plugin</literal>;
		return 0;
	}

	*pp = NULL;
	return -1;
}
    </programlisting>
    </para>

    <para>
    <emphasis>
	I will try to describe the plug-in interface (ABI) functions needed
	to get a plug-in started.  Remember that the implementation of these functions
	is usually dependent on the hardware management protocol and platform you're 
	enabling
    </emphasis>

    </para>
    </sect1>
   
   <sect1>
   
     <title>Naming convention and return codes</title>
     <para>

	You'll notice through out the code that functions, variables and structures
	start with <literal>oh_</literal>.
	This stands for OpenHpi :)
     </para>

     <para>
	Return codes:
     </para>

     <para>
	Plug-ins in OpenHpi shall return 0 for success and negative numbers for errors.
     </para>

     <note>
     <para>
	 The use of HPI defined return codes such as SA_OK and SA_ERR_HPI_ERROR
	 is allowed as well; given that it will not present a problem
	 on different architectures.
     </para>
     </note>
   </sect1>

   <sect1>

    <title>The <literal>Open</literal> function</title>
    <para>
    <programlisting>
	prototype:
	static void *my_open(GHashTable *config_file);
    </programlisting>
    </para>

    <para>
	The open function is the first function called when a plug-in is initialized.
	It takes one parameter of type GHashTable (from glib), a pointer to the hanlder's
	config hash which would have all parameters for your plug-in.
    </para>

    <para>
	In the open function you would do what your plug-in requires to initialize
	access to the hardware management protocol.
    </para>

    <para>
	Further, you would initialize the oh_handler_state elements. Allocate the 
	handler structure, parse the plug-in parameters from the confi hash, allocate
	the rptcache and initialize any private data structures in your plug-in.
    </para>

    <para>
	When done, you would return a pointer to the handler allocated for this plugin
	instance.
    </para>

   </sect1>

   <sect1>

    <title>The <literal>close</literal> function</title>

    <para>
    <programlisting>
	prototype:
	static void my_close(void *hnd);
    </programlisting>
    </para>

    <para>
	The close function is called when a plug-in is finalized.
	You would close any open connection, free any private data structures and
	terminate all loose data.
    </para>

   </sect1>

   <sect1>

    <title>The <literal>discover_resources</literal> function</title>

    <para>
    <programlisting>
	prototype:
	static int *discover_resources(*hnd);
    </programlisting>
    </para>

    <para>
	The discover_resources function is the function which reports the plug-in's
	findings of resources, sensors, controls, etc. to the infrastructure.
    </para>

    <para>
	In most existing plug-ins, the code would retrieve RPT entries from the rptcache
	and format them into oh_event(s) structures and append them into the eventq.
	The infrastructure would retrieve these events from each plug-in defined in the
	config file and store them in the main RPT table of the infrastructure.
    </para>

   <sect2>

    <title>The <literal>oh_handler_state</literal> structure</title>

    <para>
	So now is a good time to talk about the <literal>oh_handler_state</literal>
    </para>


    <para>
	The oh_handler_state structure contains:
    <programlisting role="c">
    struct oh_handler_state {
	RPTable *rptcache;
	GSList *eventq;
	GHashTable *config;
	void *data;
    };
    </programlisting>
    </para>

    <para>
	The oh_handler_state happens to be the state structure of a plug-in.
	Meaning it holds the rptcache, eventq and config data of a plug-in as
	well as a pointer to private data which the plug-in owner may decide to
	hold private to the plug-in.
    </para>

    <para>
	Part of the discover_resources function is to invoke routines which talk
	to the hardware and gather resource information and format them into HPI
	RPT (entries).  Further, the discover_resources function formats the entries
	into an openhpi "event" union provided by (look at oh_plugin.h):
    <programlisting role="c">
	struct oh_event {
        	enum {
                	OH_ET_RESOURCE,
                	OH_ET_RESOURCE_DEL,
	                OH_ET_RDR,
        	        OH_ET_RDR_DEL,
                	OH_ET_HPI
	        }type;
        	union {
                	struct oh_resource_event res_event;
	                struct oh_resource_del_event res_del_event;
        	        struct oh_rdr_event      rdr_event;
                	struct oh_rdr_del_event  rdr_del_event;
                	struct oh_hpi_event      hpi_event;
        	} u;
	};
    </programlisting>
	and pushes these events into the oh_handler_stats's eventq (GSList) for later
	retrieval by the get_event() function.
    </para>

   </sect2>

   </sect1>

   <sect1>

    <title>The <literal>get_event</literal> function</title>

    <para>
    <programlisting role="c">
	prototype:
	static int my_get_event(void *hnd, struct oh_event *event, struct timeval *timeout) 
    </programlisting>
    </para>
   
    <para>
	The get_event function currently gets called from the openhpi infrastructure 
	library	to retrieve a plug-in's (openhpi) events.
    </para>

    <para>
	This function would typically loop over the eventq of the plug-in
	instance and copy the event's data field (currently a GSList) 
	into <literal>event</literal> which gets processed by the openhpi
	library based on the event type and eventually added to the RPT table.
    </para>

    <para>
	The <literal>timeout</literal>parameter is used wait for an event until timeout.
	If set to zero (currently) it will return once the call is done.
    </para>

    <note> 
    <para>
	Note that currently there is on domain (SAHPI_DEFAULT_DOMAIN_ID)
	and one global RPT table where all reported resources from all
	plug-ins are stored.
    </para>
    </note>

   </sect1>

   <sect1>

    <title>discover_resources, saHpiResourceDiscover and get_event</title>

    <para>
	It important to understand how the <literal>saHpiResourceDiscover</literal>
	, ABI <literal>discover_resources</literal> and <literal>get_event</literal>
	are related.  This will explain how resources are communicated between
	a plug-in and the openhpi infrastructure library
    </para>

    <para>
    	The user application would call the <literal>saHpiResourceDiscover</literal>
	function which in turn calls the ABI function 
	<literal>discover_resources</literal> of all the plug-ins defined in the
	config file.  All this does is instruct the plug-ins to discover their 
	resources and causes them to be stored in the plug-in's rptcache and eventq.
	So far, the infrastructure did not get any events from the plug-in and the
	global RPT is empty.
    </para>

    <para>
	Once the ABI <literal>discover_resources</literal> returns, another function
	in the library is called -- <literal>get_events</literal> -- which is defined
	in event.c, processes each handler (plug-in) events by calling the ABI
	<literal>get_event</literal>.  Depending on the type of event, it will
	be processed and added to the global RPT table. 
    </para>

    <note>
    <para>
	We have a set of helper utilities to simplify manipulation
	of RPT and RDR entries into the rptcache and global RPT table.
	These are discussed later in this document.
    </para>
    </note>

   </sect1>

   <sect1>

    <title>Resources, ResourceId and EntityPath</title>

    <para>
	It is important to understand the relationship between a Resource,
	it's ID and it's EntityPath.
    </para>

    <para>
	In order be able to re-call the resource by it's ResourceId as well as
	have persistence in resource identification between sessions, openhpi
	persisted the SaHpiResourceIdT ResourceId field in the RptEntry structure
	using the resource's entitpath, being unique, by converting the resource's
	EntityPath to string, appending the root path defined in the config file
	to it then converting it to a unique number using uid utilities provided by
	openhpi.
    </para>

   </sect1>

   <sect1>

    <title>OpenHPI internal helper utility interfaces</title>
    <sect2><title>SNMP Utilities</title>&snmp-util;</sect2>
    <sect2><title>RPT Utilities</title>&rpt-utils;</sect2>
    <sect2><title>Entity Path Utilities</title>&epath-utils;</sect2>
    <sect2><title>Resource UID Utilities</title>&uid-utils;</sect2>
	
   </sect1>

   <sect1>

    <title>Sensor functions</title>

    <para>In this section I will demonstrate how to implement a sensor
	function in an openhpi plug-in.
    </para>

    <sect2>
    
    <title>The get_sensor_data function</title>

    <para>
    <programlisting role="c">
	static int my_get_sensor_data(
					void			*hnd,
					SaHpiResourceIdT	id,
					SaHpiSensorNumT		num,
					SaHpiSensorReadingT	*data)
    </programlisting>
    </para>

    <para>
	This function retrieves sensor data such as reading and thresholds.
	A sensor in HPI context is an RDR record associated with a resource or
	RPT.  An example would be a temperature sensor on a CPU where the CPU
	is the RPT with the sensor as the RDR associated with it.	
    </para>

    <para>
	This function is an ABI function implemented in a plug-in and gets called
	from the infrastructure library via a pointer to the function when the
	HPI saHpiSensorReadingGet() is called.	    
    </para>

    <para>
	The first parameter is the the plug-in which reported this sensor originally.
	The second is the resource id of the the sensor's parent or the resource
	the sensor is attached/belongs to.
	The third is the sensor number the caller is requesting the data for.
	And the fourth is the structure returned with the data.
    </para>

    <para>
	Depending on the hardware management protocol your plug-in is using,
	you would write internal routines here to retrieve sensor data from
	the hardware and return them using the HPI SaHpiSensorReadingT data type.
    </para>

    </sect2>


   </sect1>
</chapter>
