1 /*******************************************************************************
2 *
3 * Copyright (c) 2000-2003 Intel Corporation
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * - Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * - Neither name of Intel Corporation nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 ******************************************************************************/
31
32 /*!
33 * \addtogroup UpnpSamples
34 *
35 * @{
36 *
37 * \name Control Point Sample Module
38 *
39 * @{
40 *
41 * \file
42 */
43
44 #include "tv_ctrlpt.h"
45
46 #include "upnp.h"
47
48 /*!
49 * Mutex for protecting the global device list in a multi-threaded,
50 * asynchronous environment. All functions should lock this mutex before
51 * reading or writing the device list.
52 */
53 ithread_mutex_t DeviceListMutex;
54
55 UpnpClient_Handle ctrlpt_handle = -1;
56
57 /*! Device type for tv device. */
58 const char TvDeviceType[] = "urn:schemas-upnp-org:device:tvdevice:1";
59
60 /*! Service names.*/
61 const char *TvServiceName[] = {"Control", "Picture"};
62
63 /*!
64 Global arrays for storing variable names and counts for
65 TvControl and TvPicture services
66 */
67 const char *TvVarName[TV_SERVICE_SERVCOUNT][TV_MAXVARS] = {
68 {"Power", "Channel", "Volume", ""},
69 {"Color", "Tint", "Contrast", "Brightness"}};
70 char TvVarCount[TV_SERVICE_SERVCOUNT] = {
71 TV_CONTROL_VARCOUNT, TV_PICTURE_VARCOUNT};
72
73 /*!
74 Timeout to request during subscriptions
75 */
76 int default_timeout = 1801;
77
78 /*!
79 The first node in the global device list, or NULL if empty
80 */
81 struct TvDeviceNode *GlobalDeviceList = NULL;
82
83 /********************************************************************************
84 * TvCtrlPointDeleteNode
85 *
86 * Description:
87 * Delete a device node from the global device list. Note that this
88 * function is NOT thread safe, and should be called from another
89 * function that has already locked the global device list.
90 *
91 * Parameters:
92 * node -- The device node
93 *
94 ********************************************************************************/
TvCtrlPointDeleteNode(struct TvDeviceNode * node)95 int TvCtrlPointDeleteNode(struct TvDeviceNode *node)
96 {
97 int rc, service, var;
98
99 if (NULL == node) {
100 SampleUtil_Print(
101 "ERROR: TvCtrlPointDeleteNode: Node is empty\n");
102 return TV_ERROR;
103 }
104
105 for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) {
106 /*
107 If we have a valid control SID, then unsubscribe
108 */
109 if (strcmp(node->device.TvService[service].SID, "") != 0) {
110 rc = UpnpUnSubscribe(ctrlpt_handle,
111 node->device.TvService[service].SID);
112 if (UPNP_E_SUCCESS == rc) {
113 SampleUtil_Print("Unsubscribed from Tv %s "
114 "EventURL with SID=%s\n",
115 TvServiceName[service],
116 node->device.TvService[service].SID);
117 } else {
118 SampleUtil_Print("Error unsubscribing to Tv %s "
119 "EventURL -- %d\n",
120 TvServiceName[service],
121 rc);
122 }
123 }
124
125 for (var = 0; var < TvVarCount[service]; var++) {
126 if (node->device.TvService[service]
127 .VariableStrVal[var]) {
128 free(node->device.TvService[service]
129 .VariableStrVal[var]);
130 }
131 }
132 }
133
134 /*Notify New Device Added */
135 SampleUtil_StateUpdate(NULL, NULL, node->device.UDN, DEVICE_REMOVED);
136 free(node);
137 node = NULL;
138
139 return TV_SUCCESS;
140 }
141
142 /********************************************************************************
143 * TvCtrlPointRemoveDevice
144 *
145 * Description:
146 * Remove a device from the global device list.
147 *
148 * Parameters:
149 * UDN -- The Unique Device Name for the device to remove
150 *
151 ********************************************************************************/
TvCtrlPointRemoveDevice(const char * UDN)152 int TvCtrlPointRemoveDevice(const char *UDN)
153 {
154 struct TvDeviceNode *curdevnode;
155 struct TvDeviceNode *prevdevnode;
156
157 ithread_mutex_lock(&DeviceListMutex);
158
159 curdevnode = GlobalDeviceList;
160 if (!curdevnode) {
161 SampleUtil_Print("WARNING: TvCtrlPointRemoveDevice: Device "
162 "list empty\n");
163 } else {
164 if (0 == strcmp(curdevnode->device.UDN, UDN)) {
165 GlobalDeviceList = curdevnode->next;
166 TvCtrlPointDeleteNode(curdevnode);
167 } else {
168 prevdevnode = curdevnode;
169 curdevnode = curdevnode->next;
170 while (curdevnode) {
171 if (strcmp(curdevnode->device.UDN, UDN) == 0) {
172 prevdevnode->next = curdevnode->next;
173 TvCtrlPointDeleteNode(curdevnode);
174 break;
175 }
176 prevdevnode = curdevnode;
177 curdevnode = curdevnode->next;
178 }
179 }
180 }
181
182 ithread_mutex_unlock(&DeviceListMutex);
183
184 return TV_SUCCESS;
185 }
186
187 /********************************************************************************
188 * TvCtrlPointRemoveAll
189 *
190 * Description:
191 * Remove all devices from the global device list.
192 *
193 * Parameters:
194 * None
195 *
196 ********************************************************************************/
TvCtrlPointRemoveAll(void)197 int TvCtrlPointRemoveAll(void)
198 {
199 struct TvDeviceNode *curdevnode, *next;
200
201 ithread_mutex_lock(&DeviceListMutex);
202
203 curdevnode = GlobalDeviceList;
204 GlobalDeviceList = NULL;
205
206 while (curdevnode) {
207 next = curdevnode->next;
208 TvCtrlPointDeleteNode(curdevnode);
209 curdevnode = next;
210 }
211
212 ithread_mutex_unlock(&DeviceListMutex);
213
214 return TV_SUCCESS;
215 }
216
217 /********************************************************************************
218 * TvCtrlPointRefresh
219 *
220 * Description:
221 * Clear the current global device list and issue new search
222 * requests to build it up again from scratch.
223 *
224 * Parameters:
225 * None
226 *
227 ********************************************************************************/
TvCtrlPointRefresh(void)228 int TvCtrlPointRefresh(void)
229 {
230 int rc;
231
232 TvCtrlPointRemoveAll();
233 /* Search for all devices of type tvdevice version 1,
234 * waiting for up to 5 seconds for the response */
235 rc = UpnpSearchAsync(ctrlpt_handle, 5, TvDeviceType, NULL);
236 if (UPNP_E_SUCCESS != rc) {
237 SampleUtil_Print("Error sending search request%d\n", rc);
238
239 return TV_ERROR;
240 }
241
242 return TV_SUCCESS;
243 }
244
245 /********************************************************************************
246 * TvCtrlPointGetVar
247 *
248 * Description:
249 * Send a GetVar request to the specified service of a device.
250 *
251 * Parameters:
252 * service -- The service
253 * devnum -- The number of the device (order in the list,
254 * starting with 1)
255 * varname -- The name of the variable to request.
256 *
257 ********************************************************************************/
TvCtrlPointGetVar(int service,int devnum,const char * varname)258 int TvCtrlPointGetVar(int service, int devnum, const char *varname)
259 {
260 struct TvDeviceNode *devnode;
261 int rc;
262
263 ithread_mutex_lock(&DeviceListMutex);
264
265 rc = TvCtrlPointGetDevice(devnum, &devnode);
266
267 if (TV_SUCCESS == rc) {
268 rc = UpnpGetServiceVarStatusAsync(ctrlpt_handle,
269 devnode->device.TvService[service].ControlURL,
270 varname,
271 TvCtrlPointCallbackEventHandler,
272 NULL);
273 if (rc != UPNP_E_SUCCESS) {
274 SampleUtil_Print(
275 "Error in UpnpGetServiceVarStatusAsync -- %d\n",
276 rc);
277 rc = TV_ERROR;
278 }
279 }
280
281 ithread_mutex_unlock(&DeviceListMutex);
282
283 return rc;
284 }
285
TvCtrlPointGetPower(int devnum)286 int TvCtrlPointGetPower(int devnum)
287 {
288 return TvCtrlPointGetVar(TV_SERVICE_CONTROL, devnum, "Power");
289 }
290
TvCtrlPointGetChannel(int devnum)291 int TvCtrlPointGetChannel(int devnum)
292 {
293 return TvCtrlPointGetVar(TV_SERVICE_CONTROL, devnum, "Channel");
294 }
295
TvCtrlPointGetVolume(int devnum)296 int TvCtrlPointGetVolume(int devnum)
297 {
298 return TvCtrlPointGetVar(TV_SERVICE_CONTROL, devnum, "Volume");
299 }
300
TvCtrlPointGetColor(int devnum)301 int TvCtrlPointGetColor(int devnum)
302 {
303 return TvCtrlPointGetVar(TV_SERVICE_PICTURE, devnum, "Color");
304 }
305
TvCtrlPointGetTint(int devnum)306 int TvCtrlPointGetTint(int devnum)
307 {
308 return TvCtrlPointGetVar(TV_SERVICE_PICTURE, devnum, "Tint");
309 }
310
TvCtrlPointGetContrast(int devnum)311 int TvCtrlPointGetContrast(int devnum)
312 {
313 return TvCtrlPointGetVar(TV_SERVICE_PICTURE, devnum, "Contrast");
314 }
315
TvCtrlPointGetBrightness(int devnum)316 int TvCtrlPointGetBrightness(int devnum)
317 {
318 return TvCtrlPointGetVar(TV_SERVICE_PICTURE, devnum, "Brightness");
319 }
320
321 /********************************************************************************
322 * TvCtrlPointSendAction
323 *
324 * Description:
325 * Send an Action request to the specified service of a device.
326 *
327 * Parameters:
328 * service -- The service
329 * devnum -- The number of the device (order in the list,
330 * starting with 1)
331 * actionname -- The name of the action.
332 * param_name -- An array of parameter names
333 * param_val -- The corresponding parameter values
334 * param_count -- The number of parameters
335 *
336 ********************************************************************************/
TvCtrlPointSendAction(int service,int devnum,const char * actionname,const char ** param_name,char ** param_val,int param_count)337 int TvCtrlPointSendAction(int service,
338 int devnum,
339 const char *actionname,
340 const char **param_name,
341 char **param_val,
342 int param_count)
343 {
344 struct TvDeviceNode *devnode;
345 IXML_Document *actionNode = NULL;
346 int rc = TV_SUCCESS;
347 int param;
348
349 ithread_mutex_lock(&DeviceListMutex);
350
351 rc = TvCtrlPointGetDevice(devnum, &devnode);
352 if (TV_SUCCESS == rc) {
353 if (0 == param_count) {
354 actionNode = UpnpMakeAction(
355 actionname, TvServiceType[service], 0, NULL);
356 } else {
357 for (param = 0; param < param_count; param++) {
358 if (UpnpAddToAction(&actionNode,
359 actionname,
360 TvServiceType[service],
361 param_name[param],
362 param_val[param]) !=
363 UPNP_E_SUCCESS) {
364 SampleUtil_Print(
365 "ERROR: TvCtrlPointSendAction: "
366 "Trying to add action param\n");
367 /*return -1; // TBD - BAD! leaves mutex
368 * locked */
369 }
370 }
371 }
372
373 rc = UpnpSendActionAsync(ctrlpt_handle,
374 devnode->device.TvService[service].ControlURL,
375 TvServiceType[service],
376 NULL,
377 actionNode,
378 TvCtrlPointCallbackEventHandler,
379 NULL);
380
381 if (rc != UPNP_E_SUCCESS) {
382 SampleUtil_Print(
383 "Error in UpnpSendActionAsync -- %d\n", rc);
384 rc = TV_ERROR;
385 }
386 }
387
388 ithread_mutex_unlock(&DeviceListMutex);
389
390 if (actionNode)
391 ixmlDocument_free(actionNode);
392
393 return rc;
394 }
395
396 /********************************************************************************
397 * TvCtrlPointSendActionNumericArg
398 *
399 * Description:Send an action with one argument to a device in the global device
400 *list.
401 *
402 * Parameters:
403 * devnum -- The number of the device (order in the list, starting with 1)
404 * service -- TV_SERVICE_CONTROL or TV_SERVICE_PICTURE
405 * actionName -- The device action, i.e., "SetChannel"
406 * paramName -- The name of the parameter that is being passed
407 * paramValue -- Actual value of the parameter being passed
408 *
409 ********************************************************************************/
TvCtrlPointSendActionNumericArg(int devnum,int service,const char * actionName,const char * paramName,int paramValue)410 int TvCtrlPointSendActionNumericArg(int devnum,
411 int service,
412 const char *actionName,
413 const char *paramName,
414 int paramValue)
415 {
416 char param_val_a[50];
417 char *param_val = param_val_a;
418
419 sprintf(param_val_a, "%d", paramValue);
420 return TvCtrlPointSendAction(
421 service, devnum, actionName, ¶mName, ¶m_val, 1);
422 }
423
TvCtrlPointSendPowerOn(int devnum)424 int TvCtrlPointSendPowerOn(int devnum)
425 {
426 return TvCtrlPointSendAction(
427 TV_SERVICE_CONTROL, devnum, "PowerOn", NULL, NULL, 0);
428 }
429
TvCtrlPointSendPowerOff(int devnum)430 int TvCtrlPointSendPowerOff(int devnum)
431 {
432 return TvCtrlPointSendAction(
433 TV_SERVICE_CONTROL, devnum, "PowerOff", NULL, NULL, 0);
434 }
435
TvCtrlPointSendSetChannel(int devnum,int channel)436 int TvCtrlPointSendSetChannel(int devnum, int channel)
437 {
438 return TvCtrlPointSendActionNumericArg(
439 devnum, TV_SERVICE_CONTROL, "SetChannel", "Channel", channel);
440 }
441
TvCtrlPointSendSetVolume(int devnum,int volume)442 int TvCtrlPointSendSetVolume(int devnum, int volume)
443 {
444 return TvCtrlPointSendActionNumericArg(
445 devnum, TV_SERVICE_CONTROL, "SetVolume", "Volume", volume);
446 }
447
TvCtrlPointSendSetColor(int devnum,int color)448 int TvCtrlPointSendSetColor(int devnum, int color)
449 {
450 return TvCtrlPointSendActionNumericArg(
451 devnum, TV_SERVICE_PICTURE, "SetColor", "Color", color);
452 }
453
TvCtrlPointSendSetTint(int devnum,int tint)454 int TvCtrlPointSendSetTint(int devnum, int tint)
455 {
456 return TvCtrlPointSendActionNumericArg(
457 devnum, TV_SERVICE_PICTURE, "SetTint", "Tint", tint);
458 }
459
TvCtrlPointSendSetContrast(int devnum,int contrast)460 int TvCtrlPointSendSetContrast(int devnum, int contrast)
461 {
462 return TvCtrlPointSendActionNumericArg(devnum,
463 TV_SERVICE_PICTURE,
464 "SetContrast",
465 "Contrast",
466 contrast);
467 }
468
TvCtrlPointSendSetBrightness(int devnum,int brightness)469 int TvCtrlPointSendSetBrightness(int devnum, int brightness)
470 {
471 return TvCtrlPointSendActionNumericArg(devnum,
472 TV_SERVICE_PICTURE,
473 "SetBrightness",
474 "Brightness",
475 brightness);
476 }
477
478 /********************************************************************************
479 * TvCtrlPointGetDevice
480 *
481 * Description:
482 * Given a list number, returns the pointer to the device
483 * node at that position in the global device list. Note
484 * that this function is not thread safe. It must be called
485 * from a function that has locked the global device list.
486 *
487 * Parameters:
488 * devnum -- The number of the device (order in the list,
489 * starting with 1)
490 * devnode -- The output device node pointer
491 *
492 ********************************************************************************/
TvCtrlPointGetDevice(int devnum,struct TvDeviceNode ** devnode)493 int TvCtrlPointGetDevice(int devnum, struct TvDeviceNode **devnode)
494 {
495 int count = devnum;
496 struct TvDeviceNode *tmpdevnode = NULL;
497
498 if (count)
499 tmpdevnode = GlobalDeviceList;
500 while (--count && tmpdevnode) {
501 tmpdevnode = tmpdevnode->next;
502 }
503 if (!tmpdevnode) {
504 SampleUtil_Print(
505 "Error finding TvDevice number -- %d\n", devnum);
506 return TV_ERROR;
507 }
508 *devnode = tmpdevnode;
509
510 return TV_SUCCESS;
511 }
512
513 /********************************************************************************
514 * TvCtrlPointPrintList
515 *
516 * Description:
517 * Print the universal device names for each device in the global device
518 *list
519 *
520 * Parameters:
521 * None
522 *
523 ********************************************************************************/
TvCtrlPointPrintList()524 int TvCtrlPointPrintList()
525 {
526 struct TvDeviceNode *tmpdevnode;
527 int i = 0;
528
529 ithread_mutex_lock(&DeviceListMutex);
530
531 SampleUtil_Print("TvCtrlPointPrintList:\n");
532 tmpdevnode = GlobalDeviceList;
533 while (tmpdevnode) {
534 SampleUtil_Print(" %3d -- %s\n", ++i, tmpdevnode->device.UDN);
535 tmpdevnode = tmpdevnode->next;
536 }
537 SampleUtil_Print("\n");
538 ithread_mutex_unlock(&DeviceListMutex);
539
540 return TV_SUCCESS;
541 }
542
543 /********************************************************************************
544 * TvCtrlPointPrintDevice
545 *
546 * Description:
547 * Print the identifiers and state table for a device from
548 * the global device list.
549 *
550 * Parameters:
551 * devnum -- The number of the device (order in the list,
552 * starting with 1)
553 *
554 ********************************************************************************/
TvCtrlPointPrintDevice(int devnum)555 int TvCtrlPointPrintDevice(int devnum)
556 {
557 struct TvDeviceNode *tmpdevnode;
558 int i = 0, service, var;
559 char spacer[15];
560
561 if (devnum <= 0) {
562 SampleUtil_Print("Error in TvCtrlPointPrintDevice: "
563 "invalid devnum = %d\n",
564 devnum);
565 return TV_ERROR;
566 }
567
568 ithread_mutex_lock(&DeviceListMutex);
569
570 SampleUtil_Print("TvCtrlPointPrintDevice:\n");
571 tmpdevnode = GlobalDeviceList;
572 while (tmpdevnode) {
573 i++;
574 if (i == devnum)
575 break;
576 tmpdevnode = tmpdevnode->next;
577 }
578 if (!tmpdevnode) {
579 SampleUtil_Print(
580 "Error in TvCtrlPointPrintDevice: "
581 "invalid devnum = %d -- actual device count = %d\n",
582 devnum,
583 i);
584 } else {
585 SampleUtil_Print(" TvDevice -- %d\n"
586 " | \n"
587 " +- UDN = %s\n"
588 " +- DescDocURL = %s\n"
589 " +- FriendlyName = %s\n"
590 " +- PresURL = %s\n"
591 " +- Adver. TimeOut = %d\n",
592 devnum,
593 tmpdevnode->device.UDN,
594 tmpdevnode->device.DescDocURL,
595 tmpdevnode->device.FriendlyName,
596 tmpdevnode->device.PresURL,
597 tmpdevnode->device.AdvrTimeOut);
598 for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) {
599 if (service < TV_SERVICE_SERVCOUNT - 1)
600 sprintf(spacer, " | ");
601 else
602 sprintf(spacer, " ");
603 SampleUtil_Print(" | \n"
604 " +- Tv %s Service\n"
605 "%s+- ServiceId = %s\n"
606 "%s+- ServiceType = %s\n"
607 "%s+- EventURL = %s\n"
608 "%s+- ControlURL = %s\n"
609 "%s+- SID = %s\n"
610 "%s+- ServiceStateTable\n",
611 TvServiceName[service],
612 spacer,
613 tmpdevnode->device.TvService[service].ServiceId,
614 spacer,
615 tmpdevnode->device.TvService[service]
616 .ServiceType,
617 spacer,
618 tmpdevnode->device.TvService[service].EventURL,
619 spacer,
620 tmpdevnode->device.TvService[service]
621 .ControlURL,
622 spacer,
623 tmpdevnode->device.TvService[service].SID,
624 spacer);
625 for (var = 0; var < TvVarCount[service]; var++) {
626 SampleUtil_Print("%s +- %-10s = %s\n",
627 spacer,
628 TvVarName[service][var],
629 tmpdevnode->device.TvService[service]
630 .VariableStrVal[var]);
631 }
632 }
633 }
634 SampleUtil_Print("\n");
635 ithread_mutex_unlock(&DeviceListMutex);
636
637 return TV_SUCCESS;
638 }
639
640 /********************************************************************************
641 * TvCtrlPointAddDevice
642 *
643 * Description:
644 * If the device is not already included in the global device list,
645 * add it. Otherwise, update its advertisement expiration timeout.
646 *
647 * Parameters:
648 * DescDoc -- The description document for the device
649 * location -- The location of the description document URL
650 * expires -- The expiration time for this advertisement
651 *
652 ********************************************************************************/
TvCtrlPointAddDevice(IXML_Document * DescDoc,const char * location,int expires)653 void TvCtrlPointAddDevice(
654 IXML_Document *DescDoc, const char *location, int expires)
655 {
656 char *deviceType = NULL;
657 char *friendlyName = NULL;
658 char *presURL = NULL;
659 char *baseURL = NULL;
660 char *relURL = NULL;
661 char *UDN = NULL;
662 char *serviceId[TV_SERVICE_SERVCOUNT] = {NULL, NULL};
663 char *eventURL[TV_SERVICE_SERVCOUNT] = {NULL, NULL};
664 char *controlURL[TV_SERVICE_SERVCOUNT] = {NULL, NULL};
665 Upnp_SID eventSID[TV_SERVICE_SERVCOUNT];
666 int TimeOut[TV_SERVICE_SERVCOUNT];
667 struct TvDeviceNode *deviceNode;
668 struct TvDeviceNode *tmpdevnode;
669 int ret = 1;
670 int found = 0;
671 int service;
672 int var;
673
674 TimeOut[0] = default_timeout;
675 TimeOut[1] = default_timeout;
676 ithread_mutex_lock(&DeviceListMutex);
677
678 /* Read key elements from description document */
679 UDN = SampleUtil_GetFirstDocumentItem(DescDoc, "UDN");
680 deviceType = SampleUtil_GetFirstDocumentItem(DescDoc, "deviceType");
681 friendlyName = SampleUtil_GetFirstDocumentItem(DescDoc, "friendlyName");
682 baseURL = SampleUtil_GetFirstDocumentItem(DescDoc, "URLBase");
683 relURL = SampleUtil_GetFirstDocumentItem(DescDoc, "presentationURL");
684
685 ret = UpnpResolveURL2((baseURL ? baseURL : location), relURL, &presURL);
686
687 if (UPNP_E_SUCCESS != ret)
688 SampleUtil_Print("Error generating presURL from %s + %s\n",
689 baseURL,
690 relURL);
691
692 if (strcmp(deviceType, TvDeviceType) == 0) {
693 SampleUtil_Print("Found Tv device\n");
694
695 /* Check if this device is already in the list */
696 tmpdevnode = GlobalDeviceList;
697 while (tmpdevnode) {
698 if (strcmp(tmpdevnode->device.UDN, UDN) == 0) {
699 found = 1;
700 break;
701 }
702 tmpdevnode = tmpdevnode->next;
703 }
704
705 if (found) {
706 /* The device is already there, so just update */
707 /* the advertisement timeout field */
708 tmpdevnode->device.AdvrTimeOut = expires;
709 } else {
710 for (service = 0; service < TV_SERVICE_SERVCOUNT;
711 service++) {
712 if (SampleUtil_FindAndParseService(DescDoc,
713 location,
714 TvServiceType[service],
715 &serviceId[service],
716 &eventURL[service],
717 &controlURL[service])) {
718 SampleUtil_Print("Subscribing to "
719 "EventURL %s...\n",
720 eventURL[service]);
721 ret = UpnpSubscribe(ctrlpt_handle,
722 eventURL[service],
723 &TimeOut[service],
724 eventSID[service]);
725 if (ret == UPNP_E_SUCCESS) {
726 SampleUtil_Print(
727 "Subscribed to "
728 "EventURL with "
729 "SID=%s\n",
730 eventSID[service]);
731 } else {
732 SampleUtil_Print(
733 "Error Subscribing to "
734 "EventURL -- %d\n",
735 ret);
736 strcpy(eventSID[service], "");
737 }
738 } else {
739 SampleUtil_Print("Error: Could not "
740 "find Service: %s\n",
741 TvServiceType[service]);
742 }
743 }
744 /* Create a new device node */
745 deviceNode = (struct TvDeviceNode *)malloc(
746 sizeof(struct TvDeviceNode));
747 strcpy(deviceNode->device.UDN, UDN);
748 strcpy(deviceNode->device.DescDocURL, location);
749 strcpy(deviceNode->device.FriendlyName, friendlyName);
750 strcpy(deviceNode->device.PresURL, presURL);
751 deviceNode->device.AdvrTimeOut = expires;
752 for (service = 0; service < TV_SERVICE_SERVCOUNT;
753 service++) {
754 if (serviceId[service] == NULL) {
755 /* not found */
756 continue;
757 }
758 strcpy(deviceNode->device.TvService[service]
759 .ServiceId,
760 serviceId[service]);
761 strcpy(deviceNode->device.TvService[service]
762 .ServiceType,
763 TvServiceType[service]);
764 strcpy(deviceNode->device.TvService[service]
765 .ControlURL,
766 controlURL[service]);
767 strcpy(deviceNode->device.TvService[service]
768 .EventURL,
769 eventURL[service]);
770 strcpy(deviceNode->device.TvService[service]
771 .SID,
772 eventSID[service]);
773 for (var = 0; var < TvVarCount[service];
774 var++) {
775 deviceNode->device.TvService[service]
776 .VariableStrVal[var] =
777 (char *)malloc(TV_MAX_VAL_LEN);
778 strcpy(deviceNode->device
779 .TvService[service]
780 .VariableStrVal[var],
781 "");
782 }
783 }
784 deviceNode->next = NULL;
785 /* Insert the new device node in the list */
786 if ((tmpdevnode = GlobalDeviceList)) {
787 while (tmpdevnode) {
788 if (tmpdevnode->next) {
789 tmpdevnode = tmpdevnode->next;
790 } else {
791 tmpdevnode->next = deviceNode;
792 break;
793 }
794 }
795 } else {
796 GlobalDeviceList = deviceNode;
797 }
798 /*Notify New Device Added */
799 SampleUtil_StateUpdate(NULL,
800 NULL,
801 deviceNode->device.UDN,
802 DEVICE_ADDED);
803 }
804 }
805
806 ithread_mutex_unlock(&DeviceListMutex);
807
808 if (deviceType)
809 free(deviceType);
810 if (friendlyName)
811 free(friendlyName);
812 if (UDN)
813 free(UDN);
814 if (baseURL)
815 free(baseURL);
816 if (relURL)
817 free(relURL);
818 if (presURL)
819 free(presURL);
820 for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) {
821 if (serviceId[service])
822 free(serviceId[service]);
823 if (controlURL[service])
824 free(controlURL[service]);
825 if (eventURL[service])
826 free(eventURL[service]);
827 }
828 }
829
TvStateUpdate(char * UDN,int Service,IXML_Document * ChangedVariables,char ** State)830 void TvStateUpdate(
831 char *UDN, int Service, IXML_Document *ChangedVariables, char **State)
832 {
833 IXML_NodeList *properties;
834 IXML_NodeList *variables;
835 IXML_Element *property;
836 IXML_Element *variable;
837 long unsigned int length;
838 long unsigned int length1;
839 long unsigned int i;
840 int j;
841 char *tmpstate = NULL;
842 (void)UDN;
843
844 SampleUtil_Print("Tv State Update (service %d):\n", Service);
845 /* Find all of the e:property tags in the document */
846 properties = ixmlDocument_getElementsByTagName(
847 ChangedVariables, "e:property");
848 if (properties) {
849 length = ixmlNodeList_length(properties);
850 for (i = 0; i < length; i++) {
851 /* Loop through each property change found */
852 property = (IXML_Element *)ixmlNodeList_item(
853 properties, i);
854 /* For each variable name in the state table,
855 * check if this is a corresponding property change */
856 for (j = 0; j < TvVarCount[Service]; j++) {
857 variables = ixmlElement_getElementsByTagName(
858 property, TvVarName[Service][j]);
859 /* If a match is found, extract
860 * the value, and update the state table */
861 if (variables) {
862 length1 =
863 ixmlNodeList_length(variables);
864 if (length1) {
865 variable = (IXML_Element *)
866 ixmlNodeList_item(
867 variables, 0);
868 tmpstate =
869 SampleUtil_GetElementValue(
870 variable);
871 if (tmpstate) {
872 strcpy(State[j],
873 tmpstate);
874 SampleUtil_Print(
875 " Variable "
876 "Name: %s New "
877 "Value:'%s'\n",
878 TvVarName
879 [Service]
880 [j],
881 State[j]);
882 }
883 if (tmpstate)
884 free(tmpstate);
885 tmpstate = NULL;
886 }
887 ixmlNodeList_free(variables);
888 variables = NULL;
889 }
890 }
891 }
892 ixmlNodeList_free(properties);
893 }
894 return;
895 }
896
897 /********************************************************************************
898 * TvCtrlPointHandleEvent
899 *
900 * Description:
901 * Handle a UPnP event that was received. Process the event and update
902 * the appropriate service state table.
903 *
904 * Parameters:
905 * sid -- The subscription id for the event
906 * eventkey -- The eventkey number for the event
907 * changes -- The DOM document representing the changes
908 *
909 ********************************************************************************/
TvCtrlPointHandleEvent(const char * sid,int evntkey,IXML_Document * changes)910 void TvCtrlPointHandleEvent(
911 const char *sid, int evntkey, IXML_Document *changes)
912 {
913 struct TvDeviceNode *tmpdevnode;
914 int service;
915
916 ithread_mutex_lock(&DeviceListMutex);
917
918 tmpdevnode = GlobalDeviceList;
919 while (tmpdevnode) {
920 for (service = 0; service < TV_SERVICE_SERVCOUNT; ++service) {
921 if (strcmp(tmpdevnode->device.TvService[service].SID,
922 sid) == 0) {
923 SampleUtil_Print(
924 "Received Tv %s Event: %d for SID %s\n",
925 TvServiceName[service],
926 evntkey,
927 sid);
928 TvStateUpdate(tmpdevnode->device.UDN,
929 service,
930 changes,
931 (char **)&tmpdevnode->device
932 .TvService[service]
933 .VariableStrVal);
934 break;
935 }
936 }
937 tmpdevnode = tmpdevnode->next;
938 }
939
940 ithread_mutex_unlock(&DeviceListMutex);
941 }
942
943 /********************************************************************************
944 * TvCtrlPointHandleSubscribeUpdate
945 *
946 * Description:
947 * Handle a UPnP subscription update that was received. Find the
948 * service the update belongs to, and update its subscription
949 * timeout.
950 *
951 * Parameters:
952 * eventURL -- The event URL for the subscription
953 * sid -- The subscription id for the subscription
954 * timeout -- The new timeout for the subscription
955 *
956 ********************************************************************************/
TvCtrlPointHandleSubscribeUpdate(const char * eventURL,const Upnp_SID sid,int timeout)957 void TvCtrlPointHandleSubscribeUpdate(
958 const char *eventURL, const Upnp_SID sid, int timeout)
959 {
960 struct TvDeviceNode *tmpdevnode;
961 int service;
962 (void)timeout;
963
964 ithread_mutex_lock(&DeviceListMutex);
965
966 tmpdevnode = GlobalDeviceList;
967 while (tmpdevnode) {
968 for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) {
969 if (strcmp(tmpdevnode->device.TvService[service]
970 .EventURL,
971 eventURL) == 0) {
972 SampleUtil_Print("Received Tv %s Event Renewal "
973 "for eventURL %s\n",
974 TvServiceName[service],
975 eventURL);
976 strcpy(tmpdevnode->device.TvService[service]
977 .SID,
978 sid);
979 break;
980 }
981 }
982
983 tmpdevnode = tmpdevnode->next;
984 }
985
986 ithread_mutex_unlock(&DeviceListMutex);
987
988 return;
989 }
990
TvCtrlPointHandleGetVar(const char * controlURL,const char * varName,const DOMString varValue)991 void TvCtrlPointHandleGetVar(
992 const char *controlURL, const char *varName, const DOMString varValue)
993 {
994
995 struct TvDeviceNode *tmpdevnode;
996 int service;
997
998 ithread_mutex_lock(&DeviceListMutex);
999
1000 tmpdevnode = GlobalDeviceList;
1001 while (tmpdevnode) {
1002 for (service = 0; service < TV_SERVICE_SERVCOUNT; service++) {
1003 if (strcmp(tmpdevnode->device.TvService[service]
1004 .ControlURL,
1005 controlURL) == 0) {
1006 SampleUtil_StateUpdate(varName,
1007 varValue,
1008 tmpdevnode->device.UDN,
1009 GET_VAR_COMPLETE);
1010 break;
1011 }
1012 }
1013 tmpdevnode = tmpdevnode->next;
1014 }
1015
1016 ithread_mutex_unlock(&DeviceListMutex);
1017 }
1018
1019 /********************************************************************************
1020 * TvCtrlPointCallbackEventHandler
1021 *
1022 * Description:
1023 * The callback handler registered with the SDK while registering
1024 * the control point. Detects the type of callback, and passes the
1025 * request on to the appropriate function.
1026 *
1027 * Parameters:
1028 * EventType -- The type of callback event
1029 * Event -- Data structure containing event data
1030 * Cookie -- Optional data specified during callback registration
1031 *
1032 ********************************************************************************/
TvCtrlPointCallbackEventHandler(Upnp_EventType EventType,const void * Event,void * Cookie)1033 int TvCtrlPointCallbackEventHandler(
1034 Upnp_EventType EventType, const void *Event, void *Cookie)
1035 {
1036 int errCode = 0;
1037 (void)Cookie;
1038
1039 SampleUtil_PrintEvent(EventType, Event);
1040 switch (EventType) {
1041 /* SSDP Stuff */
1042 case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
1043 case UPNP_DISCOVERY_SEARCH_RESULT: {
1044 const UpnpDiscovery *d_event = (UpnpDiscovery *)Event;
1045 IXML_Document *DescDoc = NULL;
1046 const char *location = NULL;
1047 int errCode = UpnpDiscovery_get_ErrCode(d_event);
1048
1049 if (errCode != UPNP_E_SUCCESS) {
1050 SampleUtil_Print(
1051 "Error in Discovery Callback -- %d\n", errCode);
1052 }
1053
1054 location = UpnpString_get_String(
1055 UpnpDiscovery_get_Location(d_event));
1056 errCode = UpnpDownloadXmlDoc(location, &DescDoc);
1057 if (errCode != UPNP_E_SUCCESS) {
1058 SampleUtil_Print("Error obtaining device description "
1059 "from %s -- error = %d\n",
1060 location,
1061 errCode);
1062 } else {
1063 TvCtrlPointAddDevice(DescDoc,
1064 location,
1065 UpnpDiscovery_get_Expires(d_event));
1066 }
1067 if (DescDoc) {
1068 ixmlDocument_free(DescDoc);
1069 }
1070 TvCtrlPointPrintList();
1071 break;
1072 }
1073 case UPNP_DISCOVERY_SEARCH_TIMEOUT:
1074 /* Nothing to do here... */
1075 break;
1076 case UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE: {
1077 UpnpDiscovery *d_event = (UpnpDiscovery *)Event;
1078 int errCode = UpnpDiscovery_get_ErrCode(d_event);
1079 const char *deviceId = UpnpString_get_String(
1080 UpnpDiscovery_get_DeviceID(d_event));
1081
1082 if (errCode != UPNP_E_SUCCESS) {
1083 SampleUtil_Print(
1084 "Error in Discovery ByeBye Callback -- %d\n",
1085 errCode);
1086 }
1087 SampleUtil_Print("Received ByeBye for Device: %s\n", deviceId);
1088 TvCtrlPointRemoveDevice(deviceId);
1089 SampleUtil_Print("After byebye:\n");
1090 TvCtrlPointPrintList();
1091 break;
1092 }
1093 /* SOAP Stuff */
1094 case UPNP_CONTROL_ACTION_COMPLETE: {
1095 UpnpActionComplete *a_event = (UpnpActionComplete *)Event;
1096 int errCode = UpnpActionComplete_get_ErrCode(a_event);
1097 if (errCode != UPNP_E_SUCCESS) {
1098 SampleUtil_Print(
1099 "Error in Action Complete Callback -- %d\n",
1100 errCode);
1101 }
1102 /* No need for any processing here, just print out results.
1103 * Service state table updates are handled by events. */
1104 break;
1105 }
1106 case UPNP_CONTROL_GET_VAR_COMPLETE: {
1107 UpnpStateVarComplete *sv_event = (UpnpStateVarComplete *)Event;
1108 int errCode = UpnpStateVarComplete_get_ErrCode(sv_event);
1109 if (errCode != UPNP_E_SUCCESS) {
1110 SampleUtil_Print(
1111 "Error in Get Var Complete Callback -- %d\n",
1112 errCode);
1113 } else {
1114 TvCtrlPointHandleGetVar(
1115 UpnpString_get_String(
1116 UpnpStateVarComplete_get_CtrlUrl(
1117 sv_event)),
1118 UpnpString_get_String(
1119 UpnpStateVarComplete_get_StateVarName(
1120 sv_event)),
1121 UpnpStateVarComplete_get_CurrentVal(sv_event));
1122 }
1123 break;
1124 }
1125 /* GENA Stuff */
1126 case UPNP_EVENT_RECEIVED: {
1127 UpnpEvent *e_event = (UpnpEvent *)Event;
1128 TvCtrlPointHandleEvent(UpnpEvent_get_SID_cstr(e_event),
1129 UpnpEvent_get_EventKey(e_event),
1130 UpnpEvent_get_ChangedVariables(e_event));
1131 break;
1132 }
1133 case UPNP_EVENT_SUBSCRIBE_COMPLETE:
1134 case UPNP_EVENT_UNSUBSCRIBE_COMPLETE:
1135 case UPNP_EVENT_RENEWAL_COMPLETE: {
1136 UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event;
1137
1138 errCode = UpnpEventSubscribe_get_ErrCode(es_event);
1139 if (errCode != UPNP_E_SUCCESS) {
1140 SampleUtil_Print(
1141 "Error in Event Subscribe Callback -- %d\n",
1142 errCode);
1143 } else {
1144 TvCtrlPointHandleSubscribeUpdate(
1145 UpnpString_get_String(
1146 UpnpEventSubscribe_get_PublisherUrl(
1147 es_event)),
1148 UpnpString_get_String(
1149 UpnpEventSubscribe_get_SID(es_event)),
1150 UpnpEventSubscribe_get_TimeOut(es_event));
1151 }
1152 break;
1153 }
1154 case UPNP_EVENT_AUTORENEWAL_FAILED:
1155 case UPNP_EVENT_SUBSCRIPTION_EXPIRED: {
1156 UpnpEventSubscribe *es_event = (UpnpEventSubscribe *)Event;
1157 int TimeOut = default_timeout;
1158 Upnp_SID newSID;
1159
1160 errCode = UpnpSubscribe(ctrlpt_handle,
1161 UpnpString_get_String(
1162 UpnpEventSubscribe_get_PublisherUrl(es_event)),
1163 &TimeOut,
1164 newSID);
1165 if (errCode == UPNP_E_SUCCESS) {
1166 SampleUtil_Print(
1167 "Subscribed to EventURL with SID=%s\n", newSID);
1168 TvCtrlPointHandleSubscribeUpdate(
1169 UpnpString_get_String(
1170 UpnpEventSubscribe_get_PublisherUrl(
1171 es_event)),
1172 newSID,
1173 TimeOut);
1174 } else {
1175 SampleUtil_Print(
1176 "Error Subscribing to EventURL -- %d\n",
1177 errCode);
1178 }
1179 break;
1180 }
1181 /* ignore these cases, since this is not a device */
1182 case UPNP_EVENT_SUBSCRIPTION_REQUEST:
1183 case UPNP_CONTROL_GET_VAR_REQUEST:
1184 case UPNP_CONTROL_ACTION_REQUEST:
1185 break;
1186 }
1187
1188 return 0;
1189 }
1190
TvCtrlPointVerifyTimeouts(int incr)1191 void TvCtrlPointVerifyTimeouts(int incr)
1192 {
1193 struct TvDeviceNode *prevdevnode;
1194 struct TvDeviceNode *curdevnode;
1195 int ret;
1196
1197 ithread_mutex_lock(&DeviceListMutex);
1198
1199 prevdevnode = NULL;
1200 curdevnode = GlobalDeviceList;
1201 while (curdevnode) {
1202 curdevnode->device.AdvrTimeOut -= incr;
1203 /*SampleUtil_Print("Advertisement Timeout: %d\n",
1204 * curdevnode->device.AdvrTimeOut); */
1205 if (curdevnode->device.AdvrTimeOut <= 0) {
1206 /* This advertisement has expired, so we should remove
1207 * the device from the list */
1208 if (GlobalDeviceList == curdevnode)
1209 GlobalDeviceList = curdevnode->next;
1210 else
1211 prevdevnode->next = curdevnode->next;
1212 TvCtrlPointDeleteNode(curdevnode);
1213 if (prevdevnode)
1214 curdevnode = prevdevnode->next;
1215 else
1216 curdevnode = GlobalDeviceList;
1217 } else {
1218 if (curdevnode->device.AdvrTimeOut < 2 * incr) {
1219 /* This advertisement is about to expire, so
1220 * send out a search request for this device
1221 * UDN to try to renew */
1222 ret = UpnpSearchAsync(ctrlpt_handle,
1223 incr,
1224 curdevnode->device.UDN,
1225 NULL);
1226 if (ret != UPNP_E_SUCCESS)
1227 SampleUtil_Print(
1228 "Error sending search request "
1229 "for Device UDN: %s -- err = "
1230 "%d\n",
1231 curdevnode->device.UDN,
1232 ret);
1233 }
1234 prevdevnode = curdevnode;
1235 curdevnode = curdevnode->next;
1236 }
1237 }
1238
1239 ithread_mutex_unlock(&DeviceListMutex);
1240 }
1241
1242 /*!
1243 * \brief Function that runs in its own thread and monitors advertisement
1244 * and subscription timeouts for devices in the global device list.
1245 */
1246 static int TvCtrlPointTimerLoopRun = 1;
TvCtrlPointTimerLoop(void * args)1247 void *TvCtrlPointTimerLoop(void *args)
1248 {
1249 /* how often to verify the timeouts, in seconds */
1250 int incr = 30;
1251 (void)args;
1252
1253 while (TvCtrlPointTimerLoopRun) {
1254 isleep((unsigned int)incr);
1255 TvCtrlPointVerifyTimeouts(incr);
1256 }
1257
1258 return NULL;
1259 }
1260
1261 /*!
1262 * \brief Call this function to initialize the UPnP library and start the TV
1263 * Control Point. This function creates a timer thread and provides a
1264 * callback handler to process any UPnP events that are received.
1265 *
1266 * \return TV_SUCCESS if everything went well, else TV_ERROR.
1267 */
TvCtrlPointStart(char * iface,state_update updateFunctionPtr,int combo)1268 int TvCtrlPointStart(char *iface,
1269 state_update updateFunctionPtr,
1270 int combo)
1271 {
1272 ithread_t timer_thread;
1273 int rc;
1274 unsigned short port = 0;
1275
1276 SampleUtil_RegisterUpdateFunction(updateFunctionPtr);
1277
1278 ithread_mutex_init(&DeviceListMutex, 0);
1279
1280 SampleUtil_Print("Initializing UPnP Sdk with\n"
1281 "\tinterface = %s port = %u\n",
1282 iface ? iface : "{NULL}",
1283 port);
1284
1285 rc = UpnpInit2(iface, port);
1286 if (rc != UPNP_E_SUCCESS) {
1287 SampleUtil_Print("WinCEStart: UpnpInit2() Error: %d\n", rc);
1288 if (!combo) {
1289 UpnpFinish();
1290
1291 return TV_ERROR;
1292 }
1293 }
1294
1295 SampleUtil_Print("UPnP Initialized\n"
1296 "\tipv4 address = %s port = %u\n"
1297 "\tipv6 address = %s port = %u\n"
1298 "\tipv6ulagua address = %s port = %u\n",
1299 UpnpGetServerIpAddress(), UpnpGetServerPort(),
1300 UpnpGetServerIp6Address(), UpnpGetServerPort6(),
1301 UpnpGetServerUlaGuaIp6Address(), UpnpGetServerUlaGuaPort6());
1302 SampleUtil_Print("Registering Control Point\n");
1303 rc = UpnpRegisterClient(TvCtrlPointCallbackEventHandler,
1304 &ctrlpt_handle,
1305 &ctrlpt_handle);
1306 if (rc != UPNP_E_SUCCESS) {
1307 SampleUtil_Print("Error registering CP: %d\n", rc);
1308 UpnpFinish();
1309
1310 return TV_ERROR;
1311 }
1312
1313 SampleUtil_Print("Control Point Registered\n");
1314
1315 TvCtrlPointRefresh();
1316
1317 /* start a timer thread */
1318 ithread_create(&timer_thread, NULL, TvCtrlPointTimerLoop, NULL);
1319 ithread_detach(timer_thread);
1320
1321 return TV_SUCCESS;
1322 }
1323
TvCtrlPointStop(void)1324 int TvCtrlPointStop(void)
1325 {
1326 TvCtrlPointTimerLoopRun = 0;
1327 TvCtrlPointRemoveAll();
1328 UpnpUnRegisterClient(ctrlpt_handle);
1329 UpnpFinish();
1330 SampleUtil_Finish();
1331
1332 return TV_SUCCESS;
1333 }
1334
TvCtrlPointPrintShortHelp(void)1335 void TvCtrlPointPrintShortHelp(void)
1336 {
1337 SampleUtil_Print("Commands:\n"
1338 " Help\n"
1339 " HelpFull\n"
1340 " ListDev\n"
1341 " Refresh\n"
1342 " PrintDev <devnum>\n"
1343 " PowerOn <devnum>\n"
1344 " PowerOff <devnum>\n"
1345 " SetChannel <devnum> <channel>\n"
1346 " SetVolume <devnum> <volume>\n"
1347 " SetColor <devnum> <color>\n"
1348 " SetTint <devnum> <tint>\n"
1349 " SetContrast <devnum> <contrast>\n"
1350 " SetBrightness <devnum> <brightness>\n"
1351 " CtrlAction <devnum> <action>\n"
1352 " PictAction <devnum> <action>\n"
1353 " CtrlGetVar <devnum> <varname>\n"
1354 " PictGetVar <devnum> <action>\n"
1355 " Exit\n");
1356 }
1357
TvCtrlPointPrintLongHelp(void)1358 void TvCtrlPointPrintLongHelp(void)
1359 {
1360 SampleUtil_Print(
1361 "\n"
1362 "******************************\n"
1363 "* TV Control Point Help Info *\n"
1364 "******************************\n"
1365 "\n"
1366 "This sample control point application automatically searches\n"
1367 "for and subscribes to the services of television device "
1368 "emulator\n"
1369 "devices, described in the tvdevicedesc.xml description "
1370 "document.\n"
1371 "It also registers itself as a tv device.\n"
1372 "\n"
1373 "Commands:\n"
1374 " Help\n"
1375 " Print this help info.\n"
1376 " ListDev\n"
1377 " Print the current list of TV Device Emulators that "
1378 "this\n"
1379 " control point is aware of. Each device is preceded "
1380 "by a\n"
1381 " device number which corresponds to the devnum "
1382 "argument of\n"
1383 " commands listed below.\n"
1384 " Refresh\n"
1385 " Delete all of the devices from the device list and "
1386 "issue new\n"
1387 " search request to rebuild the list from scratch.\n"
1388 " PrintDev <devnum>\n"
1389 " Print the state table for the device <devnum>.\n"
1390 " e.g., 'PrintDev 1' prints the state table for the "
1391 "first\n"
1392 " device in the device list.\n"
1393 " PowerOn <devnum>\n"
1394 " Sends the PowerOn action to the Control Service of\n"
1395 " device <devnum>.\n"
1396 " PowerOff <devnum>\n"
1397 " Sends the PowerOff action to the Control Service of\n"
1398 " device <devnum>.\n"
1399 " SetChannel <devnum> <channel>\n"
1400 " Sends the SetChannel action to the Control Service of\n"
1401 " device <devnum>, requesting the channel to be "
1402 "changed\n"
1403 " to <channel>.\n"
1404 " SetVolume <devnum> <volume>\n"
1405 " Sends the SetVolume action to the Control Service of\n"
1406 " device <devnum>, requesting the volume to be "
1407 "changed\n"
1408 " to <volume>.\n"
1409 " SetColor <devnum> <color>\n"
1410 " Sends the SetColor action to the Control Service of\n"
1411 " device <devnum>, requesting the color to be changed\n"
1412 " to <color>.\n"
1413 " SetTint <devnum> <tint>\n"
1414 " Sends the SetTint action to the Control Service of\n"
1415 " device <devnum>, requesting the tint to be changed\n"
1416 " to <tint>.\n"
1417 " SetContrast <devnum> <contrast>\n"
1418 " Sends the SetContrast action to the Control Service "
1419 "of\n"
1420 " device <devnum>, requesting the contrast to be "
1421 "changed\n"
1422 " to <contrast>.\n"
1423 " SetBrightness <devnum> <brightness>\n"
1424 " Sends the SetBrightness action to the Control Service "
1425 "of\n"
1426 " device <devnum>, requesting the brightness to be "
1427 "changed\n"
1428 " to <brightness>.\n"
1429 " CtrlAction <devnum> <action>\n"
1430 " Sends an action request specified by the string "
1431 "<action>\n"
1432 " to the Control Service of device <devnum>. This "
1433 "command\n"
1434 " only works for actions that have no arguments.\n"
1435 " (e.g., \"CtrlAction 1 IncreaseChannel\")\n"
1436 " PictAction <devnum> <action>\n"
1437 " Sends an action request specified by the string "
1438 "<action>\n"
1439 " to the Picture Service of device <devnum>. This "
1440 "command\n"
1441 " only works for actions that have no arguments.\n"
1442 " (e.g., \"PictAction 1 DecreaseContrast\")\n"
1443 " CtrlGetVar <devnum> <varname>\n"
1444 " Requests the value of a variable specified by the "
1445 "string <varname>\n"
1446 " from the Control Service of device <devnum>.\n"
1447 " (e.g., \"CtrlGetVar 1 Volume\")\n"
1448 " PictGetVar <devnum> <action>\n"
1449 " Requests the value of a variable specified by the "
1450 "string <varname>\n"
1451 " from the Picture Service of device <devnum>.\n"
1452 " (e.g., \"PictGetVar 1 Tint\")\n"
1453 " Exit\n"
1454 " Exits the control point application.\n");
1455 }
1456
1457 /*! Tags for valid commands issued at the command prompt. */
1458 enum cmdloop_tvcmds
1459 {
1460 PRTHELP = 0,
1461 PRTFULLHELP,
1462 POWON,
1463 POWOFF,
1464 SETCHAN,
1465 SETVOL,
1466 SETCOL,
1467 SETTINT,
1468 SETCONT,
1469 SETBRT,
1470 CTRLACTION,
1471 PICTACTION,
1472 CTRLGETVAR,
1473 PICTGETVAR,
1474 PRTDEV,
1475 LSTDEV,
1476 REFRESH,
1477 EXITCMD
1478 };
1479
1480 /*! Data structure for parsing commands from the command line. */
1481 struct cmdloop_commands
1482 {
1483 /* the string */
1484 const char *str;
1485 /* the command */
1486 int cmdnum;
1487 /* the number of arguments */
1488 int numargs;
1489 /* the args */
1490 const char *args;
1491 } cmdloop_commands;
1492
1493 /*! Mappings between command text names, command tag,
1494 * and required command arguments for command line
1495 * commands */
1496 static struct cmdloop_commands cmdloop_cmdlist[] = {{"Help", PRTHELP, 1, ""},
1497 {"HelpFull", PRTFULLHELP, 1, ""},
1498 {"ListDev", LSTDEV, 1, ""},
1499 {"Refresh", REFRESH, 1, ""},
1500 {"PrintDev", PRTDEV, 2, "<devnum>"},
1501 {"PowerOn", POWON, 2, "<devnum>"},
1502 {"PowerOff", POWOFF, 2, "<devnum>"},
1503 {"SetChannel", SETCHAN, 3, "<devnum> <channel (int)>"},
1504 {"SetVolume", SETVOL, 3, "<devnum> <volume (int)>"},
1505 {"SetColor", SETCOL, 3, "<devnum> <color (int)>"},
1506 {"SetTint", SETTINT, 3, "<devnum> <tint (int)>"},
1507 {"SetContrast", SETCONT, 3, "<devnum> <contrast (int)>"},
1508 {"SetBrightness", SETBRT, 3, "<devnum> <brightness (int)>"},
1509 {"CtrlAction", CTRLACTION, 2, "<devnum> <action (string)>"},
1510 {"PictAction", PICTACTION, 2, "<devnum> <action (string)>"},
1511 {"CtrlGetVar", CTRLGETVAR, 2, "<devnum> <varname (string)>"},
1512 {"PictGetVar", PICTGETVAR, 2, "<devnum> <varname (string)>"},
1513 {"Exit", EXITCMD, 1, ""}};
1514
TvCtrlPointPrintCommands(void)1515 void TvCtrlPointPrintCommands(void)
1516 {
1517 int i;
1518 int numofcmds = (sizeof cmdloop_cmdlist) / sizeof(cmdloop_commands);
1519
1520 SampleUtil_Print("Valid Commands:\n");
1521 for (i = 0; i < numofcmds; ++i) {
1522 SampleUtil_Print(" %-14s %s\n",
1523 cmdloop_cmdlist[i].str,
1524 cmdloop_cmdlist[i].args);
1525 }
1526 SampleUtil_Print("\n");
1527 }
1528
TvCtrlPointCommandLoop(void * args)1529 void *TvCtrlPointCommandLoop(void *args)
1530 {
1531 char cmdline[100];
1532 char *s;
1533 (void)args;
1534
1535 while (1) {
1536 SampleUtil_Print("\n>> ");
1537 s = fgets(cmdline, 100, stdin);
1538 if (!s)
1539 break;
1540 TvCtrlPointProcessCommand(cmdline);
1541 }
1542
1543 return NULL;
1544 }
1545
TvCtrlPointProcessCommand(char * cmdline)1546 int TvCtrlPointProcessCommand(char *cmdline)
1547 {
1548 char cmd[100];
1549 char strarg[100];
1550 int arg_val_err = -99999;
1551 int arg1 = arg_val_err;
1552 int arg2 = arg_val_err;
1553 int cmdnum = -1;
1554 int numofcmds = (sizeof cmdloop_cmdlist) / sizeof(cmdloop_commands);
1555 int cmdfound = 0;
1556 int i;
1557 int rc;
1558 int invalidargs = 0;
1559 int validargs;
1560
1561 validargs = sscanf(cmdline, "%s %d %d", cmd, &arg1, &arg2);
1562 for (i = 0; i < numofcmds; ++i) {
1563 if (strcasecmp(cmd, cmdloop_cmdlist[i].str) == 0) {
1564 cmdnum = cmdloop_cmdlist[i].cmdnum;
1565 cmdfound++;
1566 if (validargs != cmdloop_cmdlist[i].numargs)
1567 invalidargs++;
1568 break;
1569 }
1570 }
1571 if (!cmdfound) {
1572 SampleUtil_Print("Command not found; try 'Help'\n");
1573 return TV_SUCCESS;
1574 }
1575 if (invalidargs) {
1576 SampleUtil_Print("Invalid arguments; try 'Help'\n");
1577 return TV_SUCCESS;
1578 }
1579 switch (cmdnum) {
1580 case PRTHELP:
1581 TvCtrlPointPrintShortHelp();
1582 break;
1583 case PRTFULLHELP:
1584 TvCtrlPointPrintLongHelp();
1585 break;
1586 case POWON:
1587 TvCtrlPointSendPowerOn(arg1);
1588 break;
1589 case POWOFF:
1590 TvCtrlPointSendPowerOff(arg1);
1591 break;
1592 case SETCHAN:
1593 TvCtrlPointSendSetChannel(arg1, arg2);
1594 break;
1595 case SETVOL:
1596 TvCtrlPointSendSetVolume(arg1, arg2);
1597 break;
1598 case SETCOL:
1599 TvCtrlPointSendSetColor(arg1, arg2);
1600 break;
1601 case SETTINT:
1602 TvCtrlPointSendSetTint(arg1, arg2);
1603 break;
1604 case SETCONT:
1605 TvCtrlPointSendSetContrast(arg1, arg2);
1606 break;
1607 case SETBRT:
1608 TvCtrlPointSendSetBrightness(arg1, arg2);
1609 break;
1610 case CTRLACTION:
1611 /* re-parse commandline since second arg is string. */
1612 validargs = sscanf(cmdline, "%s %d %s", cmd, &arg1, strarg);
1613 if (validargs == 3)
1614 TvCtrlPointSendAction(TV_SERVICE_CONTROL,
1615 arg1,
1616 strarg,
1617 NULL,
1618 NULL,
1619 0);
1620 else
1621 invalidargs++;
1622 break;
1623 case PICTACTION:
1624 /* re-parse commandline since second arg is string. */
1625 validargs = sscanf(cmdline, "%s %d %s", cmd, &arg1, strarg);
1626 if (validargs == 3)
1627 TvCtrlPointSendAction(TV_SERVICE_PICTURE,
1628 arg1,
1629 strarg,
1630 NULL,
1631 NULL,
1632 0);
1633 else
1634 invalidargs++;
1635 break;
1636 case CTRLGETVAR:
1637 /* re-parse commandline since second arg is string. */
1638 validargs = sscanf(cmdline, "%s %d %s", cmd, &arg1, strarg);
1639 if (validargs == 3)
1640 TvCtrlPointGetVar(TV_SERVICE_CONTROL, arg1, strarg);
1641 else
1642 invalidargs++;
1643 break;
1644 case PICTGETVAR:
1645 /* re-parse commandline since second arg is string. */
1646 validargs = sscanf(cmdline, "%s %d %s", cmd, &arg1, strarg);
1647 if (validargs == 3)
1648 TvCtrlPointGetVar(TV_SERVICE_PICTURE, arg1, strarg);
1649 else
1650 invalidargs++;
1651 break;
1652 case PRTDEV:
1653 TvCtrlPointPrintDevice(arg1);
1654 break;
1655 case LSTDEV:
1656 TvCtrlPointPrintList();
1657 break;
1658 case REFRESH:
1659 TvCtrlPointRefresh();
1660 break;
1661 case EXITCMD:
1662 rc = TvCtrlPointStop();
1663 exit(rc);
1664 break;
1665 default:
1666 SampleUtil_Print("Command not implemented; see 'Help'\n");
1667 break;
1668 }
1669 if (invalidargs)
1670 SampleUtil_Print("Invalid args in command; see 'Help'\n");
1671
1672 return TV_SUCCESS;
1673 }
1674
1675 /*! @} Control Point Sample Module */
1676
1677 /*! @} UpnpSamples */
1678