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 = "myName";
77 const char *operatingSystemVersion = "myOS";
78 const char *hardwareVersion = "myHardwareVersion";
79 const char* platformID = "myPlatformID";
80 const char *manufacturerUrl = "myManufacturerUrl";
81 const char *modelNumber = "myModelNumber";
82 const char *platformVersion = "myPlatformVersion";
83 const char *supportUrl = "mySupportUrl";
84 const char *version = "myVersion";
85 const char *systemTime = "2015-05-15T11.04";
87 // Entity handler should check for resourceTypeName and ResourceInterface in order to GET
88 // the existence of a known resource
89 const char *resourceTypeName = "core.light";
90 const char *resourceInterface = OC_RSRVD_INTERFACE_DEFAULT;
92 OCPlatformInfo platformInfo;
94 //This function takes the request as an input and returns the response
96 char* constructJsonResponse (OCEntityHandlerRequest *ehRequest)
98 cJSON *json = cJSON_CreateObject();
101 LightResource *currLightResource = &Light;
103 if (ehRequest->resource == gLightInstance[0].handle)
105 currLightResource = &gLightInstance[0];
106 gResourceUri = (char *) "a/light/0";
108 else if (ehRequest->resource == gLightInstance[1].handle)
110 currLightResource = &gLightInstance[1];
111 gResourceUri = (char *) "a/light/1";
114 if(OC_REST_PUT == ehRequest->method)
116 // Get cJSON pointer to query
117 cJSON *putJson = cJSON_Parse(ehRequest->reqJSONPayload);
121 OC_LOG_V(ERROR, TAG, "Failed to parse JSON: %s", ehRequest->reqJSONPayload);
125 // Get root of JSON payload, then the 1st resource.
126 cJSON* carrier = cJSON_GetObjectItem(putJson, "oc");
127 carrier = cJSON_GetArrayItem(carrier, 0);
128 carrier = cJSON_GetObjectItem(carrier, "rep");
130 cJSON* prop = cJSON_GetObjectItem(carrier,"power");
133 currLightResource->power =prop->valueint;
136 prop = cJSON_GetObjectItem(carrier,"state");
139 currLightResource->state = prop->valueint;
142 cJSON_Delete(putJson);
145 cJSON_AddStringToObject(json,"href",gResourceUri);
146 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
147 cJSON_AddBoolToObject(format, "state", currLightResource->state);
148 cJSON_AddNumberToObject(format, "power", currLightResource->power);
150 jsonResponse = cJSON_Print(json);
157 * Very simple example of query parsing.
158 * The query may have multiple filters separated by '&'.
159 * It is upto the entity handler to parse the query for the individual filters,
160 * VALIDATE them and respond as it sees fit.
162 * This function only returns false if the query is exactly "power<X" and
163 * current power is greater than X. If X cannot be parsed for an int,
166 bool checkIfQueryForPowerPassed(char * query)
168 if (query && strncmp(query, "power<", strlen("power<")) == 0)
170 char * pointerToOperator = strstr(query, "<");
172 if (pointerToOperator)
174 int powerRequested = atoi(pointerToOperator + 1);
175 if (Light.power > powerRequested)
177 OC_LOG_V(INFO, TAG, "Current power: %d. Requested: <%d", Light.power
187 * Application should validate and process these as desired.
189 OCEntityHandlerResult ValidateQueryParams (OCEntityHandlerRequest *entityHandlerRequest)
191 OC_LOG_V(INFO, TAG, PCF("Received query %s"), entityHandlerRequest->query);
192 OC_LOG(INFO, TAG, PCF("Not processing query"));
196 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
197 char *payload, uint16_t maxPayloadSize)
199 OCEntityHandlerResult ehResult;
200 bool queryPassed = checkIfQueryForPowerPassed(ehRequest->query);
202 // Empty payload if the query has no match.
205 char *getResp = constructJsonResponse(ehRequest);
208 OC_LOG(ERROR, TAG, "constructJsonResponse failed");
212 if (maxPayloadSize > strlen (getResp))
214 strncpy(payload, getResp, strlen(getResp));
219 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
221 ehResult = OC_EH_ERROR;
234 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
235 char *payload, uint16_t maxPayloadSize)
237 OCEntityHandlerResult ehResult;
238 char *putResp = constructJsonResponse(ehRequest);
242 OC_LOG(ERROR, TAG, "Failed to construct Json response");
246 if (maxPayloadSize > strlen ((char *)putResp))
248 strncpy(payload, putResp, strlen((char *)putResp));
253 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
255 ehResult = OC_EH_ERROR;
263 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
264 OCEntityHandlerResponse *response, char *payload, uint16_t maxPayloadSize)
266 OCEntityHandlerResult ehResult = OC_EH_OK;
267 char *respPLPost_light = NULL;
272 * The entity handler determines how to process a POST request.
273 * Per the REST paradigm, POST can also be used to update representation of existing
274 * resource or create a new resource.
275 * In the sample below, if the POST is for /a/light then a new instance of the Light
276 * resource is created with default representation (if representation is included in
277 * POST payload it can be used as initial values) as long as the instance is
278 * lesser than max new instance count. Once max instance count is reached, POST on
279 * /a/light updated the representation of /a/light (just like PUT)
282 if (ehRequest->resource == Light.handle)
284 if (gCurrLightInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
286 // Create new Light instance
287 char newLightUri[URI_MAXSIZE];
288 snprintf(newLightUri, URI_MAXSIZE, "/a/light/%d", gCurrLightInstance);
290 json = cJSON_CreateObject();
291 cJSON_AddStringToObject(json,"href",gResourceUri);
292 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
293 cJSON_AddStringToObject(format, "createduri", (char *) newLightUri);
295 if (0 == createLightResource (newLightUri, &gLightInstance[gCurrLightInstance]))
297 OC_LOG (INFO, TAG, "Created new Light instance\n");
298 gLightInstance[gCurrLightInstance].state = 0;
299 gLightInstance[gCurrLightInstance].power = 0;
300 gCurrLightInstance++;
301 respPLPost_light = cJSON_Print(json);
302 strncpy ((char *)response->resourceUri, newLightUri, MAX_URI_LENGTH);
303 ehResult = OC_EH_RESOURCE_CREATED;
310 // Update repesentation of /a/light
313 respPLPost_light = constructJsonResponse(ehRequest);
318 for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
320 if (ehRequest->resource == gLightInstance[i].handle)
322 gLightInstance[i].state = true;
323 gLightInstance[i].power = 22;
326 respPLPost_light = constructJsonResponse(ehRequest);
331 respPLPost_light = constructJsonResponse(ehRequest);
337 if ((respPLPost_light != NULL) && (maxPayloadSize > strlen ((char *)respPLPost_light)))
339 strncpy(payload, respPLPost_light, strlen((char *)respPLPost_light));
343 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
345 ehResult = OC_EH_ERROR;
348 free(respPLPost_light);
352 OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest,
353 char *payload, uint16_t maxPayloadSize)
355 if(ehRequest == NULL)
357 OC_LOG(INFO, TAG, "The ehRequest is NULL");
360 OCEntityHandlerResult ehResult = OC_EH_OK;
362 OC_LOG_V(INFO, TAG, "\n\nExecuting %s for resource %d ", __func__, ehRequest->resource);
365 * In the sample below, the application will:
366 * 1a. pass the delete request to the c stack
367 * 1b. internally, the c stack figures out what needs to be done and does it accordingly
368 * (e.g. send observers notification, remove observers...)
369 * 1c. the c stack returns with the result whether the request is fullfilled.
370 * 2. optionally, app removes observers out of its array 'interestedObservers'
373 const char* deleteResponse = NULL;
375 if ((ehRequest != NULL) && (ehRequest->resource == Light.handle))
377 //Step 1: Ask stack to do the work.
378 OCStackResult result = OCDeleteResource(ehRequest->resource);
380 if (result == OC_STACK_OK)
382 OC_LOG (INFO, TAG, "\n\nDelete Resource operation succeeded.");
384 deleteResponse = responsePayloadDeleteOk;
386 //Step 2: clear observers who wanted to observe this resource at the app level.
387 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
389 if (interestedObservers[i].resourceHandle == ehRequest->resource)
391 interestedObservers[i].valid = false;
392 interestedObservers[i].observationId = 0;
393 interestedObservers[i].resourceHandle = NULL;
397 else if (result == OC_STACK_NO_RESOURCE)
399 OC_LOG(INFO, TAG, "\n\nThe resource doesn't exist or it might have been deleted.");
400 deleteResponse = responsePayloadResourceDoesNotExist;
401 ehResult = OC_EH_RESOURCE_DELETED;
405 OC_LOG(INFO, TAG, "\n\nEncountered error from OCDeleteResource().");
406 deleteResponse = responsePayloadDeleteNotOK;
407 ehResult = OC_EH_ERROR;
410 else if (ehRequest->resource != Light.handle)
412 //Let's this app not supporting DELETE on some resources so
413 //consider the DELETE request is received for a non-support resource.
414 OC_LOG_V(INFO, TAG, "\n\nThe request is received for a non-support resource.");
415 deleteResponse = responsePayloadDeleteResourceNotSupported;
416 ehResult = OC_EH_FORBIDDEN;
419 if (maxPayloadSize > strlen ((char *)deleteResponse))
421 strncpy(payload, deleteResponse, strlen((char *)deleteResponse));
425 OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
427 ehResult = OC_EH_ERROR;
433 OCEntityHandlerResult ProcessNonExistingResourceRequest(OCEntityHandlerRequest *ehRequest,
434 char *payload, uint16_t maxPayloadSize)
436 OC_LOG_V(INFO, TAG, "\n\nExecuting %s ", __func__);
438 const char* response = NULL;
439 response = responsePayloadResourceDoesNotExist;
441 if ( (ehRequest != NULL) &&
442 (maxPayloadSize > strlen ((char *)response)) )
444 strncpy((char *)payload, response, strlen((char *)response));
448 OC_LOG_V (ERROR, TAG, "Response buffer: %d bytes is too small",
452 return OC_EH_RESOURCE_NOT_FOUND;
455 void ProcessObserveRegister (OCEntityHandlerRequest *ehRequest)
457 OC_LOG_V (INFO, TAG, "Received observation registration request with observation Id %d",
458 ehRequest->obsInfo.obsId);
459 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
461 if (interestedObservers[i].valid == false)
463 interestedObservers[i].observationId = ehRequest->obsInfo.obsId;
464 interestedObservers[i].valid = true;
465 gLightUnderObservation = 1;
471 void ProcessObserveDeregister (OCEntityHandlerRequest *ehRequest)
473 bool clientStillObserving = false;
475 OC_LOG_V (INFO, TAG, "Received observation deregistration request for observation Id %d",
476 ehRequest->obsInfo.obsId);
477 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
479 if (interestedObservers[i].observationId == ehRequest->obsInfo.obsId)
481 interestedObservers[i].valid = false;
483 if (interestedObservers[i].valid == true)
485 // Even if there is one single client observing we continue notifying entity handler
486 clientStillObserving = true;
489 if (clientStillObserving == false)
490 gLightUnderObservation = 0;
493 OCEntityHandlerResult
494 OCDeviceEntityHandlerCb (OCEntityHandlerFlag flag,
495 OCEntityHandlerRequest *entityHandlerRequest, char* uri)
497 OC_LOG_V (INFO, TAG, "Inside device default entity handler - flags: 0x%x, uri: %s", flag, uri);
499 OCEntityHandlerResult ehResult = OC_EH_OK;
500 OCEntityHandlerResponse response;
501 char payload[MAX_RESPONSE_LENGTH] = {0};
504 if (!entityHandlerRequest)
506 OC_LOG (ERROR, TAG, "Invalid request pointer");
509 // Initialize certain response fields
510 response.numSendVendorSpecificHeaderOptions = 0;
511 memset(response.sendVendorSpecificHeaderOptions, 0,
512 sizeof response.sendVendorSpecificHeaderOptions);
513 memset(response.resourceUri, 0, sizeof response.resourceUri);
516 if (flag & OC_REQUEST_FLAG)
518 OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
520 if (entityHandlerRequest->resource == NULL)
522 OC_LOG (INFO, TAG, "Received request from client to a non-existing resource");
523 ehResult = ProcessNonExistingResourceRequest(entityHandlerRequest,
524 payload, sizeof(payload) - 1);
526 else if (OC_REST_GET == entityHandlerRequest->method)
528 OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
529 ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
531 else if (OC_REST_PUT == entityHandlerRequest->method)
533 OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
534 ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
536 else if (OC_REST_DELETE == entityHandlerRequest->method)
538 OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
539 ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
543 OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
544 entityHandlerRequest->method);
545 ehResult = OC_EH_ERROR;
547 // If the result isn't an error or forbidden, send response
548 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
550 // Format the response. Note this requires some info about the request
551 response.requestHandle = entityHandlerRequest->requestHandle;
552 response.resourceHandle = entityHandlerRequest->resource;
553 response.ehResult = ehResult;
554 response.payload = payload;
555 response.payloadSize = strlen(payload);
556 // Indicate that response is NOT in a persistent buffer
557 response.persistentBufferFlag = 0;
560 if (OCDoResponse(&response) != OC_STACK_OK)
562 OC_LOG(ERROR, TAG, "Error sending response");
563 ehResult = OC_EH_ERROR;
567 if (flag & OC_OBSERVE_FLAG)
569 OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
570 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
572 OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
574 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
576 OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
583 OCEntityHandlerResult
584 OCNOPEntityHandlerCb (OCEntityHandlerFlag flag,
585 OCEntityHandlerRequest *entityHandlerRequest)
587 // This is callback is associated with the 2 presence notification
588 // resources. They are non-operational.
592 OCEntityHandlerResult
593 OCEntityHandlerCb (OCEntityHandlerFlag flag,
594 OCEntityHandlerRequest *entityHandlerRequest)
596 OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
598 OCEntityHandlerResult ehResult = OC_EH_OK;
599 OCEntityHandlerResponse response;
600 char payload[MAX_RESPONSE_LENGTH] = {0};
603 if (!entityHandlerRequest)
605 OC_LOG (ERROR, TAG, "Invalid request pointer");
609 // Initialize certain response fields
610 response.numSendVendorSpecificHeaderOptions = 0;
611 memset(response.sendVendorSpecificHeaderOptions,
612 0, sizeof response.sendVendorSpecificHeaderOptions);
613 memset(response.resourceUri, 0, sizeof response.resourceUri);
615 if (flag & OC_REQUEST_FLAG)
617 OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
619 if (OC_REST_GET == entityHandlerRequest->method)
621 OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
622 ehResult = ProcessGetRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
624 else if (OC_REST_PUT == entityHandlerRequest->method)
626 OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
627 ehResult = ProcessPutRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
629 else if (OC_REST_POST == entityHandlerRequest->method)
631 OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
632 ehResult = ProcessPostRequest (entityHandlerRequest, &response, payload, sizeof(payload) - 1);
634 else if (OC_REST_DELETE == entityHandlerRequest->method)
636 OC_LOG (INFO, TAG, "Received OC_REST_DELETE from client");
637 ehResult = ProcessDeleteRequest (entityHandlerRequest, payload, sizeof(payload) - 1);
641 OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
642 entityHandlerRequest->method);
643 ehResult = OC_EH_ERROR;
645 // If the result isn't an error or forbidden, send response
646 if (!((ehResult == OC_EH_ERROR) || (ehResult == OC_EH_FORBIDDEN)))
648 // Format the response. Note this requires some info about the request
649 response.requestHandle = entityHandlerRequest->requestHandle;
650 response.resourceHandle = entityHandlerRequest->resource;
651 response.ehResult = ehResult;
652 response.payload = payload;
653 response.payloadSize = strlen(payload);
654 // Indicate that response is NOT in a persistent buffer
655 response.persistentBufferFlag = 0;
657 // Handle vendor specific options
658 if(entityHandlerRequest->rcvdVendorSpecificHeaderOptions &&
659 entityHandlerRequest->numRcvdVendorSpecificHeaderOptions)
661 OC_LOG (INFO, TAG, "Received vendor specific options");
663 OCHeaderOption * rcvdOptions =
664 entityHandlerRequest->rcvdVendorSpecificHeaderOptions;
665 for( i = 0; i < entityHandlerRequest->numRcvdVendorSpecificHeaderOptions; i++)
667 if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
669 OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
670 ((OCHeaderOption)rcvdOptions[i]).optionID );
672 OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
673 MAX_HEADER_OPTION_DATA_LENGTH);
676 OCHeaderOption * sendOptions = response.sendVendorSpecificHeaderOptions;
677 uint8_t option2[] = {21,22,23,24,25,26,27,28,29,30};
678 uint8_t option3[] = {31,32,33,34,35,36,37,38,39,40};
679 sendOptions[0].protocolID = OC_COAP_ID;
680 sendOptions[0].optionID = 2248;
681 memcpy(sendOptions[0].optionData, option2, sizeof(option2));
682 sendOptions[0].optionLength = 10;
683 sendOptions[1].protocolID = OC_COAP_ID;
684 sendOptions[1].optionID = 2600;
685 memcpy(sendOptions[1].optionData, option3, sizeof(option3));
686 sendOptions[1].optionLength = 10;
687 response.numSendVendorSpecificHeaderOptions = 2;
691 if (OCDoResponse(&response) != OC_STACK_OK)
693 OC_LOG(ERROR, TAG, "Error sending response");
694 ehResult = OC_EH_ERROR;
698 if (flag & OC_OBSERVE_FLAG)
700 OC_LOG(INFO, TAG, "Flag includes OC_OBSERVE_FLAG");
702 if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
704 OC_LOG (INFO, TAG, "Received OC_OBSERVE_REGISTER from client");
705 ProcessObserveRegister (entityHandlerRequest);
707 else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
709 OC_LOG (INFO, TAG, "Received OC_OBSERVE_DEREGISTER from client");
710 ProcessObserveDeregister (entityHandlerRequest);
717 /* SIGINT handler: set gQuitFlag to 1 for graceful termination */
718 void handleSigInt(int signum)
720 if (signum == SIGINT)
726 void *ChangeLightRepresentation (void *param)
729 OCStackResult result = OC_STACK_ERROR;
732 uint8_t numNotifies = (SAMPLE_MAX_NUM_OBSERVATIONS)/2;
733 OCObservationId obsNotify[numNotifies];
739 if (gLightUnderObservation)
741 OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
742 if (gObserveNotifyType == 1)
744 // Notify list of observers. Alternate observers on the list will be notified.
746 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; (i=i+2))
748 if (interestedObservers[i].valid == true)
750 obsNotify[j] = interestedObservers[i].observationId;
755 cJSON *json = cJSON_CreateObject();
757 cJSON_AddStringToObject(json,"href",gResourceUri);
758 cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
759 cJSON_AddBoolToObject(format, "state", Light.state);
760 cJSON_AddNumberToObject(format, "power", Light.power);
761 char * obsResp = cJSON_Print(json);
763 result = OCNotifyListOfObservers (Light.handle, obsNotify, j,
767 else if (gObserveNotifyType == 0)
769 // Notifying all observers
770 result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
771 if (OC_STACK_NO_OBSERVERS == result)
774 "=======> No more observers exist, stop sending observations");
775 gLightUnderObservation = 0;
780 OC_LOG (ERROR, TAG, "Incorrect notification type selected");
784 if(stopPresenceCount > 0)
786 OC_LOG_V(INFO, TAG, "================ Counting down to stop presence %d", stopPresenceCount);
788 if(!stopPresenceCount--)
790 OC_LOG(INFO, TAG, "================ stopping presence");
799 void *presenceNotificationGenerator(void *param)
803 OCDoHandle presenceNotificationHandles[numPresenceResources];
804 OCStackResult res = OC_STACK_OK;
806 std::array<std::string, numPresenceResources> presenceNotificationResources { {
807 std::string("core.fan"),
808 std::string("core.led") } };
809 std::array<std::string, numPresenceResources> presenceNotificationUris { {
810 std::string("/a/fan"),
811 std::string("/a/led") } };
813 for(int i=0; i<numPresenceResources; i++)
815 if(res == OC_STACK_OK)
818 res = OCCreateResource(&presenceNotificationHandles[i],
819 presenceNotificationResources.at(i).c_str(),
820 OC_RSRVD_INTERFACE_DEFAULT,
821 presenceNotificationUris.at(i).c_str(),
822 OCNOPEntityHandlerCb,
823 OC_DISCOVERABLE|OC_OBSERVABLE);
825 if(res != OC_STACK_OK)
827 OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to create resource "
828 "%s with result %s.", presenceNotificationResources.at(i).c_str(),
832 OC_LOG_V(INFO, TAG, PCF("Created %s for presence notification"),
833 presenceNotificationUris[i].c_str());
836 for(int i=0; i<numPresenceResources; i++)
838 if(res == OC_STACK_OK)
840 res = OCDeleteResource(presenceNotificationHandles[i]);
842 if(res != OC_STACK_OK)
844 OC_LOG_V(ERROR, TAG, "\"Presence Notification Generator\" failed to delete "\
845 "resource %s.", presenceNotificationResources.at(i).c_str());
848 OC_LOG_V(INFO, TAG, PCF("Deleted %s for presence notification"),
849 presenceNotificationUris[i].c_str());
855 int createLightResource (char *uri, LightResource *lightResource)
859 OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
863 lightResource->state = false;
864 lightResource->power= 0;
865 OCStackResult res = OCCreateResource(&(lightResource->handle),
870 OC_DISCOVERABLE|OC_OBSERVABLE);
871 OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
876 void DeletePlatformInfo()
878 free (platformInfo.platformID);
879 free (platformInfo.manufacturerName);
880 free (platformInfo.manufacturerUrl);
881 free (platformInfo.modelNumber);
882 free (platformInfo.dateOfManufacture);
883 free (platformInfo.platformVersion);
884 free (platformInfo.operatingSystemVersion);
885 free (platformInfo.hardwareVersion);
886 free (platformInfo.firmwareVersion);
887 free (platformInfo.supportUrl);
888 free (platformInfo.systemTime);
891 bool DuplicateString(char** targetString, const char* sourceString)
899 *targetString = (char *) malloc(strlen(sourceString) + 1);
903 strncpy(*targetString, sourceString, (strlen(sourceString) + 1));
910 OCStackResult SetPlatformInfo(const char* platformID, const char *manufacturerName,
911 const char *manufacturerUrl, const char *modelNumber, const char *dateOfManufacture,
912 const char *platformVersion, const char* operatingSystemVersion, const char* hardwareVersion,
913 const char *firmwareVersion, const char* supportUrl, const char* systemTime)
918 if(manufacturerName != NULL && (strlen(manufacturerName) > MAX_MANUFACTURER_NAME_LENGTH))
920 return OC_STACK_INVALID_PARAM;
923 if(manufacturerUrl != NULL && (strlen(manufacturerUrl) > MAX_MANUFACTURER_URL_LENGTH))
925 return OC_STACK_INVALID_PARAM;
928 if(!DuplicateString(&platformInfo.platformID, platformID))
933 if(!DuplicateString(&platformInfo.manufacturerName, manufacturerName))
938 if(!DuplicateString(&platformInfo.manufacturerUrl, manufacturerUrl))
943 if(!DuplicateString(&platformInfo.modelNumber, modelNumber))
948 if(!DuplicateString(&platformInfo.dateOfManufacture, dateOfManufacture))
953 if(!DuplicateString(&platformInfo.platformVersion, platformVersion))
958 if(!DuplicateString(&platformInfo.operatingSystemVersion, operatingSystemVersion))
963 if(!DuplicateString(&platformInfo.hardwareVersion, hardwareVersion))
968 if(!DuplicateString(&platformInfo.firmwareVersion, firmwareVersion))
973 if(!DuplicateString(&platformInfo.supportUrl, supportUrl))
978 if(!DuplicateString(&platformInfo.systemTime, systemTime))
988 DeletePlatformInfo();
989 return OC_STACK_ERROR;
992 static void PrintUsage()
994 OC_LOG(INFO, TAG, "Usage : ocserver -o <0|1>");
995 OC_LOG(INFO, TAG, "-o 0 : Notify all observers");
996 OC_LOG(INFO, TAG, "-o 1 : Notify list of observers");
999 int main(int argc, char* argv[])
1002 pthread_t threadId_presence;
1005 while ((opt = getopt(argc, argv, "o:")) != -1)
1010 gObserveNotifyType = atoi(optarg);
1018 if ((gObserveNotifyType != 0) && (gObserveNotifyType != 1))
1024 OC_LOG(DEBUG, TAG, "OCServer is starting...");
1026 if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
1028 OC_LOG(ERROR, TAG, "OCStack init error");
1031 #ifdef WITH_PRESENCE
1032 if (OCStartPresence(0) != OC_STACK_OK)
1034 OC_LOG(ERROR, TAG, "OCStack presence/discovery error");
1039 OCSetDefaultDeviceEntityHandler(OCDeviceEntityHandlerCb);
1041 OCStackResult platformRegistrationResult =
1042 SetPlatformInfo(platformID, manufacturerName, manufacturerUrl, modelNumber,
1043 dateOfManufacture, platformVersion, operatingSystemVersion, hardwareVersion,
1044 firmwareVersion, supportUrl, systemTime);
1046 if (platformRegistrationResult != OC_STACK_OK)
1048 OC_LOG(INFO, TAG, "Platform info setting failed locally!");
1049 exit (EXIT_FAILURE);
1052 platformRegistrationResult = OCSetPlatformInfo(platformInfo);
1054 if (platformRegistrationResult != OC_STACK_OK)
1056 OC_LOG(INFO, TAG, "Platform Registration failed!");
1057 exit (EXIT_FAILURE);
1061 * Declare and create the example resource: Light
1063 createLightResource(gResourceUri, &Light);
1065 // Initialize observations data structure for the resource
1066 for (uint8_t i = 0; i < SAMPLE_MAX_NUM_OBSERVATIONS; i++)
1068 interestedObservers[i].valid = false;
1072 * Create a thread for changing the representation of the Light
1074 pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)NULL);
1077 * Create a thread for generating changes that cause presence notifications
1078 * to be sent to clients
1081 #ifdef WITH_PRESENCE
1082 pthread_create(&threadId_presence, NULL, presenceNotificationGenerator, (void *)NULL);
1085 // Break from loop with Ctrl-C
1086 OC_LOG(INFO, TAG, "Entering ocserver main loop...");
1087 DeletePlatformInfo();
1088 signal(SIGINT, handleSigInt);
1091 if (OCProcess() != OC_STACK_OK)
1093 OC_LOG(ERROR, TAG, "OCStack process error");
1101 * Cancel the Light thread and wait for it to terminate
1103 pthread_cancel(threadId);
1104 pthread_join(threadId, NULL);
1105 pthread_cancel(threadId_presence);
1106 pthread_join(threadId_presence, NULL);
1108 OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
1110 if (OCStop() != OC_STACK_OK)
1112 OC_LOG(ERROR, TAG, "OCStack process error");