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 // Entity handler should check for resourceTypeName and ResourceInterface in order to GET
84 // the existence of a known resource
85 const char *resourceTypeName = "core.light";
86 const char *resourceInterface = "oc.mi.def";
88 OCDeviceInfo deviceInfo;
90 //This function takes the request as an input and returns the response
92 char* constructJsonResponse (OCEntityHandlerRequest *ehRequest)
94 cJSON *json = cJSON_CreateObject();
97 LightResource *currLightResource = &Light;
99 if (ehRequest->resource == gLightInstance[0].handle)
101 currLightResource = &gLightInstance[0];
102 gResourceUri = (char *) "a/light/0";
104 else if (ehRequest->resource == gLightInstance[1].handle)
106 currLightResource = &gLightInstance[1];
107 gResourceUri = (char *) "a/light/1";
110 if(OC_REST_PUT == ehRequest->method)
112 // Get cJSON pointer to query
113 cJSON *putJson = cJSON_Parse((char *)ehRequest->reqJSONPayload);
115 // Get root of JSON payload, then the 1st resource.
116 cJSON* carrier = cJSON_GetObjectItem(putJson, "oc");
117 carrier = cJSON_GetArrayItem(carrier, 0);
118 carrier = cJSON_GetObjectItem(carrier, "rep");
120 cJSON* prop = cJSON_GetObjectItem(carrier,"power");
123 currLightResource->power =prop->valueint;
126 prop = cJSON_GetObjectItem(carrier,"state");
129 currLightResource->state = prop->valueint;
132 cJSON_Delete(putJson);
135 cJSON_AddStringToObject(json,"href",gResourceUri);
136 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
137 cJSON_AddBoolToObject(format, "state", currLightResource->state);
138 cJSON_AddNumberToObject(format, "power", currLightResource->power);
140 jsonResponse = cJSON_Print(json);
147 * Very simple example of query parsing.
148 * The query may have multiple filters separated by '&'.
149 * It is upto the entity handler to parse the query for the individual filters,
150 * VALIDATE them and respond as it sees fit.
152 * This function only returns false if the query is exactly "power<X" and
153 * current power is greater than X. If X cannot be parsed for an int,
156 bool checkIfQueryForPowerPassed(char * query)
158 if (query && strcmp(query, "power<") == 0)
160 char * pointerToOperator = strstr(query, "<");
162 if (pointerToOperator)
164 int powerRequested = atoi(pointerToOperator + 1);
166 if (Light.power > powerRequested)
168 OC_LOG_V(INFO, TAG, "Current power: %d. Requested: <%d", Light.power
177 /* This method check the validity of resourceTypeName and resource interfaces
178 * Entity Handler has to parse the query string in order to process it
181 OCEntityHandlerResult ValidateQueryParams (OCEntityHandlerRequest *entityHandlerRequest)
183 bool resourceList = true;
184 uint8_t resourceIndex = 0;
185 OCEntityHandlerResult ehResult = OC_EH_ERROR;
188 if (!entityHandlerRequest)
190 OC_LOG (ERROR, TAG, "Invalid request pointer");
193 //Added check for resource type & interface in server entity handle
197 const char* typeName = OCGetResourceTypeName(entityHandlerRequest->resource,
199 const char* interfaceName = OCGetResourceInterfaceName(entityHandlerRequest->resource,
201 if(typeName && interfaceName)
203 if(strcmp(typeName,resourceTypeName) == 0 &&
204 strcmp(interfaceName,resourceInterface) == 0)
213 resourceList = false;
219 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
220 char *payload, uint16_t maxPayloadSize)
222 OCEntityHandlerResult ehResult;
223 char *getResp = constructJsonResponse(ehRequest);
225 bool queryPassed = checkIfQueryForPowerPassed(ehRequest->query);
227 // Empty payload if the query has no match.
230 char *getResp = constructJsonResponse(ehRequest);
232 if (maxPayloadSize > strlen ((char *)getResp))
234 strncpy(payload, getResp, strlen((char *)getResp));
239 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
241 ehResult = OC_EH_ERROR;
254 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
255 char *payload, uint16_t maxPayloadSize)
257 OCEntityHandlerResult ehResult;
258 char *putResp = constructJsonResponse(ehRequest);
260 if (maxPayloadSize > strlen ((char *)putResp))
262 strncpy(payload, putResp, strlen((char *)putResp));
267 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
269 ehResult = OC_EH_ERROR;
277 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
278 OCEntityHandlerResponse *response, char *payload, uint16_t maxPayloadSize)
280 OCEntityHandlerResult ehResult = OC_EH_OK;
281 char *respPLPost_light = NULL;
286 * The entity handler determines how to process a POST request.
287 * Per the REST paradigm, POST can also be used to update representation of existing
288 * resource or create a new resource.
289 * In the sample below, if the POST is for /a/light then a new instance of the Light
290 * resource is created with default representation (if representation is included in
291 * POST payload it can be used as initial values) as long as the instance is
292 * lesser than max new instance count. Once max instance count is reached, POST on
293 * /a/light updated the representation of /a/light (just like PUT)
296 if (ehRequest->resource == Light.handle)
298 if (gCurrLightInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
300 // Create new Light instance
301 char newLightUri[URI_MAXSIZE];
302 snprintf(newLightUri, URI_MAXSIZE, "/a/light/%d", gCurrLightInstance);
304 json = cJSON_CreateObject();
305 cJSON_AddStringToObject(json,"href",gResourceUri);
306 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
307 cJSON_AddStringToObject(format, "createduri", (char *) newLightUri);
309 if (0 == createLightResource (newLightUri, &gLightInstance[gCurrLightInstance]))
311 OC_LOG (INFO, TAG, "Created new Light instance\n");
312 gLightInstance[gCurrLightInstance].state = 0;
313 gLightInstance[gCurrLightInstance].power = 0;
314 gCurrLightInstance++;
315 respPLPost_light = cJSON_Print(json);
316 strncpy ((char *)response->resourceUri, newLightUri, MAX_URI_LENGTH);
317 ehResult = OC_EH_RESOURCE_CREATED;
324 // Update repesentation of /a/light
327 respPLPost_light = constructJsonResponse(ehRequest);
332 for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
334 if (ehRequest->resource == gLightInstance[i].handle)
336 gLightInstance[i].state = true;
337 gLightInstance[i].power = 22;
340 respPLPost_light = constructJsonResponse(ehRequest);
345 respPLPost_light = constructJsonResponse(ehRequest);
351 if ((respPLPost_light != NULL) && (maxPayloadSize > strlen ((char *)respPLPost_light)))
353 strncpy(payload, respPLPost_light, strlen((char *)respPLPost_light));
357 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
359 ehResult = OC_EH_ERROR;
362 free(respPLPost_light);
366 OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest,
367 char *payload, uint16_t maxPayloadSize)
369 if(ehRequest == NULL)
371 OC_LOG(INFO, TAG, "The ehRequest is NULL");
374 OCEntityHandlerResult ehResult = OC_EH_OK;
376 OC_LOG_V(INFO, TAG, "\n\nExecuting %s for resource %d ", __func__, ehRequest->resource);
379 * In the sample below, the application will:
380 * 1a. pass the delete request to the c stack
381 * 1b. internally, the c stack figures out what needs to be done and does it accordingly
382 * (e.g. send observers notification, remove observers...)
383 * 1c. the c stack returns with the result whether the request is fullfilled.
384 * 2. optionally, app removes observers out of its array 'interestedObservers'
387 const char* deleteResponse = NULL;
389 if ((ehRequest != NULL) && (ehRequest->resource == Light.handle))
391 //Step 1: Ask stack to do the work.
392 OCStackResult result = OCDeleteResource(ehRequest->resource);
394 if (result == OC_STACK_OK)
396 OC_LOG (INFO, TAG, "\n\nDelete Resource operation succeeded.");
398 deleteResponse = responsePayloadDeleteOk;
400 //Step 2: clear observers who wanted to observe this resource at the app level.
401 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
403 if (interestedObservers[i].resourceHandle == ehRequest->resource)
405 interestedObservers[i].valid = false;
406 interestedObservers[i].observationId = 0;
407 interestedObservers[i].resourceHandle = NULL;
411 else if (result == OC_STACK_NO_RESOURCE)
413 OC_LOG(INFO, TAG, "\n\nThe resource doesn't exist or it might have been deleted.");
414 deleteResponse = responsePayloadResourceDoesNotExist;
415 ehResult = OC_EH_RESOURCE_DELETED;
419 OC_LOG(INFO, TAG, "\n\nEncountered error from OCDeleteResource().");
420 deleteResponse = responsePayloadDeleteNotOK;
421 ehResult = OC_EH_ERROR;
424 else if (ehRequest->resource != Light.handle)
426 //Let's this app not supporting DELETE on some resources so
427 //consider the DELETE request is received for a non-support resource.
428 OC_LOG_V(INFO, TAG, "\n\nThe request is received for a non-support resource.");
429 deleteResponse = responsePayloadDeleteResourceNotSupported;
430 ehResult = OC_EH_FORBIDDEN;
433 if (maxPayloadSize > strlen ((char *)deleteResponse))
435 strncpy(payload, deleteResponse, strlen((char *)deleteResponse));
439 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
441 ehResult = OC_EH_ERROR;
447 OCEntityHandlerResult ProcessNonExistingResourceRequest(OCEntityHandlerRequest *ehRequest,
448 char *payload, uint16_t maxPayloadSize)
450 OC_LOG_V(INFO, TAG, "\n\nExecuting %s ", __func__);
452 const char* response = NULL;
453 response = responsePayloadResourceDoesNotExist;
455 if ( (ehRequest != NULL) &&
456 (maxPayloadSize > strlen ((char *)response)) )
458 strncpy((char *)payload, response, strlen((char *)response));
462 OC_LOG_V (ERROR, TAG, "Response buffer: %d bytes is too small",
466 return OC_EH_RESOURCE_NOT_FOUND;
469 void ProcessObserveRegister (OCEntityHandlerRequest *ehRequest)
471 OC_LOG_V (INFO, TAG, "Received observation registration request with observation Id %d",
472 ehRequest->obsInfo.obsId);
473 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
475 if (interestedObservers[i].valid == false)
477 interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
478 interestedObservers[i].valid = true;
479 gLightUnderObservation = 1;
485 void ProcessObserveDeregister (OCEntityHandlerRequest *ehRequest)
487 bool clientStillObserving = false;
489 OC_LOG_V (INFO, TAG, "Received observation deregistration request for observation Id %d",
490 ehRequest->obsInfo.obsId);
491 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
493 if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
495 interestedObservers[i].valid = false;
497 if (interestedObservers[i].valid == true)
499 // Even if there is one single client observing we continue notifying entity handler
500 clientStillObserving = true;
503 if (clientStillObserving == false)
504 gLightUnderObservation = 0;
507 OCEntityHandlerResult
508 OCDeviceEntityHandlerCb (OCEntityHandlerFlag flag,
509 OCEntityHandlerRequest *entityHandlerRequest, char* uri)
511 OC_LOG_V (INFO, TAG, "Inside device default entity handler - flags: 0x%x, uri: %s", flag, uri);
513 OCEntityHandlerResult ehResult = OC_EH_ERROR;
514 OCEntityHandlerResponse response;
515 char payload[MAX_RESPONSE_LENGTH] = {0};
518 if (!entityHandlerRequest)
520 OC_LOG (ERROR, TAG, "Invalid request pointer");
523 // Initialize certain response fields
524 response.numSendVendorSpecificHeaderOptions = 0;
525 memset(response.sendVendorSpecificHeaderOptions, 0,
526 sizeof response.sendVendorSpecificHeaderOptions);
527 memset(response.resourceUri, 0, sizeof response.resourceUri);
529 // Entity handler to check the validity of resourceTypeName and resource interfaces
530 // It is Entity handler's responsibility to keep track of the list of resources prior to call
532 ehResult = ValidateQueryParams(entityHandlerRequest);
534 if (flag & OC_INIT_FLAG)
536 OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
538 if (flag & OC_REQUEST_FLAG)
540 OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
541 // Entity handler to check the validity of resourceType and resource interface
542 if( ehResult == OC_EH_OK )
544 if (entityHandlerRequest->resource == NULL)
546 OC_LOG (INFO, TAG, "Received request from client to a non-existing resource");
547 ehResult = ProcessNonExistingResourceRequest(entityHandlerRequest,
548 payload, sizeof(payload) - 1);
550 else if (OC_REST_GET == entityHandlerRequest->method)
552 OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
553 ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
555 else if (OC_REST_PUT == entityHandlerRequest->method)
557 OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
558 ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
560 else if (OC_REST_DELETE == entityHandlerRequest->method)
562 OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
563 ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
567 OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
568 entityHandlerRequest->method);
569 ehResult = OC_EH_ERROR;
575 "Invalid ResourceInterface Type & Name received from client for method: %d ",
576 entityHandlerRequest->method);
578 // If the result isn't an error or forbidden, send response
579 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
581 // Format the response. Note this requires some info about the request
582 response.requestHandle = entityHandlerRequest->requestHandle;
583 response.resourceHandle = entityHandlerRequest->resource;
584 response.ehResult = ehResult;
585 response.payload = payload;
586 response.payloadSize = strlen(payload);
587 // Indicate that response is NOT in a persistent buffer
588 response.persistentBufferFlag = 0;
591 if (OCDoResponse(&response) != OC_STACK_OK)
593 OC_LOG(ERROR, TAG, "Error sending response");
594 ehResult = OC_EH_ERROR;
598 if (flag & OC_OBSERVE_FLAG)
600 OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
601 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
603 OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
605 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
607 OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
614 OCEntityHandlerResult
615 OCNOPEntityHandlerCb (OCEntityHandlerFlag flag,
616 OCEntityHandlerRequest *entityHandlerRequest)
618 // This is callback is associated with the 2 presence notification
619 // resources. They are non-operational.
623 OCEntityHandlerResult
624 OCEntityHandlerCb (OCEntityHandlerFlag flag,
625 OCEntityHandlerRequest *entityHandlerRequest)
627 OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
629 OCEntityHandlerResult ehResult = OC_EH_OK;
630 OCEntityHandlerResponse response;
631 char payload[MAX_RESPONSE_LENGTH] = {0};
634 if (!entityHandlerRequest)
636 OC_LOG (ERROR, TAG, "Invalid request pointer");
640 // Initialize certain response fields
641 response.numSendVendorSpecificHeaderOptions = 0;
642 memset(response.sendVendorSpecificHeaderOptions,
643 0, sizeof response.sendVendorSpecificHeaderOptions);
644 memset(response.resourceUri, 0, sizeof response.resourceUri);
646 // Entity handler to check the validity of resourceTypeName and resource interfaces
647 // It is Entity handler's responsibility to keep track of the list of resources prior to call
650 ehResult = ValidateQueryParams(entityHandlerRequest);
652 if (flag & OC_INIT_FLAG)
654 OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
656 if (flag & OC_REQUEST_FLAG)
658 OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
660 // Entity handler to check the validity of resourceType and resource interface
661 // Entity handler to check the validity of resourceType and resource interface
662 if(ehResult == OC_EH_OK)
664 if (OC_REST_GET == entityHandlerRequest->method)
666 OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
667 ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
669 else if (OC_REST_PUT == entityHandlerRequest->method)
671 OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
672 ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
674 else if (OC_REST_POST == entityHandlerRequest->method)
676 OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
677 ehResult = ProcessPostRequest (entityHandlerRequest, &response, payload, sizeof(payload) - 1);
679 else if (OC_REST_DELETE == entityHandlerRequest->method)
681 OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
682 ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
686 OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
687 entityHandlerRequest->method);
688 ehResult = OC_EH_ERROR;
694 "Invalid ResourceInterface Type & Name received from client for method: %d ",
695 entityHandlerRequest->method);
697 // If the result isn't an error or forbidden, send response
698 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
700 // Format the response. Note this requires some info about the request
701 response.requestHandle = entityHandlerRequest->requestHandle;
702 response.resourceHandle = entityHandlerRequest->resource;
703 response.ehResult = ehResult;
704 response.payload = payload;
705 response.payloadSize = strlen(payload);
706 // Indicate that response is NOT in a persistent buffer
707 response.persistentBufferFlag = 0;
709 // Handle vendor specific options
710 if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
711 entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
713 OC_LOG (INFO, TAG, "Received vendor specific options");
715 OCHeaderOption * rcvdOptions =
716 entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
717 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
719 if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
721 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
722 ((OCHeaderOption)rcvdOptions[i]).optionID );
724 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
725 MAX_HEADER_OPTION_DATA_LENGTH);
728 OCHeaderOption * sendOptions = response.sendVendorSpecificHeaderOptions;
729 uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
730 uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
731 sendOptions[0].protocolID = OC_COAP_ID;
732 sendOptions[0].optionID = 2248;
733 memcpy(sendOptions[0].optionData, option2, sizeof(option2));
734 sendOptions[0].optionLength = 10;
735 sendOptions[1].protocolID = OC_COAP_ID;
736 sendOptions[1].optionID = 2600;
737 memcpy(sendOptions[1].optionData, option3, sizeof(option3));
738 sendOptions[1].optionLength = 10;
739 response.numSendVendorSpecificHeaderOptions = 2;
743 if (OCDoResponse(&response) != OC_STACK_OK)
745 OC_LOG(ERROR, TAG, "Error sending response");
746 ehResult = OC_EH_ERROR;
750 if (flag & OC_OBSERVE_FLAG)
752 OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
754 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
756 OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
757 ProcessObserveRegister (entityHandlerRequest);
759 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
761 OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
762 ProcessObserveDeregister (entityHandlerRequest);
769 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
770 void handleSigInt(int signum)
772 if (signum == SIGINT)
778 void *ChangeLightRepresentation (void *param)
781 OCStackResult result = OC_STACK_ERROR;
784 uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
785 OCObservationId obsNotify[numNotifies];
791 if (gLightUnderObservation)
793 OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
794 if (gObserveNotifyType == 1)
796 // Notify list of observers. Alternate observers on the list will be notified.
798 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
800 if (interestedObservers[i].valid == true)
802 obsNotify[j] = interestedObservers[i].observationId;
807 cJSON *json = cJSON_CreateObject();
809 cJSON_AddStringToObject(json,"href",gResourceUri);
810 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
811 cJSON_AddBoolToObject(format, "state", Light.state);
812 cJSON_AddNumberToObject(format, "power", Light.power);
813 char * obsResp = cJSON_Print(json);
815 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
819 else if (gObserveNotifyType == 0)
821 // Notifying all observers
822 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
823 if (OC_STACK_NO_OBSERVERS == result)
826 "=======> No more observers exist, stop sending observations");
827 gLightUnderObservation = 0;
832 OC_LOG (ERROR, TAG, "Incorrect notification type selected");
836 if(stopPresenceCount > 0)
838 OC_LOG_V(INFO, TAG, "================ Counting down to stop presence %d", stopPresenceCount);
840 if(!stopPresenceCount--)
842 OC_LOG(INFO, TAG, "================ stopping presence");
851 void *presenceNotificationGenerator(void *param)
855 OCDoHandle presenceNotificationHandles[numPresenceResources];
856 OCStackResult res = OC_STACK_OK;
858 std::array<std::string, numPresenceResources> presenceNotificationResources { {
859 std::string("core.fan"),
860 std::string("core.led") } };
861 std::array<std::string, numPresenceResources> presenceNotificationUris { {
862 std::string("/a/fan"),
863 std::string("/a/led") } };
865 for(int i=0; i<numPresenceResources; i++)
867 if(res == OC_STACK_OK)
870 res = OCCreateResource(&presenceNotificationHandles[i],
871 presenceNotificationResources.at(i).c_str(),
873 presenceNotificationUris.at(i).c_str(),
874 OCNOPEntityHandlerCb,
875 OC_DISCOVERABLE|OC_OBSERVABLE);
877 if(res != OC_STACK_OK)
879 OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to create resource "
880 "%s with result %s.", presenceNotificationResources.at(i).c_str(),
884 OC_LOG_V(INFO, TAG, PCF("Created %s for presence notification"),
885 presenceNotificationUris[i].c_str());
888 for(int i=0; i<numPresenceResources; i++)
890 if(res == OC_STACK_OK)
892 res = OCDeleteResource(presenceNotificationHandles[i]);
894 if(res != OC_STACK_OK)
896 OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to delete "\
897 "resource %s.", presenceNotificationResources.at(i).c_str());
900 OC_LOG_V(INFO, TAG, PCF("Deleted %s for presence notification"),
901 presenceNotificationUris[i].c_str());
907 static void PrintUsage()
909 OC_LOG(INFO, TAG, "Usage : ocserver -o <0|1>");
910 OC_LOG(INFO, TAG, "-o 0 : Notify all observers");
911 OC_LOG(INFO, TAG, "-o 1 : Notify list of observers");
914 int main(int argc, char* argv[])
917 pthread_t threadId_presence;
920 while ((opt = getopt(argc, argv, "o:")) != -1)
925 gObserveNotifyType = atoi(optarg);
933 if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
939 OC_LOG(DEBUG, TAG, "OCServer is starting...");
941 if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
943 OC_LOG(ERROR, TAG, "OCStack init error");
947 if (OCStartPresence(0) != OC_STACK_OK)
949 OC_LOG(ERROR, TAG, "OCStack presence/discovery error");
954 OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb);
956 OCStackResult deviceResult = SetDeviceInfo(contentType, dateOfManufacture, deviceName,
957 deviceUUID, firmwareVersion, hostName, manufacturerName,
958 manufacturerUrl, modelNumber, platformVersion, supportUrl, version);
960 if (deviceResult != OC_STACK_OK)
962 OC_LOG(INFO, TAG, "Device Registration failed!");
966 deviceResult = OCSetDeviceInfo(deviceInfo);
968 if (deviceResult != OC_STACK_OK)
970 OC_LOG(INFO, TAG, "Device Registration failed!");
975 * Declare and create the example resource: Light
977 createLightResource(gResourceUri, &Light);
979 // Initialize observations data structure for the resource
980 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
982 interestedObservers[i].valid = false;
986 * Create a thread for changing the representation of the Light
988 pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)NULL);
991 * Create a thread for generating changes that cause presence notifications
992 * to be sent to clients
996 pthread_create(&threadId_presence, NULL, presenceNotificationGenerator, (void *)NULL);
999 // Break from loop with Ctrl-C
1000 OC_LOG(INFO, TAG, "Entering ocserver main loop...");
1002 signal(SIGINT, handleSigInt);
1005 if (OCProcess() != OC_STACK_OK)
1007 OC_LOG(ERROR, TAG, "OCStack process error");
1015 * Cancel the Light thread and wait for it to terminate
1017 pthread_cancel(threadId);
1018 pthread_join(threadId, NULL);
1019 pthread_cancel(threadId_presence);
1020 pthread_join(threadId_presence, NULL);
1022 OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
1024 if (OCStop() != OC_STACK_OK)
1026 OC_LOG(ERROR, TAG, "OCStack process error");
1032 int createLightResource (char *uri, LightResource *lightResource)
1036 OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
1040 lightResource->state = false;
1041 lightResource->power= 0;
1042 OCStackResult res = OCCreateResource(&(lightResource->handle),
1047 OC_DISCOVERABLE|OC_OBSERVABLE);
1048 OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
1053 void DeleteDeviceInfo()
1055 free(deviceInfo.contentType);
1056 free(deviceInfo.dateOfManufacture);
1057 free(deviceInfo.deviceName);
1058 free(deviceInfo.deviceUUID);
1059 free(deviceInfo.firmwareVersion);
1060 free(deviceInfo.hostName);
1061 free(deviceInfo.manufacturerName);
1062 free(deviceInfo.manufacturerUrl);
1063 free(deviceInfo.modelNumber);
1064 free(deviceInfo.platformVersion);
1065 free(deviceInfo.supportUrl);
1066 free(deviceInfo.version);
1069 bool DuplicateString(char** targetString, const char* sourceString)
1077 *targetString = (char *) malloc(strlen(sourceString) + 1);
1081 strncpy(*targetString, sourceString, (strlen(sourceString) + 1));
1088 OCStackResult SetDeviceInfo(const char *contentType, const char *dateOfManufacture,
1089 const char *deviceName, const char *deviceUUID, const char *firmwareVersion,
1090 const char *hostName, const char *manufacturerName, const char *manufacturerUrl,
1091 const char *modelNumber, const char *platformVersion, const char *supportUrl,
1092 const char *version)
1095 bool success = true;
1097 if(manufacturerName != NULL && (strlen(manufacturerName) > MAX_MANUFACTURER_NAME_LENGTH))
1099 return OC_STACK_INVALID_PARAM;
1102 if(manufacturerUrl != NULL && (strlen(manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH))
1104 return OC_STACK_INVALID_PARAM;
1107 if(!DuplicateString(&deviceInfo.contentType, contentType))
1112 if(!DuplicateString(&deviceInfo.dateOfManufacture, dateOfManufacture))
1117 if(!DuplicateString(&deviceInfo.deviceName, deviceName))
1122 if(!DuplicateString(&deviceInfo.deviceUUID, deviceUUID))
1127 if(!DuplicateString(&deviceInfo.firmwareVersion, firmwareVersion))
1132 if(!DuplicateString(&deviceInfo.hostName, hostName))
1137 if(!DuplicateString(&deviceInfo.manufacturerName, manufacturerName))
1142 if(!DuplicateString(&deviceInfo.manufacturerUrl, manufacturerUrl))
1147 if(!DuplicateString(&deviceInfo.modelNumber, modelNumber))
1152 if(!DuplicateString(&deviceInfo.platformVersion, platformVersion))
1157 if(!DuplicateString(&deviceInfo.supportUrl, supportUrl))
1162 if(!DuplicateString(&deviceInfo.version, version))
1173 return OC_STACK_ERROR;