1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
35 //string length of "/a/light/" + std::numeric_limits<int>::digits10 + '\0'"
37 const int URI_MAXSIZE = 19;
39 static int gObserveNotifyType = 3;
42 int gLightUnderObservation = 0;
44 static LightResource Light;
45 // This variable determines instance number of the Light resource.
46 // Used by POST method to create a new instance of Light resource.
47 static int gCurrLightInstance = 0;
49 static LightResource gLightInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
51 Observers interestedObservers[SAMPLE_MAX_NUM_OBSERVATIONS];
54 static int stopPresenceCount = 10;
55 #define numPresenceResources (2)
58 //TODO: Follow the pattern used in constructJsonResponse() when the payload is decided.
59 const char responsePayloadDeleteOk[] =
60 "{App determines payload: Delete Resource operation succeeded.}";
61 const char responsePayloadDeleteNotOK[] =
62 "{App determines payload: Delete Resource operation failed.}";
63 const char responsePayloadResourceDoesNotExist[] =
64 "{App determines payload: The resource does not exist.}";
65 const char responsePayloadDeleteResourceNotSupported[] =
66 "{App determines payload: The request is received for a non-support resource.}";
69 char *gResourceUri= (char *)"/a/light";
70 const char *contentType = "myContentType";
71 const char *dateOfManufacture = "myDateOfManufacture";
72 const char *deviceName = "myDeviceName";
73 const char *deviceUUID = "myDeviceUUID";
74 const char *firmwareVersion = "myFirmwareVersion";
75 const char *hostName = "myHostName";
76 const char *manufacturerName = "myManufacturerNa";
77 const char *manufacturerUrl = "myManufacturerUrl";
78 const char *modelNumber = "myModelNumber";
79 const char *platformVersion = "myPlatformVersion";
80 const char *supportUrl = "mySupportUrl";
81 const char *version = "myVersion";
83 OCDeviceInfo deviceInfo;
85 //This function takes the request as an input and returns the response
87 char* constructJsonResponse (OCEntityHandlerRequest *ehRequest)
89 cJSON *json = cJSON_CreateObject();
92 LightResource *currLightResource = &Light;
94 if (ehRequest->resource == gLightInstance[0].handle)
96 currLightResource = &gLightInstance[0];
97 gResourceUri = (char *) "a/light/0";
99 else if (ehRequest->resource == gLightInstance[1].handle)
101 currLightResource = &gLightInstance[1];
102 gResourceUri = (char *) "a/light/1";
105 if(OC_REST_PUT == ehRequest->method)
107 // Get cJSON pointer to query
108 cJSON *putJson = cJSON_Parse((char *)ehRequest->reqJSONPayload);
110 // Get root of JSON payload, then the 1st resource.
111 cJSON* carrier = cJSON_GetObjectItem(putJson, "oc");
112 carrier = cJSON_GetArrayItem(carrier, 0);
113 carrier = cJSON_GetObjectItem(carrier, "rep");
115 cJSON* prop = cJSON_GetObjectItem(carrier,"power");
118 currLightResource->power =prop->valueint;
121 prop = cJSON_GetObjectItem(carrier,"state");
124 currLightResource->state = prop->valueint;
127 cJSON_Delete(putJson);
130 cJSON_AddStringToObject(json,"href",gResourceUri);
131 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
132 cJSON_AddBoolToObject(format, "state", currLightResource->state);
133 cJSON_AddNumberToObject(format, "power", currLightResource->power);
135 jsonResponse = cJSON_Print(json);
142 * Very simple example of query parsing.
143 * The query may have multiple filters separated by '&'.
144 * It is upto the entity handler to parse the query for the individual filters,
145 * VALIDATE them and respond as it sees fit.
147 * This function only returns false if the query is exactly "power<X" and
148 * current power is greater than X. If X cannot be parsed for an int,
151 bool checkIfQueryForPowerPassed(char * query)
153 if (query && strcmp(query, "power<") == 0)
155 char * pointerToOperator = strstr(query, "<");
157 if (pointerToOperator)
159 int powerRequested = atoi(pointerToOperator + 1);
161 if (Light.power > powerRequested)
163 OC_LOG_V(INFO, TAG, "Current power: %d. Requested: <%d", Light.power
172 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
173 char *payload, uint16_t maxPayloadSize)
175 OCEntityHandlerResult ehResult;
177 bool queryPassed = checkIfQueryForPowerPassed(ehRequest->query);
179 // Empty payload if the query has no match.
182 char *getResp = constructJsonResponse(ehRequest);
184 if (maxPayloadSize > strlen ((char *)getResp))
186 strncpy(payload, getResp, strlen((char *)getResp));
191 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
193 ehResult = OC_EH_ERROR;
206 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
207 char *payload, uint16_t maxPayloadSize)
209 OCEntityHandlerResult ehResult;
210 char *putResp = constructJsonResponse(ehRequest);
212 if (maxPayloadSize > strlen ((char *)putResp))
214 strncpy(payload, putResp, strlen((char *)putResp));
219 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
221 ehResult = OC_EH_ERROR;
229 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
230 OCEntityHandlerResponse *response, char *payload, uint16_t maxPayloadSize)
232 OCEntityHandlerResult ehResult = OC_EH_OK;
233 char *respPLPost_light = NULL;
238 * The entity handler determines how to process a POST request.
239 * Per the REST paradigm, POST can also be used to update representation of existing
240 * resource or create a new resource.
241 * In the sample below, if the POST is for /a/light then a new instance of the Light
242 * resource is created with default representation (if representation is included in
243 * POST payload it can be used as initial values) as long as the instance is
244 * lesser than max new instance count. Once max instance count is reached, POST on
245 * /a/light updated the representation of /a/light (just like PUT)
248 if (ehRequest->resource == Light.handle)
250 if (gCurrLightInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
252 // Create new Light instance
253 char newLightUri[URI_MAXSIZE];
254 snprintf(newLightUri, URI_MAXSIZE, "/a/light/%d", gCurrLightInstance);
256 json = cJSON_CreateObject();
257 cJSON_AddStringToObject(json,"href",gResourceUri);
258 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
259 cJSON_AddStringToObject(format, "createduri", (char *) newLightUri);
261 if (0 == createLightResource (newLightUri, &gLightInstance[gCurrLightInstance]))
263 OC_LOG (INFO, TAG, "Created new Light instance\n");
264 gLightInstance[gCurrLightInstance].state = 0;
265 gLightInstance[gCurrLightInstance].power = 0;
266 gCurrLightInstance++;
267 respPLPost_light = cJSON_Print(json);
268 strncpy ((char *)response->resourceUri, newLightUri, MAX_URI_LENGTH);
269 ehResult = OC_EH_RESOURCE_CREATED;
276 // Update repesentation of /a/light
279 respPLPost_light = constructJsonResponse(ehRequest);
284 for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
286 if (ehRequest->resource == gLightInstance[i].handle)
288 gLightInstance[i].state = true;
289 gLightInstance[i].power = 22;
292 respPLPost_light = constructJsonResponse(ehRequest);
297 respPLPost_light = constructJsonResponse(ehRequest);
303 if ((respPLPost_light != NULL) && (maxPayloadSize > strlen ((char *)respPLPost_light)))
305 strncpy(payload, respPLPost_light, strlen((char *)respPLPost_light));
309 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
311 ehResult = OC_EH_ERROR;
314 free(respPLPost_light);
318 OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest,
319 char *payload, uint16_t maxPayloadSize)
321 if(ehRequest == NULL)
323 OC_LOG(INFO, TAG, "The ehRequest is NULL");
326 OCEntityHandlerResult ehResult = OC_EH_OK;
328 OC_LOG_V(INFO, TAG, "\n\nExecuting %s for resource %d ", __func__, ehRequest->resource);
331 * In the sample below, the application will:
332 * 1a. pass the delete request to the c stack
333 * 1b. internally, the c stack figures out what needs to be done and does it accordingly
334 * (e.g. send observers notification, remove observers...)
335 * 1c. the c stack returns with the result whether the request is fullfilled.
336 * 2. optionally, app removes observers out of its array 'interestedObservers'
339 const char* deleteResponse = NULL;
341 if ((ehRequest != NULL) && (ehRequest->resource == Light.handle))
343 //Step 1: Ask stack to do the work.
344 OCStackResult result = OCDeleteResource(ehRequest->resource);
346 if (result == OC_STACK_OK)
348 OC_LOG (INFO, TAG, "\n\nDelete Resource operation succeeded.");
350 deleteResponse = responsePayloadDeleteOk;
352 //Step 2: clear observers who wanted to observe this resource at the app level.
353 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
355 if (interestedObservers[i].resourceHandle == ehRequest->resource)
357 interestedObservers[i].valid = false;
358 interestedObservers[i].observationId = 0;
359 interestedObservers[i].resourceHandle = NULL;
363 else if (result == OC_STACK_NO_RESOURCE)
365 OC_LOG(INFO, TAG, "\n\nThe resource doesn't exist or it might have been deleted.");
366 deleteResponse = responsePayloadResourceDoesNotExist;
367 ehResult = OC_EH_RESOURCE_DELETED;
371 OC_LOG(INFO, TAG, "\n\nEncountered error from OCDeleteResource().");
372 deleteResponse = responsePayloadDeleteNotOK;
373 ehResult = OC_EH_ERROR;
376 else if (ehRequest->resource != Light.handle)
378 //Let's this app not supporting DELETE on some resources so
379 //consider the DELETE request is received for a non-support resource.
380 OC_LOG_V(INFO, TAG, "\n\nThe request is received for a non-support resource.");
381 deleteResponse = responsePayloadDeleteResourceNotSupported;
382 ehResult = OC_EH_FORBIDDEN;
385 if (maxPayloadSize > strlen ((char *)deleteResponse))
387 strncpy(payload, deleteResponse, strlen((char *)deleteResponse));
391 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
393 ehResult = OC_EH_ERROR;
399 OCEntityHandlerResult ProcessNonExistingResourceRequest(OCEntityHandlerRequest *ehRequest,
400 char *payload, uint16_t maxPayloadSize)
402 OC_LOG_V(INFO, TAG, "\n\nExecuting %s ", __func__);
404 const char* response = NULL;
405 response = responsePayloadResourceDoesNotExist;
407 if ( (ehRequest != NULL) &&
408 (maxPayloadSize > strlen ((char *)response)) )
410 strncpy((char *)payload, response, strlen((char *)response));
414 OC_LOG_V (ERROR, TAG, "Response buffer: %d bytes is too small",
418 return OC_EH_RESOURCE_NOT_FOUND;
421 void ProcessObserveRegister (OCEntityHandlerRequest *ehRequest)
423 OC_LOG_V (INFO, TAG, "Received observation registration request with observation Id %d",
424 ehRequest->obsInfo.obsId);
425 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
427 if (interestedObservers[i].valid == false)
429 interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
430 interestedObservers[i].valid = true;
431 gLightUnderObservation = 1;
437 void ProcessObserveDeregister (OCEntityHandlerRequest *ehRequest)
439 bool clientStillObserving = false;
441 OC_LOG_V (INFO, TAG, "Received observation deregistration request for observation Id %d",
442 ehRequest->obsInfo.obsId);
443 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
445 if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
447 interestedObservers[i].valid = false;
449 if (interestedObservers[i].valid == true)
451 // Even if there is one single client observing we continue notifying entity handler
452 clientStillObserving = true;
455 if (clientStillObserving == false)
456 gLightUnderObservation = 0;
459 OCEntityHandlerResult
460 OCDeviceEntityHandlerCb (OCEntityHandlerFlag flag,
461 OCEntityHandlerRequest *entityHandlerRequest, char* uri)
463 OC_LOG_V (INFO, TAG, "Inside device default entity handler - flags: 0x%x, uri: %s", flag, uri);
465 OCEntityHandlerResult ehResult = OC_EH_OK;
466 OCEntityHandlerResponse response;
467 char payload[MAX_RESPONSE_LENGTH] = {0};
470 if (!entityHandlerRequest)
472 OC_LOG (ERROR, TAG, "Invalid request pointer");
476 // Initialize certain response fields
477 response.numSendVendorSpecificHeaderOptions = 0;
478 memset(response.sendVendorSpecificHeaderOptions, 0,
479 sizeof response.sendVendorSpecificHeaderOptions);
480 memset(response.resourceUri, 0, sizeof response.resourceUri);
482 if (flag & OC_INIT_FLAG)
484 OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
486 if (flag & OC_REQUEST_FLAG)
488 OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
489 if (entityHandlerRequest->resource == NULL)
491 OC_LOG (INFO, TAG, "Received request from client to a non-existing resource");
492 ehResult = ProcessNonExistingResourceRequest(entityHandlerRequest,
493 payload, sizeof(payload) - 1);
495 else if (OC_REST_GET == entityHandlerRequest->method)
497 OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
498 ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
500 else if (OC_REST_PUT == entityHandlerRequest->method)
502 OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
503 ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
505 else if (OC_REST_DELETE == entityHandlerRequest->method)
507 OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
508 ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
512 OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
513 entityHandlerRequest->method);
514 ehResult = OC_EH_ERROR;
517 // If the result isn't an error or forbidden, send response
518 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
520 // Format the response. Note this requires some info about the request
521 response.requestHandle = entityHandlerRequest->requestHandle;
522 response.resourceHandle = entityHandlerRequest->resource;
523 response.ehResult = ehResult;
524 response.payload = payload;
525 response.payloadSize = strlen(payload);
526 // Indicate that response is NOT in a persistent buffer
527 response.persistentBufferFlag = 0;
530 if (OCDoResponse(&response) != OC_STACK_OK)
532 OC_LOG(ERROR, TAG, "Error sending response");
533 ehResult = OC_EH_ERROR;
537 if (flag & OC_OBSERVE_FLAG)
539 OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
540 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
542 OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
544 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
546 OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
553 OCEntityHandlerResult
554 OCNOPEntityHandlerCb (OCEntityHandlerFlag flag,
555 OCEntityHandlerRequest *entityHandlerRequest)
557 // This is callback is associated with the 2 presence notification
558 // resources. They are non-operational.
562 OCEntityHandlerResult
563 OCEntityHandlerCb (OCEntityHandlerFlag flag,
564 OCEntityHandlerRequest *entityHandlerRequest)
566 OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
568 OCEntityHandlerResult ehResult = OC_EH_OK;
569 OCEntityHandlerResponse response;
570 char payload[MAX_RESPONSE_LENGTH] = {0};
573 if (!entityHandlerRequest)
575 OC_LOG (ERROR, TAG, "Invalid request pointer");
579 // Initialize certain response fields
580 response.numSendVendorSpecificHeaderOptions = 0;
581 memset(response.sendVendorSpecificHeaderOptions,
582 0, sizeof response.sendVendorSpecificHeaderOptions);
583 memset(response.resourceUri, 0, sizeof response.resourceUri);
585 if (flag & OC_INIT_FLAG)
587 OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
589 if (flag & OC_REQUEST_FLAG)
591 OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
592 if (OC_REST_GET == entityHandlerRequest->method)
594 OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
595 ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
597 else if (OC_REST_PUT == entityHandlerRequest->method)
599 OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
600 ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
602 else if (OC_REST_POST == entityHandlerRequest->method)
604 OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
605 ehResult = ProcessPostRequest (entityHandlerRequest,
606 &response, payload, sizeof(payload) - 1);
608 else if (OC_REST_DELETE == entityHandlerRequest->method)
610 OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
611 ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
615 OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
616 entityHandlerRequest->method);
619 // If the result isn't an error or forbidden, send response
620 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
622 // Format the response. Note this requires some info about the request
623 response.requestHandle = entityHandlerRequest->requestHandle;
624 response.resourceHandle = entityHandlerRequest->resource;
625 response.ehResult = ehResult;
626 response.payload = payload;
627 response.payloadSize = strlen(payload);
628 // Indicate that response is NOT in a persistent buffer
629 response.persistentBufferFlag = 0;
631 // Handle vendor specific options
632 if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
633 entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
635 OC_LOG (INFO, TAG, "Received vendor specific options");
637 OCHeaderOption * rcvdOptions =
638 entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
639 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
641 if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
643 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
644 ((OCHeaderOption)rcvdOptions[i]).optionID );
646 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
647 MAX_HEADER_OPTION_DATA_LENGTH);
650 OCHeaderOption * sendOptions = response.sendVendorSpecificHeaderOptions;
651 uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
652 uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
653 sendOptions[0].protocolID = OC_COAP_ID;
654 sendOptions[0].optionID = 2248;
655 memcpy(sendOptions[0].optionData, option2, sizeof(option2));
656 sendOptions[0].optionLength = 10;
657 sendOptions[1].protocolID = OC_COAP_ID;
658 sendOptions[1].optionID = 2600;
659 memcpy(sendOptions[1].optionData, option3, sizeof(option3));
660 sendOptions[1].optionLength = 10;
661 response.numSendVendorSpecificHeaderOptions = 2;
665 if (OCDoResponse(&response) != OC_STACK_OK)
667 OC_LOG(ERROR, TAG, "Error sending response");
668 ehResult = OC_EH_ERROR;
672 if (flag & OC_OBSERVE_FLAG)
674 OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
676 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
678 OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
679 ProcessObserveRegister (entityHandlerRequest);
681 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
683 OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
684 ProcessObserveDeregister (entityHandlerRequest);
691 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
692 void handleSigInt(int signum)
694 if (signum == SIGINT)
700 void *ChangeLightRepresentation (void *param)
703 OCStackResult result = OC_STACK_ERROR;
706 uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
707 OCObservationId obsNotify[numNotifies];
713 if (gLightUnderObservation)
715 OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
716 if (gObserveNotifyType == 1)
718 // Notify list of observers. Alternate observers on the list will be notified.
720 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
722 if (interestedObservers[i].valid == true)
724 obsNotify[j] = interestedObservers[i].observationId;
729 cJSON *json = cJSON_CreateObject();
731 cJSON_AddStringToObject(json,"href",gResourceUri);
732 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
733 cJSON_AddBoolToObject(format, "state", Light.state);
734 cJSON_AddNumberToObject(format, "power", Light.power);
735 char * obsResp = cJSON_Print(json);
737 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
741 else if (gObserveNotifyType == 0)
743 // Notifying all observers
744 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
745 if (OC_STACK_NO_OBSERVERS == result)
748 "=======> No more observers exist, stop sending observations");
749 gLightUnderObservation = 0;
754 OC_LOG (ERROR, TAG, "Incorrect notification type selected");
758 if(stopPresenceCount > 0)
760 OC_LOG_V(INFO, TAG, "================ Counting down to stop presence %d", stopPresenceCount);
762 if(!stopPresenceCount--)
764 OC_LOG(INFO, TAG, "================ stopping presence");
773 void *presenceNotificationGenerator(void *param)
777 OCDoHandle presenceNotificationHandles[numPresenceResources];
778 OCStackResult res = OC_STACK_OK;
780 std::array<std::string, numPresenceResources> presenceNotificationResources { {
781 std::string("core.fan"),
782 std::string("core.led") } };
783 std::array<std::string, numPresenceResources> presenceNotificationUris { {
784 std::string("/a/fan"),
785 std::string("/a/led") } };
787 for(int i=0; i<numPresenceResources; i++)
789 if(res == OC_STACK_OK)
792 res = OCCreateResource(&presenceNotificationHandles[i],
793 presenceNotificationResources.at(i).c_str(),
795 presenceNotificationUris.at(i).c_str(),
796 OCNOPEntityHandlerCb,
797 OC_DISCOVERABLE|OC_OBSERVABLE);
799 if(res != OC_STACK_OK)
801 OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to create resource "
802 "%s with result %s.", presenceNotificationResources.at(i).c_str(),
806 OC_LOG_V(INFO, TAG, PCF("Created %s for presence notification"),
807 presenceNotificationUris[i].c_str());
810 for(int i=0; i<numPresenceResources; i++)
812 if(res == OC_STACK_OK)
814 res = OCDeleteResource(presenceNotificationHandles[i]);
816 if(res != OC_STACK_OK)
818 OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to delete "\
819 "resource %s.", presenceNotificationResources.at(i).c_str());
822 OC_LOG_V(INFO, TAG, PCF("Deleted %s for presence notification"),
823 presenceNotificationUris[i].c_str());
829 static void PrintUsage()
831 OC_LOG(INFO, TAG, "Usage : ocserver -o <0|1>");
832 OC_LOG(INFO, TAG, "-o 0 : Notify all observers");
833 OC_LOG(INFO, TAG, "-o 1 : Notify list of observers");
836 int main(int argc, char* argv[])
839 pthread_t threadId_presence;
842 while ((opt = getopt(argc, argv, "o:")) != -1)
847 gObserveNotifyType = atoi(optarg);
855 if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
861 OC_LOG(DEBUG, TAG, "OCServer is starting...");
863 if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
865 OC_LOG(ERROR, TAG, "OCStack init error");
869 if (OCStartPresence(0) != OC_STACK_OK)
871 OC_LOG(ERROR, TAG, "OCStack presence/discovery error");
876 OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb);
878 OCStackResult deviceResult = SetDeviceInfo(contentType, dateOfManufacture, deviceName,
879 deviceUUID, firmwareVersion, hostName, manufacturerName,
880 manufacturerUrl, modelNumber, platformVersion, supportUrl, version);
882 if (deviceResult != OC_STACK_OK)
884 OC_LOG(INFO, TAG, "Device Registration failed!");
888 deviceResult = OCSetDeviceInfo(deviceInfo);
890 if (deviceResult != OC_STACK_OK)
892 OC_LOG(INFO, TAG, "Device Registration failed!");
897 * Declare and create the example resource: Light
899 createLightResource(gResourceUri, &Light);
901 // Initialize observations data structure for the resource
902 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
904 interestedObservers[i].valid = false;
908 * Create a thread for changing the representation of the Light
910 pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)NULL);
913 * Create a thread for generating changes that cause presence notifications
914 * to be sent to clients
918 pthread_create(&threadId_presence, NULL, presenceNotificationGenerator, (void *)NULL);
921 // Break from loop with Ctrl-C
922 OC_LOG(INFO, TAG, "Entering ocserver main loop...");
924 signal(SIGINT, handleSigInt);
927 if (OCProcess() != OC_STACK_OK)
929 OC_LOG(ERROR, TAG, "OCStack process error");
937 * Cancel the Light thread and wait for it to terminate
939 pthread_cancel(threadId);
940 pthread_join(threadId, NULL);
941 pthread_cancel(threadId_presence);
942 pthread_join(threadId_presence, NULL);
944 OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
946 if (OCStop() != OC_STACK_OK)
948 OC_LOG(ERROR, TAG, "OCStack process error");
954 int createLightResource (char *uri, LightResource *lightResource)
958 OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
962 lightResource->state = false;
963 lightResource->power= 0;
964 OCStackResult res = OCCreateResource(&(lightResource->handle),
969 OC_DISCOVERABLE|OC_OBSERVABLE);
970 OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
975 void DeleteDeviceInfo()
977 free(deviceInfo.contentType);
978 free(deviceInfo.dateOfManufacture);
979 free(deviceInfo.deviceName);
980 free(deviceInfo.deviceUUID);
981 free(deviceInfo.firmwareVersion);
982 free(deviceInfo.hostName);
983 free(deviceInfo.manufacturerName);
984 free(deviceInfo.manufacturerUrl);
985 free(deviceInfo.modelNumber);
986 free(deviceInfo.platformVersion);
987 free(deviceInfo.supportUrl);
988 free(deviceInfo.version);
991 bool DuplicateString(char** targetString, const char* sourceString)
999 *targetString = (char *) malloc(strlen(sourceString) + 1);
1003 strncpy(*targetString, sourceString, (strlen(sourceString) + 1));
1010 OCStackResult SetDeviceInfo(const char *contentType, const char *dateOfManufacture,
1011 const char *deviceName, const char *deviceUUID, const char *firmwareVersion,
1012 const char *hostName, const char *manufacturerName, const char *manufacturerUrl,
1013 const char *modelNumber, const char *platformVersion, const char *supportUrl,
1014 const char *version)
1017 bool success = true;
1019 if(manufacturerName != NULL && (strlen(manufacturerName) > MAX_MANUFACTURER_NAME_LENGTH))
1021 return OC_STACK_INVALID_PARAM;
1024 if(manufacturerUrl != NULL && (strlen(manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH))
1026 return OC_STACK_INVALID_PARAM;
1029 if(!DuplicateString(&deviceInfo.contentType, contentType))
1034 if(!DuplicateString(&deviceInfo.dateOfManufacture, dateOfManufacture))
1039 if(!DuplicateString(&deviceInfo.deviceName, deviceName))
1044 if(!DuplicateString(&deviceInfo.deviceUUID, deviceUUID))
1049 if(!DuplicateString(&deviceInfo.firmwareVersion, firmwareVersion))
1054 if(!DuplicateString(&deviceInfo.hostName, hostName))
1059 if(!DuplicateString(&deviceInfo.manufacturerName, manufacturerName))
1064 if(!DuplicateString(&deviceInfo.manufacturerUrl, manufacturerUrl))
1069 if(!DuplicateString(&deviceInfo.modelNumber, modelNumber))
1074 if(!DuplicateString(&deviceInfo.platformVersion, platformVersion))
1079 if(!DuplicateString(&deviceInfo.supportUrl, supportUrl))
1084 if(!DuplicateString(&deviceInfo.version, version))
1095 return OC_STACK_ERROR;