examples: Add notice about using experimental API
[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 "ocstack.h"
25 #include "ocpayload.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 #elif defined ARDUINOETH
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 /// This example is using experimental API, so there is no guarantee of support for future release,
44 /// nor any there any guarantee that breaking changes will not occur across releases.
45 #include "experimental/logger.h"
46
47 const char *getResult(OCStackResult result);
48
49 #define TAG "ArduinoServer"
50
51 int gLightUnderObservation = 0;
52 void createLightResource();
53
54 /* Structure to represent a Light resource */
55 typedef struct LIGHTRESOURCE{
56     OCResourceHandle handle;
57     bool state;
58     int power;
59 } LightResource;
60
61 static LightResource Light;
62
63 #ifdef ARDUINOWIFI
64 // Arduino WiFi Shield
65 // Note : Arduino WiFi Shield currently does NOT support multicast and therefore
66 // this server will NOT be listening on 224.0.1.187 multicast address.
67
68 static const char ARDUINO_WIFI_SHIELD_UDP_FW_VER[] = "1.1.0";
69
70 /// WiFi Shield firmware with Intel patches
71 static const char INTEL_WIFI_SHIELD_FW_VER[] = "1.2.0";
72
73 /// WiFi network info and credentials
74 char ssid[] = "mDNSAP";
75 char pass[] = "letmein9";
76
77 int ConnectToNetwork()
78 {
79     char *fwVersion;
80     int status = WL_IDLE_STATUS;
81     // check for the presence of the shield:
82     if (WiFi.status() == WL_NO_SHIELD)
83     {
84         OIC_LOG(ERROR, TAG, ("WiFi shield not present"));
85         return -1;
86     }
87
88     // Verify that WiFi Shield is running the firmware with all UDP fixes
89     fwVersion = WiFi.firmwareVersion();
90     OIC_LOG_V(INFO, TAG, "WiFi Shield Firmware version %s", fwVersion);
91     if ( strncmp(fwVersion, ARDUINO_WIFI_SHIELD_UDP_FW_VER, sizeof(ARDUINO_WIFI_SHIELD_UDP_FW_VER)) !=0 )
92     {
93         OIC_LOG(DEBUG, TAG, ("!!!!! Upgrade WiFi Shield Firmware version !!!!!!"));
94         return -1;
95     }
96
97     // attempt to connect to Wifi network:
98     while (status != WL_CONNECTED)
99     {
100         OIC_LOG_V(INFO, TAG, "Attempting to connect to SSID: %s", ssid);
101         status = WiFi.begin(ssid,pass);
102
103         // wait 10 seconds for connection:
104         delay(10000);
105     }
106     OIC_LOG(DEBUG, TAG, ("Connected to wifi"));
107
108     IPAddress ip = WiFi.localIP();
109     OIC_LOG_V(INFO, TAG, "IP Address:  %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
110     return 0;
111 }
112 #elif defined ARDUINOETH
113 // Arduino Ethernet Shield
114 int ConnectToNetwork()
115 {
116     // Note: ****Update the MAC address here with your shield's MAC address****
117     uint8_t ETHERNET_MAC[] = {0x90, 0xA2, 0xDA, 0x0E, 0xC4, 0x05};
118     uint8_t error = Ethernet.begin(ETHERNET_MAC);
119     if (error  == 0)
120     {
121         OIC_LOG_V(ERROR, TAG, "error is: %d", error);
122         return -1;
123     }
124
125     IPAddress ip = Ethernet.localIP();
126     OIC_LOG_V(INFO, TAG, "IP Address:  %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
127     return 0;
128 }
129 #endif //ARDUINOWIFI
130
131 // On Arduino Atmel boards with Harvard memory architecture, the stack grows
132 // downwards from the top and the heap grows upwards. This method will print
133 // the distance(in terms of bytes) between those two.
134 // See here for more details :
135 // http://www.atmel.com/webdoc/AVRLibcReferenceManual/malloc_1malloc_intro.html
136 void PrintArduinoMemoryStats()
137 {
138     #ifdef ARDUINO_AVR_MEGA2560
139     //This var is declared in avr-libc/stdlib/malloc.c
140     //It keeps the largest address not allocated for heap
141     extern char *__brkval;
142     //address of tmp gives us the current stack boundry
143     int tmp;
144     OIC_LOG_V(INFO, TAG, "Stack: %u         Heap: %u", (unsigned int)&tmp, (unsigned int)__brkval);
145     OIC_LOG_V(INFO, TAG, "Unallocated Memory between heap and stack: %u",
146             ((unsigned int)&tmp - (unsigned int)__brkval));
147     #endif
148 }
149
150 // This is the entity handler for the registered resource.
151 // This is invoked by OCStack whenever it recevies a request for this resource.
152 OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandlerRequest * entityHandlerRequest,
153                                         void *callbackParam)
154 {
155     OCEntityHandlerResult ehRet = OC_EH_OK;
156     OCEntityHandlerResponse response = {0};
157     OCRepPayload* payload = OCRepPayloadCreate();
158     if(!payload)
159     {
160         OIC_LOG(ERROR, TAG, ("Failed to allocate Payload"));
161         return OC_EH_ERROR;
162     }
163
164     if(entityHandlerRequest && (flag & OC_REQUEST_FLAG))
165     {
166         OIC_LOG (INFO, TAG, ("Flag includes OC_REQUEST_FLAG"));
167
168         if(OC_REST_GET == entityHandlerRequest->method)
169         {
170             OCRepPayloadSetUri(payload, "/a/light");
171             OCRepPayloadSetPropBool(payload, "state", true);
172             OCRepPayloadSetPropInt(payload, "power", 10);
173         }
174         else if(OC_REST_PUT == entityHandlerRequest->method)
175         {
176             //Do something with the 'put' payload
177             OCRepPayloadSetUri(payload, "/a/light");
178             OCRepPayloadSetPropBool(payload, "state", false);
179             OCRepPayloadSetPropInt(payload, "power", 0);
180         }
181
182         if (ehRet == OC_EH_OK)
183         {
184             // Format the response.  Note this requires some info about the request
185             response.requestHandle = entityHandlerRequest->requestHandle;
186             response.resourceHandle = entityHandlerRequest->resource;
187             response.ehResult = ehRet;
188             response.payload = (OCPayload*) payload;
189             response.numSendVendorSpecificHeaderOptions = 0;
190             memset(response.sendVendorSpecificHeaderOptions, 0,
191                     sizeof response.sendVendorSpecificHeaderOptions);
192             memset(response.resourceUri, 0, sizeof response.resourceUri);
193             // Indicate that response is NOT in a persistent buffer
194             response.persistentBufferFlag = 0;
195
196             // Send the response
197             if (OCDoResponse(&response) != OC_STACK_OK)
198             {
199                 OIC_LOG(ERROR, TAG, "Error sending response");
200                 ehRet = OC_EH_ERROR;
201             }
202         }
203     }
204     if (entityHandlerRequest && (flag & OC_OBSERVE_FLAG))
205     {
206         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
207         {
208             OIC_LOG (INFO, TAG, ("Received OC_OBSERVE_REGISTER from client"));
209             gLightUnderObservation = 1;
210         }
211         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
212         {
213             OIC_LOG (INFO, TAG, ("Received OC_OBSERVE_DEREGISTER from client"));
214             gLightUnderObservation = 0;
215         }
216     }
217     OCRepPayloadDestroy(payload);
218     return ehRet;
219 }
220
221 // This method is used to display 'Observe' functionality of OC Stack.
222 static uint8_t modCounter = 0;
223 void *ChangeLightRepresentation (void *param)
224 {
225     (void)param;
226     OCStackResult result = OC_STACK_ERROR;
227     modCounter += 1;
228     // Matching the timing that the Linux Sample Server App uses for the same functionality.
229     if(modCounter % 10 == 0)
230     {
231         Light.power += 5;
232         if (gLightUnderObservation)
233         {
234             OIC_LOG_V(INFO, TAG, " =====> Notifying stack of new power level %d\n", Light.power);
235             result = OCNotifyAllObservers (Light.handle, OC_NA_QOS);
236             if (OC_STACK_NO_OBSERVERS == result)
237             {
238                 gLightUnderObservation = 0;
239             }
240         }
241     }
242     return NULL;
243 }
244
245 //The setup function is called once at startup of the sketch
246 void setup()
247 {
248     // Add your initialization code here
249     // Note : This will initialize Serial port on Arduino at 115200 bauds
250     OIC_LOG_INIT();
251     OIC_LOG(DEBUG, TAG, ("OCServer is starting..."));
252
253     // Connect to Ethernet or WiFi network
254 #if defined(ARDUINOWIFI) || defined(ARDUINOETH)
255     if (ConnectToNetwork() != 0)
256     {
257         OIC_LOG(ERROR, TAG, ("Unable to connect to network"));
258         return;
259     }
260 #endif
261
262     // Initialize the OC Stack in Server mode
263     if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK)
264     {
265         OIC_LOG(ERROR, TAG, ("OCStack init error"));
266         return;
267     }
268
269     // Declare and create the example resource: Light
270     createLightResource();
271 }
272
273 // The loop function is called in an endless loop
274 void loop()
275 {
276     // This artificial delay is kept here to avoid endless spinning
277     // of Arduino microcontroller. Modify it as per specific application needs.
278     delay(2000);
279
280     // This call displays the amount of free SRAM available on Arduino
281     PrintArduinoMemoryStats();
282
283     // Give CPU cycles to OCStack to perform send/recv and other OCStack stuff
284     if (OCProcess() != OC_STACK_OK)
285     {
286         OIC_LOG(ERROR, TAG, ("OCStack process error"));
287         return;
288     }
289     ChangeLightRepresentation(NULL);
290 }
291
292 void createLightResource()
293 {
294     Light.state = false;
295     OCStackResult res = OCCreateResource(&Light.handle,
296             "core.light",
297             OC_RSRVD_INTERFACE_DEFAULT,
298             "/a/light",
299             OCEntityHandlerCb,
300             NULL,
301             OC_DISCOVERABLE|OC_OBSERVABLE);
302     OIC_LOG_V(INFO, TAG, "Created Light resource with result: %s", getResult(res));
303 }
304
305 const char *getResult(OCStackResult result) {
306     switch (result) {
307     case OC_STACK_OK:
308         return "OC_STACK_OK";
309     case OC_STACK_INVALID_URI:
310         return "OC_STACK_INVALID_URI";
311     case OC_STACK_INVALID_QUERY:
312         return "OC_STACK_INVALID_QUERY";
313     case OC_STACK_INVALID_IP:
314         return "OC_STACK_INVALID_IP";
315     case OC_STACK_INVALID_PORT:
316         return "OC_STACK_INVALID_PORT";
317     case OC_STACK_INVALID_CALLBACK:
318         return "OC_STACK_INVALID_CALLBACK";
319     case OC_STACK_INVALID_METHOD:
320         return "OC_STACK_INVALID_METHOD";
321     case OC_STACK_NO_MEMORY:
322         return "OC_STACK_NO_MEMORY";
323     case OC_STACK_COMM_ERROR:
324         return "OC_STACK_COMM_ERROR";
325     case OC_STACK_INVALID_PARAM:
326         return "OC_STACK_INVALID_PARAM";
327     case OC_STACK_NOTIMPL:
328         return "OC_STACK_NOTIMPL";
329     case OC_STACK_NO_RESOURCE:
330         return "OC_STACK_NO_RESOURCE";
331     case OC_STACK_RESOURCE_ERROR:
332         return "OC_STACK_RESOURCE_ERROR";
333     case OC_STACK_SLOW_RESOURCE:
334         return "OC_STACK_SLOW_RESOURCE";
335     case OC_STACK_NO_OBSERVERS:
336         return "OC_STACK_NO_OBSERVERS";
337     case OC_STACK_ERROR:
338         return "OC_STACK_ERROR";
339     default:
340         return "UNKNOWN";
341     }
342 }
343