Modifying version number for building on tizen 3.0
[platform/upstream/iotivity.git] / resource / csdk / stack / samples / arduino / SimpleClientServer / ocserver / ocserver.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 // Do not remove the include below
22 #include "Arduino.h"
23
24 #include "logger.h"
25 #include "ocstack.h"
26 #include <string.h>
27
28 #ifdef ARDUINOWIFI
29 // Arduino WiFi Shield
30 #include <SPI.h>
31 #include <WiFi.h>
32 #include <WiFiUdp.h>
33 #else
34 // Arduino Ethernet Shield
35 #include <EthernetServer.h>
36 #include <Ethernet.h>
37 #include <Dns.h>
38 #include <EthernetClient.h>
39 #include <util.h>
40 #include <EthernetUdp.h>
41 #include <Dhcp.h>
42 #endif
43
44 const char *getResult(OCStackResult result);
45
46 PROGMEM const char TAG[] = "ArduinoServer";
47
48 int gLightUnderObservation = 0;
49 void createLightResource();
50
51 /* Structure to represent a Light resource */
52 typedef struct LIGHTRESOURCE{
53     OCResourceHandle handle;
54     bool state;
55     int power;
56 } LightResource;
57
58 static LightResource Light;
59
60 static char responsePayloadGet[] = "{\"href\":\"/a/light\",\"rep\":{\"state\":\"on\",\"power\":10}}";
61 static char responsePayloadPut[] = "{\"href\":\"/a/light\",\"rep\":{\"state\":\"off\",\"power\":0}}";
62
63 /// This is the port which Arduino Server will use for all unicast communication with it's peers
64 static uint16_t OC_WELL_KNOWN_PORT = 5683;
65
66 #ifdef ARDUINOWIFI
67 // Arduino WiFi Shield
68 // Note : Arduino WiFi Shield currently does NOT support multicast and therefore
69 // this server will NOT be listening on 224.0.1.187 multicast address.
70
71 /// WiFi Shield firmware with Intel patches
72 static const char INTEL_WIFI_SHIELD_FW_VER[] = "1.2.0";
73
74 /// WiFi network info and credentials
75 char ssid[] = "mDNSAP";
76 char pass[] = "letmein9";
77
78 int ConnectToNetwork()
79 {
80     char *fwVersion;
81     int status = WL_IDLE_STATUS;
82     // check for the presence of the shield:
83     if (WiFi.status() == WL_NO_SHIELD)
84     {
85         OC_LOG(ERROR, TAG, PCF("WiFi shield not present"));
86         return -1;
87     }
88
89     // Verify that WiFi Shield is running the firmware with all UDP fixes
90     fwVersion = WiFi.firmwareVersion();
91     OC_LOG_V(INFO, TAG, "WiFi Shield Firmware version %s", fwVersion);
92     if ( strncmp(fwVersion, INTEL_WIFI_SHIELD_FW_VER, sizeof(INTEL_WIFI_SHIELD_FW_VER)) !=0 )
93     {
94         OC_LOG(DEBUG, TAG, PCF("!!!!! Upgrade WiFi Shield Firmware version !!!!!!"));
95         return -1;
96     }
97
98     // attempt to connect to Wifi network:
99     while (status != WL_CONNECTED)
100     {
101         OC_LOG_V(INFO, TAG, "Attempting to connect to SSID: %s", ssid);
102         status = WiFi.begin(ssid,pass);
103
104         // wait 10 seconds for connection:
105         delay(10000);
106     }
107     OC_LOG(DEBUG, TAG, PCF("Connected to wifi"));
108
109     IPAddress ip = WiFi.localIP();
110     OC_LOG_V(INFO, TAG, "IP Address:  %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
111     return 0;
112 }
113 #else
114 // Arduino Ethernet Shield
115 int ConnectToNetwork()
116 {
117     // Note: ****Update the MAC address here with your shield's MAC address****
118     uint8_t ETHERNET_MAC[] = {0x90, 0xA2, 0xDA, 0x0E, 0xC4, 0x05};
119     uint8_t error = Ethernet.begin(ETHERNET_MAC);
120     if (error  == 0)
121     {
122         OC_LOG_V(ERROR, TAG, "error is: %d", error);
123         return -1;
124     }
125
126     IPAddress ip = Ethernet.localIP();
127     OC_LOG_V(INFO, TAG, "IP Address:  %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
128     return 0;
129 }
130 #endif //ARDUINOWIFI
131
132 // On Arduino Atmel boards with Harvard memory architecture, the stack grows
133 // downwards from the top and the heap grows upwards. This method will print
134 // the distance(in terms of bytes) between those two.
135 // See here for more details :
136 // http://www.atmel.com/webdoc/AVRLibcReferenceManual/malloc_1malloc_intro.html
137 void PrintArduinoMemoryStats()
138 {
139     #ifdef ARDUINO_AVR_MEGA2560
140     //This var is declared in avr-libc/stdlib/malloc.c
141     //It keeps the largest address not allocated for heap
142     extern char *__brkval;
143     //address of tmp gives us the current stack boundry
144     int tmp;
145     OC_LOG_V(INFO, TAG, "Stack: %u         Heap: %u", (unsigned int)&tmp, (unsigned int)__brkval);
146     OC_LOG_V(INFO, TAG, "Unallocated Memory between heap and stack: %u",
147             ((unsigned int)&tmp - (unsigned int)__brkval));
148     #endif
149 }
150
151 // This is the entity handler for the registered resource.
152 // This is invoked by OCStack whenever it recevies a request for this resource.
153 OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandlerRequest * entityHandlerRequest )
154 {
155     OCEntityHandlerResult ehRet = OC_EH_OK;
156     OCEntityHandlerResponse response = {0};
157     char payload[MAX_RESPONSE_LENGTH] = {0};
158
159     if(entityHandlerRequest && (flag & OC_REQUEST_FLAG))
160     {
161         OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
162
163         if(OC_REST_GET == entityHandlerRequest->method)
164         {
165             size_t responsePayloadGetLength = strlen(responsePayloadGet);
166             if (responsePayloadGetLength < (sizeof(payload) - 1))
167             {
168                 strncpy(payload, responsePayloadGet, responsePayloadGetLength);
169             }
170             else
171             {
172                 ehRet = OC_EH_ERROR;
173             }
174         }
175         else if(OC_REST_PUT == entityHandlerRequest->method)
176         {
177             //Do something with the 'put' payload
178             size_t responsePayloadPutLength = strlen(responsePayloadPut);
179             if (responsePayloadPutLength < (sizeof(payload) - 1))
180             {
181                 strncpy((char *)payload, responsePayloadPut, responsePayloadPutLength);
182             }
183             else
184             {
185                 ehRet = OC_EH_ERROR;
186             }
187         }
188
189         if (ehRet == OC_EH_OK)
190         {
191             // Format the response.  Note this requires some info about the request
192             response.requestHandle = entityHandlerRequest->requestHandle;
193             response.resourceHandle = entityHandlerRequest->resource;
194             response.ehResult = ehRet;
195             response.payload = (unsigned char *)payload;
196             response.payloadSize = strlen(payload);
197             response.numSendVendorSpecificHeaderOptions = 0;
198             memset(response.sendVendorSpecificHeaderOptions, 0, sizeof response.sendVendorSpecificHeaderOptions);
199             memset(response.resourceUri, 0, sizeof response.resourceUri);
200             // Indicate that response is NOT in a persistent buffer
201             response.persistentBufferFlag = 0;
202
203             // Send the response
204             if (OCDoResponse(&response) != OC_STACK_OK)
205             {
206                 OC_LOG(ERROR, TAG, "Error sending response");
207                 ehRet = OC_EH_ERROR;
208             }
209         }
210     }
211     if (entityHandlerRequest && (flag & OC_OBSERVE_FLAG))
212     {
213         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
214         {
215             OC_LOG (INFO, TAG, PCF("Received OC_OBSERVE_REGISTER from client"));
216             gLightUnderObservation = 1;
217         }
218         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
219         {
220             OC_LOG (INFO, TAG, PCF("Received OC_OBSERVE_DEREGISTER from client"));
221         }
222     }
223
224     return ehRet;
225 }
226
227 // This method is used to display 'Observe' functionality of OC Stack.
228 static uint8_t modCounter = 0;
229 void *ChangeLightRepresentation (void *param)
230 {
231     (void)param;
232     OCStackResult result = OC_STACK_ERROR;
233     modCounter += 1;
234     if(modCounter % 10 == 0)  // Matching the timing that the Linux Sample Server App uses for the same functionality.
235     {
236         Light.power += 5;
237         if (gLightUnderObservation)
238         {
239             OC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
240             result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
241             if (OC_STACK_NO_OBSERVERS == result)
242             {
243                 gLightUnderObservation = 0;
244             }
245         }
246     }
247     return NULL;
248 }
249
250 //The setup function is called once at startup of the sketch
251 void setup()
252 {
253     // Add your initialization code here
254     // Note : This will initialize Serial port on Arduino at 115200 bauds
255     OC_LOG_INIT();
256     OC_LOG(DEBUG, TAG, PCF("OCServer is starting..."));
257     uint16_t port = OC_WELL_KNOWN_PORT;
258
259     // Connect to Ethernet or WiFi network
260     if (ConnectToNetwork() != 0)
261     {
262         OC_LOG(ERROR, TAG, PCF("Unable to connect to network"));
263         return;
264     }
265
266     // Initialize the OC Stack in Server mode
267     if (OCInit(NULL, port, OC_SERVER) != OC_STACK_OK)
268     {
269         OC_LOG(ERROR, TAG, PCF("OCStack init error"));
270         return;
271     }
272
273     // Declare and create the example resource: Light
274     createLightResource();
275 }
276
277 // The loop function is called in an endless loop
278 void loop()
279 {
280     // This artificial delay is kept here to avoid endless spinning
281     // of Arduino microcontroller. Modify it as per specfic application needs.
282     delay(2000);
283
284     // This call displays the amount of free SRAM available on Arduino
285     PrintArduinoMemoryStats();
286
287     // Give CPU cycles to OCStack to perform send/recv and other OCStack stuff
288     if (OCProcess() != OC_STACK_OK)
289     {
290         OC_LOG(ERROR, TAG, PCF("OCStack process error"));
291         return;
292     }
293     ChangeLightRepresentation(NULL);
294 }
295
296 void createLightResource()
297 {
298     Light.state = false;
299     OCStackResult res = OCCreateResource(&Light.handle,
300             "core.light",
301             "oc.mi.def",
302             "/a/light",
303             OCEntityHandlerCb,
304             OC_DISCOVERABLE|OC_OBSERVABLE);
305     OC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
306 }
307
308 const char *getResult(OCStackResult result) {
309     switch (result) {
310     case OC_STACK_OK:
311         return "OC_STACK_OK";
312     case OC_STACK_INVALID_URI:
313         return "OC_STACK_INVALID_URI";
314     case OC_STACK_INVALID_QUERY:
315         return "OC_STACK_INVALID_QUERY";
316     case OC_STACK_INVALID_IP:
317         return "OC_STACK_INVALID_IP";
318     case OC_STACK_INVALID_PORT:
319         return "OC_STACK_INVALID_PORT";
320     case OC_STACK_INVALID_CALLBACK:
321         return "OC_STACK_INVALID_CALLBACK";
322     case OC_STACK_INVALID_METHOD:
323         return "OC_STACK_INVALID_METHOD";
324     case OC_STACK_NO_MEMORY:
325         return "OC_STACK_NO_MEMORY";
326     case OC_STACK_COMM_ERROR:
327         return "OC_STACK_COMM_ERROR";
328     case OC_STACK_INVALID_PARAM:
329         return "OC_STACK_INVALID_PARAM";
330     case OC_STACK_NOTIMPL:
331         return "OC_STACK_NOTIMPL";
332     case OC_STACK_NO_RESOURCE:
333         return "OC_STACK_NO_RESOURCE";
334     case OC_STACK_RESOURCE_ERROR:
335         return "OC_STACK_RESOURCE_ERROR";
336     case OC_STACK_SLOW_RESOURCE:
337         return "OC_STACK_SLOW_RESOURCE";
338     case OC_STACK_NO_OBSERVERS:
339         return "OC_STACK_NO_OBSERVERS";
340     case OC_STACK_ERROR:
341         return "OC_STACK_ERROR";
342     default:
343         return "UNKNOWN";
344     }
345 }