iotivity 0.9.0
[platform/upstream/iotivity.git] / service / soft-sensor-manager / SampleApp / arduino / THSensorApp / src / thserver.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 #define dht11_pin 12
25
26 #include "logger.h"
27 #include "ocstack.h"
28 #include <string.h>
29
30 #ifdef ARDUINOWIFI
31 // Arduino WiFi Shield
32 #include <SPI.h>
33 #include <WiFi.h>
34 #include <WiFiUdp.h>
35 #else
36 // Arduino Ethernet Shield
37 #include <EthernetServer.h>
38 #include <Ethernet.h>
39 #include <Dns.h>
40 #include <EthernetClient.h>
41 #include <util.h>
42 #include <EthernetUdp.h>
43 #include <Dhcp.h>
44 #endif
45
46 const char *getResult(OCStackResult result);
47
48 PROGMEM const char TAG[] = "ArduinoServer";
49
50 int g_THUnderObservation = 0;
51 void createTHResource();
52 typedef struct THRESOURCE
53 {
54     OCResourceHandle m_handle;
55     int m_temp;
56     int m_humid;
57 } THResource;
58
59 static THResource TH;
60
61 /// This is the port which Arduino Server will use for all unicast communication with it's peers
62 static uint16_t OC_WELL_KNOWN_PORT = 5683;
63
64 #define JSON_BASE00 "{\"href\":\"\",\"rep\":{"
65 #define JSON_BASE01 "\"0\":\"temperature\",\"1\":\"int\",\"2\":\""
66 #define JSON_BASE02 "\",\"3\":\"humidity\",\"4\":\"int\",\"5\":\""
67 #define JSON_BASE03 "\"}}"
68
69 char temp[100];
70
71 #define LENGTH_VAR              100
72 static int base_length = 0;
73
74 bool JsonGenerator( THResource& th, char* jsonBuf, uint16_t buf_length )
75 {
76         if( (buf_length - base_length) < LENGTH_VAR )
77         {
78                 OC_LOG_V(ERROR, TAG, "Error : length is very long.");
79                 return false;
80         }
81
82         sprintf(jsonBuf, JSON_BASE00 JSON_BASE01"%d",th.m_temp);
83         sprintf(jsonBuf+strlen(jsonBuf), JSON_BASE02"%d"JSON_BASE03, th.m_humid);
84
85         Serial.println(jsonBuf);
86
87         return true;
88 }
89
90 byte read_dht11_dat()
91 {
92     byte i = 0;
93     byte result = 0;
94     for (i = 0; i < 8; i++)
95     {
96         while (!digitalRead(dht11_pin));
97         delayMicroseconds(30);
98         if (digitalRead(dht11_pin) != 0 )
99             bitSet(result, 7 - i);
100         while (digitalRead(dht11_pin));
101     }
102     return result;
103 }
104
105 #ifdef ARDUINOWIFI
106 // Arduino WiFi Shield
107 // Note : Arduino WiFi Shield currently does NOT support multicast and therefore
108 // this server will NOT be listening on 224.0.1.187 multicast address.
109
110 /// WiFi Shield firmware with Intel patches
111 static const char INTEL_WIFI_SHIELD_FW_VER[] = "1.2.0";
112
113 /// WiFi network info and credentials
114 char ssid[] = "SoftSensor_AP";
115 char pass[] = "1234567890";
116
117 //char ssid[] = "Iotivity-1";
118 //char pass[] = "1234567890";
119
120 int ConnectToNetwork()
121 {
122     char *fwVersion;
123     int status = WL_IDLE_STATUS;
124     // check for the presence of the shield:
125     if (WiFi.status() == WL_NO_SHIELD)
126     {
127         OC_LOG(ERROR, TAG, PCF("WiFi shield not present"));
128         return -1;
129     }
130
131     // Verify that WiFi Shield is running the firmware with all UDP fixes
132     fwVersion = WiFi.firmwareVersion();
133     OC_LOG_V(INFO, TAG, "WiFi Shield Firmware version %s", fwVersion);
134     if ( strncmp(fwVersion, INTEL_WIFI_SHIELD_FW_VER, sizeof(INTEL_WIFI_SHIELD_FW_VER)) != 0 )
135     {
136         OC_LOG(DEBUG, TAG, PCF("!!!!! Upgrade WiFi Shield Firmware version !!!!!!"));
137         return -1;
138     }
139
140     // attempt to connect to Wifi network:
141     while (status != WL_CONNECTED)
142     {
143         OC_LOG_V(INFO, TAG, "Attempting to connect to SSID: %s", ssid);
144         status = WiFi.begin(ssid, pass);
145
146         // wait 10 seconds for connection:
147         delay(10000);
148     }
149     OC_LOG(DEBUG, TAG, PCF("Connected to wifi"));
150
151     IPAddress ip = WiFi.localIP();
152     OC_LOG_V(INFO, TAG, "IP Address:  %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
153     return 0;
154 }
155 #else
156 // Arduino Ethernet Shield
157 int ConnectToNetwork()
158 {
159     // Note: ****Update the MAC address here with your shield's MAC address****
160     uint8_t ETHERNET_MAC[] = {0x90, 0xA2, 0xDA, 0x0E, 0xB8, 0xAC};
161
162     uint8_t error = Ethernet.begin(ETHERNET_MAC);
163     if (error  == 0)
164     {
165         OC_LOG_V(ERROR, TAG, "error is: %d", error);
166         return -1;
167     }
168     IPAddress ip = Ethernet.localIP();
169     OC_LOG_V(INFO, TAG, "IP Address:  %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
170     return 0;
171 }
172 #endif //ARDUINOWIFI
173
174 // On Arduino Atmel boards with Harvard memory architecture, the stack grows
175 // downwards from the top and the heap grows upwards. This method will print
176 // the distance(in terms of bytes) between those two.
177 // See here for more details :
178 // http://www.atmel.com/webdoc/AVRLibcReferenceManual/malloc_1malloc_intro.html
179 void PrintArduinoMemoryStats()
180 {
181 #ifdef ARDUINO_AVR_MEGA2560
182     //This var is declared in avr-libc/stdlib/malloc.c
183     //It keeps the largest address not allocated for heap
184     extern char *__brkval;
185     //address of tmp gives us the current stack boundry
186     int tmp;
187     OC_LOG_V(INFO, TAG, "Stack: %u         Heap: %u", (unsigned int)&tmp, (unsigned int)__brkval);
188     OC_LOG_V(INFO, TAG, "Unallocated Memory between heap and stack: %u",
189              ((unsigned int)&tmp - (unsigned int)__brkval));
190 #endif
191 }
192
193
194 // This is the entity handler for the registered resource.
195 // This is invoked by OCStack whenever it recevies a request for this resource.
196 OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandlerRequest * entityHandlerRequest )
197 {
198     OCEntityHandlerResult ehRet = OC_EH_OK;
199     OCEntityHandlerResponse response = {0};
200     char payload[MAX_RESPONSE_LENGTH] = {0};
201
202     if(entityHandlerRequest && (flag & OC_REQUEST_FLAG))
203     {
204         OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
205         if(OC_REST_GET == entityHandlerRequest->method)
206         {
207                 if(JsonGenerator( TH, payload, MAX_RESPONSE_LENGTH))
208                  {
209                  }
210            else
211             {
212                 ehRet = OC_EH_ERROR;
213             }
214         }
215         if(OC_REST_PUT == entityHandlerRequest->method)
216         {
217             //Do something with the 'put' payload
218             if (JsonGenerator( TH, payload, MAX_RESPONSE_LENGTH))
219             {
220             }
221             else
222             {
223                 ehRet = OC_EH_ERROR;
224             }
225          }
226
227         if (ehRet == OC_EH_OK)
228                 {
229                         // Format the response.  Note this requires some info about the request
230                         response.requestHandle = entityHandlerRequest->requestHandle;
231                         response.resourceHandle = entityHandlerRequest->resource;
232                         response.ehResult = ehRet;
233                         response.payload = (unsigned char *)payload;
234                         response.payloadSize = strlen(payload);
235                         response.numSendVendorSpecificHeaderOptions = 0;
236                         memset(response.sendVendorSpecificHeaderOptions, 0, sizeof response.sendVendorSpecificHeaderOptions);
237                         memset(response.resourceUri, 0, sizeof response.resourceUri);
238                         // Indicate that response is NOT in a persistent buffer
239                         response.persistentBufferFlag = 0;
240
241                         // Send the response
242                         if (OCDoResponse(&response) != OC_STACK_OK)
243                         {
244                                 OC_LOG(ERROR, TAG, "Error sending response");
245                                 ehRet = OC_EH_ERROR;
246                         }
247                 }
248     }
249     if (entityHandlerRequest && (flag & OC_OBSERVE_FLAG))
250     {
251         if (OC_OBSERVE_REGISTER == entityHandlerRequest->obsInfo.action)
252         {
253             OC_LOG (INFO, TAG, PCF("Received OC_OBSERVE_REGISTER from client"));
254             g_THUnderObservation = 1;
255         }
256         else if (OC_OBSERVE_DEREGISTER == entityHandlerRequest->obsInfo.action)
257         {
258             OC_LOG (INFO, TAG, PCF("Received OC_OBSERVE_DEREGISTER from client"));
259         }
260     }
261
262     return ehRet;
263 }
264
265 // This method is used to display 'Observe' functionality of OC Stack.
266 static uint8_t modCounter = 0;
267 void *ChangeTHRepresentation (void *param)
268 {
269     (void)param;
270     OCStackResult result = OC_STACK_ERROR;
271     modCounter += 1;
272     if (modCounter % 10 ==
273         0) // Matching the timing that the Linux Sample Server App uses for the same functionality.
274     {
275
276         byte dht11_dat[5];
277         byte i;// start condition
278
279         digitalWrite(dht11_pin, LOW);
280         delay(18);
281         digitalWrite(dht11_pin, HIGH);
282         delayMicroseconds(1);
283         pinMode(dht11_pin, INPUT);
284         delayMicroseconds(40);
285
286         if (digitalRead(dht11_pin))
287         {
288             Serial.println("dht11 start condition 1 not met"); // wait for DHT response signal: LOW
289             delay(1000);
290             return NULL;
291         }
292         delayMicroseconds(80);
293         if (!digitalRead(dht11_pin))
294         {
295             Serial.println("dht11 start condition 2 not met");  //wair for second response signal:HIGH
296             return NULL;
297         }
298
299         delayMicroseconds(80);// now ready for data reception
300         for (i = 0; i < 5; i++)
301         {
302             dht11_dat[i] = read_dht11_dat();
303         }  //recieved 40 bits data. Details are described in datasheet
304
305         pinMode(dht11_pin, OUTPUT);
306         digitalWrite(dht11_pin, HIGH);
307         byte dht11_check_sum = dht11_dat[0] + dht11_dat[2]; // check check_sum
308         if (dht11_dat[4] != dht11_check_sum)
309         {
310             Serial.println("DHT11 checksum error");
311         }
312         Serial.print("Current humdity = ");
313         Serial.print(dht11_dat[0], DEC);
314         Serial.print("%  ");
315         Serial.print("temperature = ");
316         Serial.print(dht11_dat[2], DEC);
317         Serial.println("C  ");
318
319         TH.m_humid = dht11_dat[0];
320         TH.m_temp = dht11_dat[2];
321
322            if (g_THUnderObservation)
323         {
324             OC_LOG_V(INFO, TAG, " =====> Notifying stack of new humid level %d\n", TH.m_humid);
325             OC_LOG_V(INFO, TAG, " =====> Notifying stack of new temp level %d\n", TH.m_temp);
326
327             result = OCNotifyAllObservers (TH.m_handle, OC_NA_QOS);
328
329             if (OC_STACK_NO_OBSERVERS == result)
330             {
331                 g_THUnderObservation = 0;
332             }
333         }
334     }
335     return NULL;
336 }
337
338
339
340 //The setup function is called once at startup of the sketch
341 void setup()
342 {
343     pinMode(dht11_pin, OUTPUT);
344     digitalWrite(dht11_pin, HIGH);
345
346     // Add your initialization code here
347     OC_LOG_INIT();
348
349     OC_LOG(DEBUG, TAG, PCF("OCServer is starting..."));
350     uint16_t port = OC_WELL_KNOWN_PORT;
351
352     // Connect to Ethernet or WiFi network
353     if (ConnectToNetwork() != 0)
354     {
355         OC_LOG(ERROR, TAG, "Unable to connect to network");
356         return;
357     }
358
359     // Initialize the OC Stack in Server mode
360     if (OCInit(NULL, port, OC_SERVER) != OC_STACK_OK)
361     {
362         OC_LOG(ERROR, TAG, PCF("OCStack init error"));
363         return;
364     }
365     OCStartPresence(60);
366     // Declare and create the example resource: TH
367     createTHResource();
368
369 }
370
371 // The loop function is called in an endless loop
372 void loop()
373 {
374     // This artificial delay is kept here to avoid endless spinning
375     // of Arduino microcontroller. Modify it as per specfic application needs.
376     delay(2000);
377
378     // This call displays the amount of free SRAM available on Arduino
379     PrintArduinoMemoryStats();
380
381     if (OCProcess() != OC_STACK_OK)
382     {
383         OC_LOG(ERROR, TAG, PCF("OCStack process error"));
384         return;
385     }
386     ChangeTHRepresentation(NULL);
387 }
388
389 void createTHResource()
390 {
391     TH.m_humid = 0;
392     TH.m_temp = 0;
393
394     OCStackResult res = OCCreateResource(&TH.m_handle,
395                                          "SoftSensorManager.Sensor",
396                                          "oc.mi.def",
397                                          "/Thing_TempHumSensor1",
398                                          OCEntityHandlerCb,
399                                          OC_DISCOVERABLE | OC_OBSERVABLE);
400     OC_LOG_V(INFO, TAG, "Created TH resource with result: %s", getResult(res));
401 }
402
403 const char *getResult(OCStackResult result)
404 {
405     switch (result)
406     {
407         case OC_STACK_OK:
408             return "OC_STACK_OK";
409         case OC_STACK_INVALID_URI:
410             return "OC_STACK_INVALID_URI";
411         case OC_STACK_INVALID_QUERY:
412             return "OC_STACK_INVALID_QUERY";
413         case OC_STACK_INVALID_IP:
414             return "OC_STACK_INVALID_IP";
415         case OC_STACK_INVALID_PORT:
416             return "OC_STACK_INVALID_PORT";
417         case OC_STACK_INVALID_CALLBACK:
418             return "OC_STACK_INVALID_CALLBACK";
419         case OC_STACK_INVALID_METHOD:
420             return "OC_STACK_INVALID_METHOD";
421         case OC_STACK_NO_MEMORY:
422             return "OC_STACK_NO_MEMORY";
423         case OC_STACK_COMM_ERROR:
424             return "OC_STACK_COMM_ERROR";
425         case OC_STACK_INVALID_PARAM:
426             return "OC_STACK_INVALID_PARAM";
427         case OC_STACK_NOTIMPL:
428             return "OC_STACK_NOTIMPL";
429         case OC_STACK_NO_RESOURCE:
430             return "OC_STACK_NO_RESOURCE";
431         case OC_STACK_RESOURCE_ERROR:
432             return "OC_STACK_RESOURCE_ERROR";
433         case OC_STACK_SLOW_RESOURCE:
434             return "OC_STACK_SLOW_RESOURCE";
435         case OC_STACK_NO_OBSERVERS:
436             return "OC_STACK_NO_OBSERVERS";
437         case OC_STACK_ERROR:
438             return "OC_STACK_ERROR";
439         default:
440             return "UNKNOWN";
441     }
442 }