Deprecate OCSetDeviceInfo and registerDeviceInfo
[platform/upstream/iotivity.git] / resource / examples / simpleserverHQ.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 ///
22 /// This sample provides steps to define an interface for a resource
23 /// (properties and methods) and host this resource on the server.
24 ///
25
26 #include "iotivity_config.h"
27 #include <functional>
28
29 #ifdef HAVE_PTHREAD_H
30 #include <pthread.h>
31 #endif
32 #include <mutex>
33 #include <condition_variable>
34
35 #include "OCPlatform.h"
36 #include "OCApi.h"
37
38 #ifdef HAVE_WINDOWS_H
39 #include <windows.h>
40 #endif
41
42 #include "ocpayload.h"
43
44 using namespace OC;
45 using namespace std;
46 namespace PH = std::placeholders;
47
48 int gObservation = 0;
49 void * ChangeLightRepresentation (void *param);
50
51 // Set of strings for each of platform Info fields
52 std::string  platformId = "0A3E0D6F-DBF5-404E-8719-D6880042463A";
53 std::string  manufacturerName = "OCF";
54 std::string  manufacturerLink = "https://www.iotivity.org";
55 std::string  modelNumber = "myModelNumber";
56 std::string  dateOfManufacture = "2016-01-15";
57 std::string  platformVersion = "myPlatformVersion";
58 std::string  operatingSystemVersion = "myOS";
59 std::string  hardwareVersion = "myHardwareVersion";
60 std::string  firmwareVersion = "1.0";
61 std::string  supportLink = "https://www.iotivity.org";
62 std::string  systemTime = "2016-01-15T11.01";
63
64 // Set of strings for each of device info fields
65 std::string  deviceName = "IoTivity Simple Server HQ";
66 std::string  specVersion = "core.1.1.0";
67 std::vector<std::string> dataModelVersions = {"res.1.1.0"};
68
69 // OCPlatformInfo Contains all the platform info to be stored
70 OCPlatformInfo platformInfo;
71
72 // Specifies where to notify all observers or list of observers
73 // 0 - notifies all observers
74 // 1 - notifies list of observers
75 int isListOfObservers = 0;
76
77 /// This class represents a single resource named 'lightResource'. This resource has
78 /// two simple properties named 'state' and 'power'
79
80 class LightResource
81 {
82
83 public:
84     /// Access this property from a TB client
85     std::string m_name;
86     bool m_state;
87     int m_power;
88     std::string m_lightUri;
89     OCResourceHandle m_resourceHandle;
90     OCRepresentation m_lightRep;
91     ObservationIds m_interestedObservers;
92
93 public:
94     /// Constructor
95     LightResource(PlatformConfig& /*cfg*/)
96         :m_name("John's light"), m_state(false), m_power(0), m_lightUri("/a/light") {
97         // Initialize representation
98         m_lightRep.setUri(m_lightUri);
99
100         m_lightRep.setValue("state", m_state);
101         m_lightRep.setValue("power", m_power);
102         m_lightRep.setValue("name", m_name);
103     }
104
105     /* Note that this does not need to be a member function: for classes you do not have
106     access to, you can accomplish this with a free function: */
107
108     /// This function internally calls registerResource API.
109     void createResource()
110     {
111         std::string resourceURI = m_lightUri; // URI of the resource
112         // resource type name. In this case, it is light
113         std::string resourceTypeName = "core.light";
114         std::string resourceInterface = DEFAULT_INTERFACE; // resource interface.
115
116         // OCResourceProperty is defined ocstack.h
117         uint8_t resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
118
119         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
120
121         // This will internally create and register the resource.
122         OCStackResult result = OCPlatform::registerResource(
123                                     m_resourceHandle, resourceURI, resourceTypeName,
124                                     resourceInterface, cb, resourceProperty);
125
126         if (OC_STACK_OK != result)
127         {
128             cout << "Resource creation was unsuccessful\n";
129         }
130     }
131
132     OCStackResult createResource1()
133     {
134         std::string resourceURI = "/a/light1"; // URI of the resource
135         std::string resourceTypeName = "core.light"; // resource type name. In this case, it is light
136         std::string resourceInterface = DEFAULT_INTERFACE; // resource interface.
137
138         // OCResourceProperty is defined ocstack.h
139         uint8_t resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE;
140
141         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
142
143         OCResourceHandle resHandle;
144
145         // This will internally create and register the resource.
146         OCStackResult result = OCPlatform::registerResource(
147                                     resHandle, resourceURI, resourceTypeName,
148                                     resourceInterface, cb, resourceProperty);
149
150         if (OC_STACK_OK != result)
151         {
152             cout << "Resource creation was unsuccessful\n";
153         }
154
155         return result;
156     }
157
158     OCResourceHandle getHandle()
159     {
160         return m_resourceHandle;
161     }
162
163     // Puts representation.
164     // Gets values from the representation and
165     // updates the internal state
166     void put(OCRepresentation& rep)
167     {
168         try {
169             if (rep.getValue("state", m_state))
170             {
171                 cout << "\t\t\t\t" << "state: " << m_state << endl;
172             }
173             else
174             {
175                 cout << "\t\t\t\t" << "state not found in the representation" << endl;
176             }
177
178             if (rep.getValue("power", m_power))
179             {
180                 cout << "\t\t\t\t" << "power: " << m_power << endl;
181             }
182             else
183             {
184                 cout << "\t\t\t\t" << "power not found in the representation" << endl;
185             }
186         }
187         catch (exception& e)
188         {
189             cout << e.what() << endl;
190         }
191
192     }
193
194     // Post representation.
195     // Post can create new resource or simply act like put.
196     // Gets values from the representation and
197     // updates the internal state
198     OCRepresentation post(OCRepresentation& rep)
199     {
200         static int first = 1;
201
202         std::cout << "In POST\n";
203
204         // for the first time it tries to create a resource
205         if(first)
206         {
207             std::cout << "In POST/First\n";
208
209             first = 0;
210
211             if(OC_STACK_OK == createResource1())
212             {
213                 std::cout << "Created a new resource\n";
214                 OCRepresentation rep1;
215                 rep1.setValue("createduri", std::string("/a/light1"));
216
217                 return rep1;
218             }
219         }
220
221         // from second time onwards it just puts
222         put(rep);
223         return get();
224     }
225
226
227     // gets the updated representation.
228     // Updates the representation with latest internal state before
229     // sending out.
230     OCRepresentation get()
231     {
232         m_lightRep.setValue("state", m_state);
233         m_lightRep.setValue("power", m_power);
234
235         return m_lightRep;
236     }
237
238     void addType(const std::string& type) const
239     {
240         OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type);
241         if (OC_STACK_OK != result)
242         {
243             cout << "Binding TypeName to Resource was unsuccessful\n";
244         }
245     }
246
247     void addInterface(const std::string& iface) const
248     {
249         OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, iface);
250         if (OC_STACK_OK != result)
251         {
252             cout << "Binding TypeName to Resource was unsuccessful\n";
253         }
254     }
255
256 private:
257
258 OCStackResult sendResponse(std::shared_ptr<OCResourceRequest> pRequest)
259 {
260     auto pResponse = std::make_shared<OC::OCResourceResponse>();
261     pResponse->setRequestHandle(pRequest->getRequestHandle());
262     pResponse->setResourceHandle(pRequest->getResourceHandle());
263     pResponse->setResourceRepresentation(get());
264
265     pResponse->setResponseResult(OC_EH_OK);
266
267     return OCPlatform::sendResponse(pResponse);
268 }
269
270 OCStackResult sendPostResponse(std::shared_ptr<OCResourceRequest> pRequest)
271 {
272     auto pResponse = std::make_shared<OC::OCResourceResponse>();
273     pResponse->setRequestHandle(pRequest->getRequestHandle());
274     pResponse->setResourceHandle(pRequest->getResourceHandle());
275
276     OCRepresentation rep = pRequest->getResourceRepresentation();
277     OCRepresentation rep_post = post(rep);
278
279     pResponse->setResourceRepresentation(rep_post);
280
281     pResponse->setResponseResult(OC_EH_OK);
282
283     return OCPlatform::sendResponse(pResponse);
284 }
285
286 // This is just a sample implementation of entity handler.
287 // Entity handler can be implemented in several ways by the manufacturer
288 OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
289 {
290     cout << "\tIn Server CPP entity handler:\n";
291     OCEntityHandlerResult ehResult = OC_EH_ERROR;
292
293     if(request)
294     {
295         // Get the request type and request flag
296         std::string requestType = request->getRequestType();
297         int requestFlag = request->getRequestHandlerFlag();
298
299         if(requestFlag & RequestHandlerFlag::RequestFlag)
300         {
301             cout << "\t\trequestFlag : Request\n";
302
303             // If the request type is GET
304             if(requestType == "GET")
305             {
306                 cout << "\t\t\trequestType : GET\n";
307                 if(OC_STACK_OK == sendResponse(request))
308                 {
309                     ehResult = OC_EH_OK;
310                 }
311             }
312             else if(requestType == "PUT")
313             {
314                 cout << "\t\t\trequestType : PUT\n";
315
316                 OCRepresentation rep = request->getResourceRepresentation();
317                 // Do related operations related to PUT request
318                 // Update the lightResource
319                 put(rep);
320                 if(OC_STACK_OK == sendResponse(request))
321                 {
322                     ehResult = OC_EH_OK;
323                 }
324             }
325             else if(requestType == "POST")
326             {
327                 cout << "\t\t\trequestType : POST\n";
328                 if(OC_STACK_OK == sendPostResponse(request))
329                 {
330                     ehResult = OC_EH_OK;
331                 }
332             }
333             else if(requestType == "DELETE")
334             {
335                 // DELETE request operations
336             }
337         }
338
339         if(requestFlag & RequestHandlerFlag::ObserverFlag)
340         {
341             ObservationInfo observationInfo = request->getObservationInfo();
342             if(ObserveAction::ObserveRegister == observationInfo.action)
343             {
344                 m_interestedObservers.push_back(observationInfo.obsId);
345             }
346             else if(ObserveAction::ObserveUnregister == observationInfo.action)
347             {
348                 m_interestedObservers.erase(std::remove(
349                                                             m_interestedObservers.begin(),
350                                                             m_interestedObservers.end(),
351                                                             observationInfo.obsId),
352                                                             m_interestedObservers.end());
353             }
354
355             pthread_t threadId;
356
357             cout << "\t\trequestFlag : Observer\n";
358             gObservation = 1;
359             static int startedThread = 0;
360
361             // Observation happens on a different thread in ChangeLightRepresentation function.
362             // If we have not created the thread already, we will create one here.
363             if(!startedThread)
364             {
365                 pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)this);
366                 startedThread = 1;
367             }
368             ehResult = OC_EH_OK;
369         }
370     }
371     else
372     {
373         std::cout << "Request invalid" << std::endl;
374     }
375
376     return ehResult;
377 }
378
379 };
380
381 // ChangeLightRepresentaion is an observation function,
382 // which notifies any changes to the resource to stack
383 // via notifyObservers
384 void * ChangeLightRepresentation (void *param)
385 {
386     LightResource* lightPtr = (LightResource*) param;
387
388     // This function continuously monitors for the changes
389     while (1)
390     {
391         sleep (3);
392
393         if (gObservation)
394         {
395             // If under observation if there are any changes to the light resource
396             // we call notifyObservors
397             //
398             // For demostration we are changing the power value and notifying.
399             lightPtr->m_power += 10;
400
401             cout << "\nPower updated to : " << lightPtr->m_power << endl;
402             cout << "Notifying observers with resource handle: " << lightPtr->getHandle() << endl;
403
404             OCStackResult result = OC_STACK_OK;
405
406             if(isListOfObservers)
407             {
408                 std::shared_ptr<OCResourceResponse> resourceResponse =
409                             std::make_shared<OCResourceResponse>();
410
411                 resourceResponse->setResourceRepresentation(lightPtr->get(), DEFAULT_INTERFACE);
412
413                 result = OCPlatform::notifyListOfObservers(
414                                                             lightPtr->getHandle(),
415                                                             lightPtr->m_interestedObservers,
416                                                             resourceResponse,
417                                                             OC::QualityOfService::HighQos);
418             }
419             else
420             {
421                 result = OCPlatform::notifyAllObservers(lightPtr->getHandle(),
422                                                             OC::QualityOfService::HighQos);
423             }
424
425             if(OC_STACK_NO_OBSERVERS == result)
426             {
427                 cout << "No More observers, stopping notifications" << endl;
428                 gObservation = 0;
429             }
430         }
431     }
432
433     return NULL;
434 }
435
436 void DeletePlatformInfo()
437 {
438     delete[] platformInfo.platformID;
439     delete[] platformInfo.manufacturerName;
440     delete[] platformInfo.manufacturerUrl;
441     delete[] platformInfo.modelNumber;
442     delete[] platformInfo.dateOfManufacture;
443     delete[] platformInfo.platformVersion;
444     delete[] platformInfo.operatingSystemVersion;
445     delete[] platformInfo.hardwareVersion;
446     delete[] platformInfo.firmwareVersion;
447     delete[] platformInfo.supportUrl;
448     delete[] platformInfo.systemTime;
449 }
450
451 void DuplicateString(char ** targetString, std::string sourceString)
452 {
453     *targetString = new char[sourceString.length() + 1];
454     strncpy(*targetString, sourceString.c_str(), (sourceString.length() + 1));
455 }
456
457 OCStackResult SetPlatformInfo(std::string platformID, std::string manufacturerName,
458         std::string manufacturerUrl, std::string modelNumber, std::string dateOfManufacture,
459         std::string platformVersion, std::string operatingSystemVersion,
460         std::string hardwareVersion, std::string firmwareVersion, std::string supportUrl,
461         std::string systemTime)
462 {
463     DuplicateString(&platformInfo.platformID, platformID);
464     DuplicateString(&platformInfo.manufacturerName, manufacturerName);
465     DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl);
466     DuplicateString(&platformInfo.modelNumber, modelNumber);
467     DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture);
468     DuplicateString(&platformInfo.platformVersion, platformVersion);
469     DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion);
470     DuplicateString(&platformInfo.hardwareVersion, hardwareVersion);
471     DuplicateString(&platformInfo.firmwareVersion, firmwareVersion);
472     DuplicateString(&platformInfo.supportUrl, supportUrl);
473     DuplicateString(&platformInfo.systemTime, systemTime);
474
475     return OC_STACK_OK;
476 }
477
478 OCStackResult SetDeviceInfo()
479 {
480     OCStackResult result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME,
481                                                         deviceName);
482     if (result != OC_STACK_OK)
483     {
484         cout << "Failed to set device name" << endl;
485         return result;
486     }
487
488     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION,
489                                           dataModelVersions);
490     if (result != OC_STACK_OK)
491     {
492         cout << "Failed to set data model versions" << endl;
493         return result;
494     }
495
496     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, specVersion);
497     if (result != OC_STACK_OK)
498     {
499         cout << "Failed to set spec version" << endl;
500         return result;
501     }
502
503     return OC_STACK_OK;
504 }
505
506 void PrintUsage()
507 {
508     std::cout << std::endl;
509     std::cout << "Usage : simpleserverHQ <ObserveType>\n";
510     std::cout << "   ObserveType : 0 - Observe All\n";
511     std::cout << "   ObserveType : 1 - Observe List of observers\n\n";
512 }
513
514
515 int main(int argc, char* argv[])
516 {
517     PrintUsage();
518
519     if (argc == 1)
520     {
521         isListOfObservers = 0;
522     }
523     else if (argc == 2)
524     {
525         int value = atoi(argv[1]);
526         if (value == 1)
527             isListOfObservers = 1;
528         else
529             isListOfObservers = 0;
530     }
531     else
532     {
533         return -1;
534     }
535
536     // Create PlatformConfig object
537     PlatformConfig cfg {
538         OC::ServiceType::InProc,
539         OC::ModeType::Server,
540         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
541         0,         // Uses randomly available port
542         OC::QualityOfService::LowQos
543     };
544
545     OCPlatform::Configure(cfg);
546     std::cout << "Starting server & setting platform info\n";
547
548     OCStackResult result = SetPlatformInfo(platformId, manufacturerName, manufacturerLink,
549             modelNumber, dateOfManufacture, platformVersion, operatingSystemVersion,
550             hardwareVersion, firmwareVersion, supportLink, systemTime);
551
552     result = OCPlatform::registerPlatformInfo(platformInfo);
553
554     if (result != OC_STACK_OK)
555     {
556         std::cout << "Platform Registration failed\n";
557         return -1;
558     }
559
560     result = SetDeviceInfo();
561     if (result != OC_STACK_OK)
562     {
563         std::cout << "Device Registration failed\n";
564         return -1;
565     }
566
567     try
568     {
569         // Create the instance of the resource class
570         // (in this case instance of class 'LightResource').
571         LightResource myLight(cfg);
572
573         // Invoke createResource function of class light.
574         myLight.createResource();
575
576         myLight.addType(std::string("core.brightlight"));
577         myLight.addInterface(std::string(LINK_INTERFACE));
578
579         DeletePlatformInfo();
580
581         // A condition variable will free the mutex it is given, then do a non-
582         // intensive block until 'notify' is called on it.  In this case, since we
583         // don't ever call cv.notify, this should be a non-processor intensive version
584         // of while(true);
585         std::mutex blocker;
586         std::condition_variable cv;
587         std::unique_lock<std::mutex> lock(blocker);
588         cv.wait(lock, []{return false;});
589     }
590     catch(OCException& e)
591     {
592         oclog() << "Exception in main: "<< e.what();
593     }
594
595     // No explicit call to stop the platform.
596     // When OCPlatform destructor is invoked, internally we do platform cleanup
597
598     return 0;
599 }
600