Deprecate OCSetDeviceInfo and registerDeviceInfo
[platform/upstream/iotivity.git] / resource / examples / lightserver.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 // Copyright 2014 Samsung Electronics All Rights Reserved.
5 //
6 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 //
12 //      http://www.apache.org/licenses/LICENSE-2.0
13 //
14 // Unless required by applicable law or agreed to in writing, software
15 // distributed under the License is distributed on an "AS IS" BASIS,
16 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 // See the License for the specific language governing permissions and
18 // limitations under the License.
19 //
20 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21
22 ///
23 /// This sample provides steps to define an interface for a resource
24 /// (properties and methods) and host this resource on the server.
25 ///
26 #include "iotivity_config.h"
27
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <functional>
32
33 #include <pthread.h>
34 #include <mutex>
35 #include <condition_variable>
36
37 #include "OCPlatform.h"
38 #include "OCApi.h"
39 #include "ocpayload.h"
40
41 using namespace OC;
42 using namespace std;
43 namespace PH = std::placeholders;
44
45 int gObservation = 0;
46 void * ChangeLightRepresentation (void *param);
47 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest);
48
49 // Set of strings for each of platform Info fields
50 std::string  platformId = "0A3E0D6F-DBF5-404E-8719-D6880042463A";
51 std::string  manufacturerName = "OCF";
52 std::string  manufacturerLink = "https://www.iotivity.org";
53 std::string  modelNumber = "myModelNumber";
54 std::string  dateOfManufacture = "2016-01-15";
55 std::string  platformVersion = "myPlatformVersion";
56 std::string  operatingSystemVersion = "myOS";
57 std::string  hardwareVersion = "myHardwareVersion";
58 std::string  firmwareVersion = "1.0";
59 std::string  supportLink = "https://www.iotivity.org";
60 std::string  systemTime = "2016-01-15T11.01";
61
62 // Set of strings for each of device info fields
63 std::string  deviceName = "IoTivity Light Server";
64 std::string  specVersion = "core.1.1.0";
65 std::vector<std::string> dataModelVersions = {"res.1.1.0"};
66
67 // OCPlatformInfo Contains all the platform info to be stored
68 OCPlatformInfo platformInfo;
69
70 // Specifies secure or non-secure
71 // false: non-secure resource
72 // true: secure resource
73 bool isSecure = false;
74
75 /// Specifies whether Entity handler is going to do slow response or not
76 bool isSlowResponse = false;
77
78 // Forward declaring the entityHandler
79
80 /// This class represents a single resource named 'lightResource'. This resource has
81 /// one simple attribute, power
82
83 class LightResource
84 {
85
86 public:
87     /// Access this property from a TB client
88     std::string m_power;
89     std::string m_lightUri;
90     OCResourceHandle m_resourceHandle;
91     OCRepresentation m_lightRep;
92
93 public:
94     /// Constructor
95     LightResource()
96         :m_power(""), m_lightUri("/a/light") {
97         // Initialize representation
98         m_lightRep.setUri(m_lightUri);
99
100         m_lightRep.setValue("power", m_power);
101     }
102
103     /* Note that this does not need to be a member function: for classes you do not have
104     access to, you can accomplish this with a free function: */
105
106     /// This function internally calls registerResource API.
107     void createResource()
108     {
109         std::string resourceURI = m_lightUri; //URI of the resource
110         std::string resourceTypeName = "core.light"; //resource type name. In this case, it is light
111         std::string resourceInterface = DEFAULT_INTERFACE; // resource interface.
112
113         EntityHandler cb = std::bind(&LightResource::entityHandler, this,PH::_1);
114
115         // This will internally create and register the resource.
116         OCStackResult result = OCPlatform::registerResource(
117                                     m_resourceHandle, resourceURI, resourceTypeName,
118                                     resourceInterface, cb, OC_DISCOVERABLE | OC_OBSERVABLE);
119
120         if (OC_STACK_OK != result)
121         {
122             cout << "Resource creation was unsuccessful\n";
123         }
124     }
125
126     OCResourceHandle getHandle()
127     {
128         return m_resourceHandle;
129     }
130
131     // Puts representation.
132     // Gets values from the representation and
133     // updates the internal state
134     void put(OCRepresentation& rep)
135     {
136         try {
137             if (rep.getValue("power", m_power))
138             {
139                 cout << "\t\t\t\t" << "power: " << m_power << endl;
140             }
141             else
142             {
143                 cout << "\t\t\t\t" << "power not found in the representation" << endl;
144             }
145         }
146         catch (exception& e)
147         {
148             cout << e.what() << endl;
149         }
150
151     }
152
153     // Post representation.
154     // Post can create new resource or simply act like put.
155     // Gets values from the representation and
156     // updates the internal state
157     OCRepresentation post(OCRepresentation& rep)
158     {
159         put(rep);
160         return get();
161     }
162
163
164     // gets the updated representation.
165     // Updates the representation with latest internal state before
166     // sending out.
167     OCRepresentation get()
168     {
169         m_lightRep.setValue("power", m_power);
170
171         return m_lightRep;
172     }
173
174     void addType(const std::string& type) const
175     {
176         OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type);
177         if (OC_STACK_OK != result)
178         {
179             cout << "Binding TypeName to Resource was unsuccessful\n";
180         }
181     }
182
183     void addInterface(const std::string& interface) const
184     {
185         OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, interface);
186         if (OC_STACK_OK != result)
187         {
188             cout << "Binding TypeName to Resource was unsuccessful\n";
189         }
190     }
191
192 private:
193 // This is just a sample implementation of entity handler.
194 // Entity handler can be implemented in several ways by the manufacturer
195 OCEntityHandlerResult entityHandler(std::shared_ptr<OCResourceRequest> request)
196 {
197     cout << "\tIn Server CPP entity handler:\n";
198     OCEntityHandlerResult ehResult = OC_EH_ERROR;
199     if(request)
200     {
201         // Get the request type and request flag
202         std::string requestType = request->getRequestType();
203         int requestFlag = request->getRequestHandlerFlag();
204
205         if(requestFlag & RequestHandlerFlag::RequestFlag)
206         {
207             cout << "\t\trequestFlag : Request\n";
208             auto pResponse = std::make_shared<OC::OCResourceResponse>();
209             pResponse->setRequestHandle(request->getRequestHandle());
210             pResponse->setResourceHandle(request->getResourceHandle());
211
212             // If the request type is GET
213             if(requestType == "GET")
214             {
215                 cout << "\t\t\trequestType : GET\n";
216                 if(isSlowResponse) // Slow response case
217                 {
218                     static int startedThread = 0;
219                     if(!startedThread)
220                     {
221                         std::thread t(handleSlowResponse, (void *)this, request);
222                         startedThread = 1;
223                         t.detach();
224                     }
225                     ehResult = OC_EH_SLOW;
226                 }
227                 else // normal response case.
228                 {
229
230                     pResponse->setResponseResult(OC_EH_OK);
231                     pResponse->setResourceRepresentation(get());
232                     if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
233                     {
234                         ehResult = OC_EH_OK;
235                     }
236                 }
237             }
238             else if(requestType == "PUT")
239             {
240                 cout << "\t\t\trequestType : PUT\n";
241                 OCRepresentation rep = request->getResourceRepresentation();
242
243                 // Do related operations related to PUT request
244                 // Update the lightResource
245                 put(rep);
246
247                 pResponse->setResponseResult(OC_EH_OK);
248                 pResponse->setResourceRepresentation(get());
249                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
250                 {
251                     ehResult = OC_EH_OK;
252                 }
253             }
254             else if(requestType == "POST")
255             {
256                 cout << "\t\t\trequestType : POST\n";
257
258                 OCRepresentation rep = request->getResourceRepresentation();
259
260                 // Do related operations related to POST request
261                 OCRepresentation rep_post = post(rep);
262                 pResponse->setResourceRepresentation(rep_post);
263
264                 if(rep_post.hasAttribute("createduri"))
265                 {
266                     pResponse->setResponseResult(OC_EH_RESOURCE_CREATED);
267                     pResponse->setNewResourceUri(rep_post.getValue<std::string>("createduri"));
268                 }
269
270                 if(OC_STACK_OK == OCPlatform::sendResponse(pResponse))
271                 {
272                     ehResult = OC_EH_OK;
273                 }
274             }
275             else if(requestType == "DELETE")
276             {
277                 // DELETE request operations
278             }
279         }
280     }
281     else
282     {
283         std::cout << "Request invalid" << std::endl;
284     }
285
286     return ehResult;
287 }
288 };
289
290 void * handleSlowResponse (void *param, std::shared_ptr<OCResourceRequest> pRequest)
291 {
292     // This function handles slow response case
293     LightResource* lightPtr = (LightResource*) param;
294     // Induce a case for slow response by using sleep
295     std::cout << "SLOW response" << std::endl;
296     sleep (10);
297
298     auto pResponse = std::make_shared<OC::OCResourceResponse>();
299     pResponse->setRequestHandle(pRequest->getRequestHandle());
300     pResponse->setResourceHandle(pRequest->getResourceHandle());
301     pResponse->setResourceRepresentation(lightPtr->get());
302
303     pResponse->setResponseResult(OC_EH_OK);
304
305     // Set the slow response flag back to false
306     isSlowResponse = false;
307     OCPlatform::sendResponse(pResponse);
308     return NULL;
309 }
310
311 void DeletePlatformInfo()
312 {
313     delete[] platformInfo.platformID;
314     delete[] platformInfo.manufacturerName;
315     delete[] platformInfo.manufacturerUrl;
316     delete[] platformInfo.modelNumber;
317     delete[] platformInfo.dateOfManufacture;
318     delete[] platformInfo.platformVersion;
319     delete[] platformInfo.operatingSystemVersion;
320     delete[] platformInfo.hardwareVersion;
321     delete[] platformInfo.firmwareVersion;
322     delete[] platformInfo.supportUrl;
323     delete[] platformInfo.systemTime;
324 }
325
326 void DuplicateString(char ** targetString, std::string sourceString)
327 {
328     *targetString = new char[sourceString.length() + 1];
329     strncpy(*targetString, sourceString.c_str(), (sourceString.length() + 1));
330 }
331
332 OCStackResult SetPlatformInfo(std::string platformID, std::string manufacturerName,
333         std::string manufacturerUrl, std::string modelNumber, std::string dateOfManufacture,
334         std::string platformVersion, std::string operatingSystemVersion,
335         std::string hardwareVersion, std::string firmwareVersion, std::string supportUrl,
336         std::string systemTime)
337 {
338     DuplicateString(&platformInfo.platformID, platformID);
339     DuplicateString(&platformInfo.manufacturerName, manufacturerName);
340     DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl);
341     DuplicateString(&platformInfo.modelNumber, modelNumber);
342     DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture);
343     DuplicateString(&platformInfo.platformVersion, platformVersion);
344     DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion);
345     DuplicateString(&platformInfo.hardwareVersion, hardwareVersion);
346     DuplicateString(&platformInfo.firmwareVersion, firmwareVersion);
347     DuplicateString(&platformInfo.supportUrl, supportUrl);
348     DuplicateString(&platformInfo.systemTime, systemTime);
349
350     return OC_STACK_OK;
351 }
352
353 OCStackResult SetDeviceInfo()
354 {
355     OCStackResult result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DEVICE_NAME,
356                                                         deviceName);
357     if (result != OC_STACK_OK)
358     {
359         cout << "Failed to set device name" << endl;
360         return result;
361     }
362
363     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_DATA_MODEL_VERSION,
364                                           dataModelVersions);
365     if (result != OC_STACK_OK)
366     {
367         cout << "Failed to set data model versions" << endl;
368         return result;
369     }
370
371     result = OCPlatform::setPropertyValue(PAYLOAD_TYPE_DEVICE, OC_RSRVD_SPEC_VERSION, specVersion);
372     if (result != OC_STACK_OK)
373     {
374         cout << "Failed to set spec version" << endl;
375         return result;
376     }
377
378     return OC_STACK_OK;
379 }
380
381 int main(int /*argc*/, char** /*argv[]*/)
382 {
383     // Create PlatformConfig object
384     PlatformConfig cfg {
385         OC::ServiceType::InProc,
386         OC::ModeType::Server,
387         "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces
388         0,         // Uses randomly available port
389         OC::QualityOfService::LowQos
390     };
391
392     OCPlatform::Configure(cfg);
393     std::cout << "Starting server & setting platform info\n";
394
395     OCStackResult result = SetPlatformInfo(platformId, manufacturerName, manufacturerLink,
396             modelNumber, dateOfManufacture, platformVersion, operatingSystemVersion,
397             hardwareVersion, firmwareVersion, supportLink, systemTime);
398
399     result = OCPlatform::registerPlatformInfo(platformInfo);
400
401     if (result != OC_STACK_OK)
402     {
403         std::cout << "Platform Registration failed\n";
404         return -1;
405     }
406
407     result = SetDeviceInfo();
408
409     if (result != OC_STACK_OK)
410     {
411         std::cout << "Device Registration failed\n";
412         return -1;
413     }
414
415     try
416     {
417         // Create the instance of the resource class
418         // (in this case instance of class 'LightResource').
419         LightResource myLight;
420
421         // Invoke createResource function of class light.
422         myLight.createResource();
423
424         myLight.addType(std::string("core.brightlight"));
425         myLight.addInterface(std::string(LINK_INTERFACE));
426
427         DeletePlatformInfo();
428
429         // A condition variable will free the mutex it is given, then do a non-
430         // intensive block until 'notify' is called on it.  In this case, since we
431         // don't ever call cv.notify, this should be a non-processor intensive version
432         // of while(true);
433         std::mutex blocker;
434         std::condition_variable cv;
435         std::unique_lock<std::mutex> lock(blocker);
436         cv.wait(lock);
437     }
438     catch(OCException& e)
439     {
440        oclog() << "Exception in main: "<< e.what();
441     }
442
443     // No explicit call to stop the platform.
444     // When OCPlatform::destructor is invoked, internally we do platform cleanup
445
446     return 0;
447 }
448