/******************************************************************************* * * Copyright (c) 2000-2003 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************/ #include "sample_util.h" #include #include #include #if !UPNP_HAVE_TOOLS # error "Need upnptools.h to compile samples ; try ./configure --enable-tools" #endif static int initialize_init = 1; static int initialize_register = 1; /*! Function pointers to use for displaying formatted strings. * Set on Initialization of device. */ print_string gPrintFun = NULL; state_update gStateUpdateFun = NULL; /*! mutex to control displaying of events */ ithread_mutex_t display_mutex; /******************************************************************************* * SampleUtil_Initialize * * Description: * Initializes the sample util. Must be called before any sample util * functions. May be called multiple times. * But the initialization is done only once. * * Parameters: * print_function - print function to use in SampleUtil_Print * ******************************************************************************/ int SampleUtil_Initialize(print_string print_function) { if (initialize_init) { ithread_mutexattr_t attr; ithread_mutexattr_init(&attr); ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP); ithread_mutex_init(&display_mutex, &attr); ithread_mutexattr_destroy(&attr); /* To shut up valgrind mutex warning. */ ithread_mutex_lock(&display_mutex); gPrintFun = print_function; ithread_mutex_unlock(&display_mutex); initialize_init = 0; } else { SampleUtil_Print("***** SampleUtil_Initialize was called multiple times!\n"); abort(); } return UPNP_E_SUCCESS; } /******************************************************************************* * SampleUtil_RegisterUpdateFunction * * Description: * * Parameters: * ******************************************************************************/ int SampleUtil_RegisterUpdateFunction(state_update update_function) { if (initialize_register) { gStateUpdateFun = update_function; initialize_register = 0; } return UPNP_E_SUCCESS; } /******************************************************************************* * SampleUtil_Finish * * Description: * Releases Resources held by sample util. * * Parameters: * ******************************************************************************/ int SampleUtil_Finish() { ithread_mutex_destroy(&display_mutex); gPrintFun = NULL; gStateUpdateFun = NULL; initialize_init = 1; initialize_register = 1; return UPNP_E_SUCCESS; } /******************************************************************************* * SampleUtil_GetElementValue * * Description: * Given a DOM node such as 11, this routine * extracts the value (e.g., 11) from the node and returns it as * a string. The string must be freed by the caller using * free. * * Parameters: * node -- The DOM node from which to extract the value * ******************************************************************************/ char *SampleUtil_GetElementValue(IN IXML_Element *element) { IXML_Node *child = ixmlNode_getFirstChild((IXML_Node *)element); char *temp = NULL; if (child != 0 && ixmlNode_getNodeType(child) == eTEXT_NODE) { temp = strdup(ixmlNode_getNodeValue(child)); } return temp; } /******************************************************************************* * SampleUtil_GetFirstServiceList * * Description: * Given a DOM node representing a UPnP Device Description Document, * this routine parses the document and finds the first service list * (i.e., the service list for the root device). The service list * is returned as a DOM node list. * * Parameters: * node -- The DOM node from which to extract the service list * ******************************************************************************/ IXML_NodeList *SampleUtil_GetFirstServiceList(IN IXML_Document *doc) { IXML_NodeList *ServiceList = NULL; IXML_NodeList *servlistnodelist = NULL; IXML_Node *servlistnode = NULL; servlistnodelist = ixmlDocument_getElementsByTagName( doc, "serviceList" ); if (servlistnodelist && ixmlNodeList_length(servlistnodelist)) { /* we only care about the first service list, from the root * device */ servlistnode = ixmlNodeList_item(servlistnodelist, 0); /* create as list of DOM nodes */ ServiceList = ixmlElement_getElementsByTagName( (IXML_Element *)servlistnode, "service"); } if (servlistnodelist) { ixmlNodeList_free(servlistnodelist); } return ServiceList; } /* * Obtain the service list * n == 0 the first * n == 1 the next in the device list, etc.. * */ IXML_NodeList *SampleUtil_GetNthServiceList(IN IXML_Document *doc , int n) { IXML_NodeList *ServiceList = NULL; IXML_NodeList *servlistnodelist = NULL; IXML_Node *servlistnode = NULL; /* * ixmlDocument_getElementsByTagName() * Returns a NodeList of all Elements that match the given * tag name in the order in which they were encountered in a preorder * traversal of the Document tree. * * return (NodeList*) A pointer to a NodeList containing the * matching items or NULL on an error. */ SampleUtil_Print("SampleUtil_GetNthServiceList called : n = %d\n", n); servlistnodelist = ixmlDocument_getElementsByTagName(doc, "serviceList"); if (servlistnodelist && ixmlNodeList_length(servlistnodelist) && n < ixmlNodeList_length(servlistnodelist)) { /* For the first service list (from the root device), * we pass 0 */ /*servlistnode = ixmlNodeList_item( servlistnodelist, 0 );*/ /* Retrieves a Node from a NodeList} specified by a * numerical index. * * return (Node*) A pointer to a Node or NULL if there was an * error. */ servlistnode = ixmlNodeList_item(servlistnodelist, n); assert(servlistnode != 0); /* create as list of DOM nodes */ ServiceList = ixmlElement_getElementsByTagName( (IXML_Element *)servlistnode, "service"); } if (servlistnodelist) { ixmlNodeList_free(servlistnodelist); } return ServiceList; } /******************************************************************************* * SampleUtil_GetFirstDocumentItem * * Description: * Given a document node, this routine searches for the first element * named by the input string item, and returns its value as a string. * String must be freed by caller using free. * Parameters: * doc -- The DOM document from which to extract the value * item -- The item to search for * ******************************************************************************/ char *SampleUtil_GetFirstDocumentItem( IN IXML_Document *doc, IN const char *item) { IXML_NodeList *nodeList = NULL; IXML_Node *textNode = NULL; IXML_Node *tmpNode = NULL; char *ret = NULL; nodeList = ixmlDocument_getElementsByTagName(doc, (char *)item); if (nodeList) { tmpNode = ixmlNodeList_item(nodeList, 0); if (tmpNode) { textNode = ixmlNode_getFirstChild(tmpNode); if (!textNode) { SampleUtil_Print("sample_util.c: (bug) " "ixmlNode_getFirstChild(tmpNode) " "returned NULL\n"); ret = strdup(""); goto epilogue; } if (!ixmlNode_getNodeValue(textNode)) { SampleUtil_Print("ixmlNode_getNodeValue " "returned NULL\n"); ret = strdup(""); goto epilogue; } else { ret = strdup(ixmlNode_getNodeValue(textNode)); } } else { SampleUtil_Print("ixmlNode_getFirstChild(tmpNode) " "returned NULL\n"); goto epilogue; } } else { SampleUtil_Print("Error finding %s in XML Node\n", item); goto epilogue; } epilogue: if (nodeList) { ixmlNodeList_free(nodeList); } return ret; } /******************************************************************************* * SampleUtil_GetFirstElementItem * * Description: * Given a DOM element, this routine searches for the first element * named by the input string item, and returns its value as a string. * The string must be freed using free. * Parameters: * node -- The DOM element from which to extract the value * item -- The item to search for * ******************************************************************************/ char *SampleUtil_GetFirstElementItem( IN IXML_Element *element, IN const char *item) { IXML_NodeList *nodeList = NULL; IXML_Node *textNode = NULL; IXML_Node *tmpNode = NULL; char *ret = NULL; nodeList = ixmlElement_getElementsByTagName(element, (char *)item); if (nodeList == NULL) { SampleUtil_Print( "Error finding %s in XML Node\n", item); return NULL; } tmpNode = ixmlNodeList_item(nodeList, 0); if (tmpNode) { SampleUtil_Print("Error finding %s value in XML Node\n", item); ixmlNodeList_free(nodeList); return NULL; } textNode = ixmlNode_getFirstChild(tmpNode); ret = strdup(ixmlNode_getNodeValue(textNode)); if (!ret) { SampleUtil_Print("Error allocating memory for %s in XML Node\n", item); ixmlNodeList_free(nodeList); return NULL; } ixmlNodeList_free(nodeList); return ret; } /******************************************************************************* * SampleUtil_PrintEventType * * Description: * Prints a callback event type as a string. * * Parameters: * S -- The callback event * ******************************************************************************/ void SampleUtil_PrintEventType(IN Upnp_EventType S) { switch (S) { /* Discovery */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: SampleUtil_Print("UPNP_DISCOVERY_ADVERTISEMENT_ALIVE\n"); break; case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: SampleUtil_Print("UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE\n"); break; case UPNP_DISCOVERY_SEARCH_RESULT: SampleUtil_Print( "UPNP_DISCOVERY_SEARCH_RESULT\n"); break; case UPNP_DISCOVERY_SEARCH_TIMEOUT: SampleUtil_Print( "UPNP_DISCOVERY_SEARCH_TIMEOUT\n"); break; /* SOAP */ case UPNP_CONTROL_ACTION_REQUEST: SampleUtil_Print("UPNP_CONTROL_ACTION_REQUEST\n"); break; case UPNP_CONTROL_ACTION_COMPLETE: SampleUtil_Print("UPNP_CONTROL_ACTION_COMPLETE\n"); break; case UPNP_CONTROL_GET_VAR_REQUEST: SampleUtil_Print("UPNP_CONTROL_GET_VAR_REQUEST\n"); break; case UPNP_CONTROL_GET_VAR_COMPLETE: SampleUtil_Print("UPNP_CONTROL_GET_VAR_COMPLETE\n"); break; /* GENA */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: SampleUtil_Print("UPNP_EVENT_SUBSCRIPTION_REQUEST\n"); break; case UPNP_EVENT_RECEIVED: SampleUtil_Print("UPNP_EVENT_RECEIVED\n"); break; case UPNP_EVENT_RENEWAL_COMPLETE: SampleUtil_Print("UPNP_EVENT_RENEWAL_COMPLETE\n"); break; case UPNP_EVENT_SUBSCRIBE_COMPLETE: SampleUtil_Print("UPNP_EVENT_SUBSCRIBE_COMPLETE\n"); break; case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: SampleUtil_Print("UPNP_EVENT_UNSUBSCRIBE_COMPLETE\n"); break; case UPNP_EVENT_AUTORENEWAL_FAILED: SampleUtil_Print("UPNP_EVENT_AUTORENEWAL_FAILED\n"); break; case UPNP_EVENT_SUBSCRIPTION_EXPIRED: SampleUtil_Print("UPNP_EVENT_SUBSCRIPTION_EXPIRED\n"); break; } } /******************************************************************************* * SampleUtil_PrintEvent * * Description: * Prints callback event structure details. * * Parameters: * EventType -- The type of callback event * Event -- The callback event structure * ******************************************************************************/ int SampleUtil_PrintEvent(IN Upnp_EventType EventType, IN void *Event) { ithread_mutex_lock(&display_mutex); SampleUtil_Print( "======================================================================\n" "----------------------------------------------------------------------\n"); SampleUtil_PrintEventType(EventType); switch (EventType) { /* SSDP */ case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE: case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: case UPNP_DISCOVERY_SEARCH_RESULT: { UpnpDiscovery *d_event = (UpnpDiscovery *)Event; SampleUtil_Print( "ErrCode = %d\n" "Expires = %d\n" "DeviceId = %s\n" "DeviceType = %s\n" "ServiceType = %s\n" "ServiceVer = %s\n" "Location = %s\n" "OS = %s\n" "Date = %s\n" "Ext = %s\n", UpnpDiscovery_get_ErrCode(d_event), UpnpDiscovery_get_Expires(d_event), UpnpString_get_String(UpnpDiscovery_get_DeviceID(d_event)), UpnpString_get_String(UpnpDiscovery_get_DeviceType(d_event)), UpnpString_get_String(UpnpDiscovery_get_ServiceType(d_event)), UpnpString_get_String(UpnpDiscovery_get_ServiceVer(d_event)), UpnpString_get_String(UpnpDiscovery_get_Location(d_event)), UpnpString_get_String(UpnpDiscovery_get_Os(d_event)), UpnpString_get_String(UpnpDiscovery_get_Date(d_event)), UpnpString_get_String(UpnpDiscovery_get_Ext(d_event))); break; } case UPNP_DISCOVERY_SEARCH_TIMEOUT: /* Nothing to print out here */ break; /* SOAP */ case UPNP_CONTROL_ACTION_REQUEST: { UpnpActionRequest *a_event = (UpnpActionRequest *)Event; IXML_Document *actionRequestDoc = NULL; IXML_Document *actionResultDoc = NULL; char *xmlbuff = NULL; SampleUtil_Print( "ErrCode = %d\n" "ErrStr = %s\n" "ActionName = %s\n" "UDN = %s\n" "ServiceID = %s\n", UpnpActionRequest_get_ErrCode(a_event), UpnpString_get_String(UpnpActionRequest_get_ErrStr(a_event)), UpnpString_get_String(UpnpActionRequest_get_ActionName(a_event)), UpnpString_get_String(UpnpActionRequest_get_DevUDN(a_event)), UpnpString_get_String(UpnpActionRequest_get_ServiceID(a_event))); actionRequestDoc = UpnpActionRequest_get_ActionRequest(a_event); if (actionRequestDoc) { xmlbuff = ixmlPrintNode((IXML_Node *)actionRequestDoc); if (xmlbuff) { SampleUtil_Print("ActRequest = %s\n", xmlbuff); ixmlFreeDOMString(xmlbuff); } xmlbuff = NULL; } else { SampleUtil_Print("ActRequest = (null)\n"); } actionResultDoc = UpnpActionRequest_get_ActionResult(a_event); if (actionResultDoc) { xmlbuff = ixmlPrintNode((IXML_Node *)actionResultDoc); if (xmlbuff) { SampleUtil_Print("ActResult = %s\n", xmlbuff); ixmlFreeDOMString(xmlbuff); } xmlbuff = NULL; } else { SampleUtil_Print("ActResult = (null)\n"); } break; } case UPNP_CONTROL_ACTION_COMPLETE: { UpnpActionComplete *a_event = (UpnpActionComplete *)Event; char *xmlbuff = NULL; int errCode = UpnpActionComplete_get_ErrCode(a_event); const char *ctrlURL = UpnpString_get_String( UpnpActionComplete_get_CtrlUrl(a_event)); IXML_Document *actionRequest = UpnpActionComplete_get_ActionRequest(a_event); IXML_Document *actionResult = UpnpActionComplete_get_ActionResult(a_event); SampleUtil_Print( "ErrCode = %d\n" "CtrlUrl = %s\n", errCode, ctrlURL); if (actionRequest) { xmlbuff = ixmlPrintNode((IXML_Node *)actionRequest); if (xmlbuff) { SampleUtil_Print("ActRequest = %s\n", xmlbuff); ixmlFreeDOMString(xmlbuff); } xmlbuff = NULL; } else { SampleUtil_Print("ActRequest = (null)\n"); } if (actionResult) { xmlbuff = ixmlPrintNode((IXML_Node *)actionResult); if (xmlbuff) { SampleUtil_Print("ActResult = %s\n", xmlbuff); ixmlFreeDOMString(xmlbuff); } xmlbuff = NULL; } else { SampleUtil_Print("ActResult = (null)\n"); } break; } case UPNP_CONTROL_GET_VAR_REQUEST: { UpnpStateVarRequest *sv_event = (UpnpStateVarRequest *)Event; SampleUtil_Print( "ErrCode = %d\n" "ErrStr = %s\n" "UDN = %s\n" "ServiceID = %s\n" "StateVarName= %s\n" "CurrentVal = %s\n", UpnpStateVarRequest_get_ErrCode(sv_event), UpnpString_get_String(UpnpStateVarRequest_get_ErrStr(sv_event)), UpnpString_get_String(UpnpStateVarRequest_get_DevUDN(sv_event)), UpnpString_get_String(UpnpStateVarRequest_get_ServiceID(sv_event)), UpnpString_get_String(UpnpStateVarRequest_get_StateVarName(sv_event)), UpnpStateVarRequest_get_CurrentVal(sv_event)); break; } case UPNP_CONTROL_GET_VAR_COMPLETE: { UpnpStateVarComplete *sv_event = (UpnpStateVarComplete *)Event; SampleUtil_Print( "ErrCode = %d\n" "CtrlUrl = %s\n" "StateVarName= %s\n" "CurrentVal = %s\n", UpnpStateVarComplete_get_ErrCode(sv_event), UpnpString_get_String(UpnpStateVarComplete_get_CtrlUrl(sv_event)), UpnpString_get_String(UpnpStateVarComplete_get_StateVarName(sv_event)), UpnpStateVarComplete_get_CurrentVal(sv_event)); break; } /* GENA */ case UPNP_EVENT_SUBSCRIPTION_REQUEST: { UpnpSubscriptionRequest *sr_event = (UpnpSubscriptionRequest *)Event; SampleUtil_Print( "ServiceID = %s\n" "UDN = %s\n" "SID = %s\n", UpnpString_get_String(UpnpSubscriptionRequest_get_ServiceId(sr_event)), UpnpString_get_String(UpnpSubscriptionRequest_get_UDN(sr_event)), UpnpString_get_String(UpnpSubscriptionRequest_get_SID(sr_event))); break; } case UPNP_EVENT_RECEIVED: { UpnpEvent *e_event = (UpnpEvent *)Event; char *xmlbuff = NULL; xmlbuff = ixmlPrintNode( (IXML_Node *)UpnpEvent_get_ChangedVariables(e_event)); SampleUtil_Print( "SID = %s\n" "EventKey = %d\n" "ChangedVars = %s\n", UpnpString_get_String(UpnpEvent_get_SID(e_event)), UpnpEvent_get_EventKey(e_event), xmlbuff); ixmlFreeDOMString(xmlbuff); break; } case UPNP_EVENT_RENEWAL_COMPLETE: { UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event; SampleUtil_Print( "SID = %s\n" "ErrCode = %d\n" "TimeOut = %d\n", UpnpString_get_String(UpnpEventSubscribe_get_SID(es_event)), UpnpEventSubscribe_get_ErrCode(es_event), UpnpEventSubscribe_get_TimeOut(es_event)); break; } case UPNP_EVENT_SUBSCRIBE_COMPLETE: case UPNP_EVENT_UNSUBSCRIBE_COMPLETE: { UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event; SampleUtil_Print( "SID = %s\n" "ErrCode = %d\n" "PublisherURL= %s\n" "TimeOut = %d\n", UpnpString_get_String(UpnpEventSubscribe_get_SID(es_event)), UpnpEventSubscribe_get_ErrCode(es_event), UpnpString_get_String(UpnpEventSubscribe_get_PublisherUrl(es_event)), UpnpEventSubscribe_get_TimeOut(es_event)); break; } case UPNP_EVENT_AUTORENEWAL_FAILED: case UPNP_EVENT_SUBSCRIPTION_EXPIRED: { UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event; SampleUtil_Print( "SID = %s\n" "ErrCode = %d\n" "PublisherURL= %s\n" "TimeOut = %d\n", UpnpString_get_String(UpnpEventSubscribe_get_SID(es_event)), UpnpEventSubscribe_get_ErrCode(es_event), UpnpString_get_String(UpnpEventSubscribe_get_PublisherUrl(es_event)), UpnpEventSubscribe_get_TimeOut(es_event)); break; } } SampleUtil_Print( "----------------------------------------------------------------------\n" "======================================================================\n" "\n\n\n"); ithread_mutex_unlock(&display_mutex); return 0; } /******************************************************************************* * SampleUtil_FindAndParseService * * Description: * This routine finds the first occurance of a service in a DOM representation * of a description document and parses it. * * Parameters: * DescDoc -- The DOM description document * location -- The location of the description document * serviceSearchType -- The type of service to search for * serviceId -- OUT -- The service ID * eventURL -- OUT -- The event URL for the service * controlURL -- OUT -- The control URL for the service * ******************************************************************************/ int SampleUtil_FindAndParseService( IN IXML_Document *DescDoc, IN const char *location, IN char *serviceType, OUT char **serviceId, OUT char **eventURL, OUT char **controlURL) { int i; int length; int found = 0; int ret; int sindex = 0; char *tempServiceType = NULL; char *baseURL = NULL; const char *base = NULL; char *relcontrolURL = NULL; char *releventURL = NULL; IXML_NodeList *serviceList = NULL; IXML_Element *service = NULL; baseURL = SampleUtil_GetFirstDocumentItem(DescDoc, "URLBase"); if (baseURL) { base = baseURL; } else { base = location; } /* Top level */ for (sindex = 0; (serviceList = SampleUtil_GetNthServiceList(DescDoc , sindex)) != NULL; sindex ++) { tempServiceType = NULL; relcontrolURL = NULL; releventURL = NULL; service = NULL; /* serviceList = SampleUtil_GetFirstServiceList( DescDoc ); */ length = ixmlNodeList_length(serviceList); for (i = 0; i < length; i++) { service = (IXML_Element *)ixmlNodeList_item(serviceList, i); tempServiceType = SampleUtil_GetFirstElementItem( (IXML_Element *)service, "serviceType"); if (strcmp(tempServiceType, serviceType) == 0) { SampleUtil_Print("Found service: %s\n", serviceType); *serviceId = SampleUtil_GetFirstElementItem(service, "serviceId"); SampleUtil_Print("serviceId: %s\n", *serviceId); relcontrolURL = SampleUtil_GetFirstElementItem(service, "controlURL"); releventURL = SampleUtil_GetFirstElementItem(service, "eventSubURL"); *controlURL = malloc(strlen(base) + strlen(relcontrolURL)+1); if (*controlURL) { ret = UpnpResolveURL(base, relcontrolURL, *controlURL); if (ret != UPNP_E_SUCCESS) { SampleUtil_Print("Error generating controlURL from %s + %s\n", base, relcontrolURL); } } *eventURL = malloc(strlen(base) + strlen(releventURL)+1); if (*eventURL) { ret = UpnpResolveURL(base, releventURL, *eventURL); if (ret != UPNP_E_SUCCESS) { SampleUtil_Print("Error generating eventURL from %s + %s\n", base, releventURL); } } free(relcontrolURL); free(releventURL); relcontrolURL = NULL; releventURL = NULL; found = 1; break; } free(tempServiceType); tempServiceType = NULL; } free(tempServiceType); tempServiceType = NULL; if (serviceList) { ixmlNodeList_free(serviceList); } serviceList = NULL; } free(baseURL); return found; } /******************************************************************************* * SampleUtil_Print * * Description: * Provides platform-specific print functionality. This function should be * called when you want to print content suitable for console output (i.e., * in a large text box or on a screen). If your device/operating system is * not supported here, you should add a port. * * Parameters: * Same as printf() * ******************************************************************************/ int SampleUtil_Print(char *fmt, ...) { #define MAX_BUF (8 * 1024) va_list ap; static char buf[MAX_BUF]; int rc; /* Protect both the display and the static buffer with the mutex */ ithread_mutex_lock(&display_mutex); va_start(ap, fmt); rc = vsnprintf(buf, MAX_BUF, fmt, ap); va_end(ap); if (gPrintFun) { gPrintFun(buf); } ithread_mutex_unlock(&display_mutex); return rc; } /******************************************************************************* * SampleUtil_StateUpdate * * Description: * * Parameters: * ******************************************************************************/ void SampleUtil_StateUpdate(const char *varName, const char *varValue, const char *UDN, eventType type) { /* TBD: Add mutex here? */ if (gStateUpdateFun) { gStateUpdateFun(varName, varValue, UDN, type); } }