59906b06db5346204a9898ff39bd97313a15712c
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / wifi_adapter / arduino / cawifiserver.cpp
1 /******************************************************************
2 *
3 * Copyright 2014 Samsung Electronics 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 #include "cawifiinterface.h"
22
23 #include <Arduino.h>
24 #include <WiFi.h>
25 #include <WiFiUdp.h>
26 #include <SPI.h>
27 #include <utility/server_drv.h>
28 #include <utility/wifi_drv.h>
29 #include <IPAddress.h>
30 #include <TimedAction.h>
31
32 #include "logger.h"
33 #include "cacommon.h"
34 #include "cainterface.h"
35 #include "caadapterinterface.h"
36 #include "cawifiadapter.h"
37 #include "caadapterutils.h"
38 #include "oic_malloc.h"
39
40 #define COAP_MAX_PDU_SIZE 320
41 #define MOD_NAME "WiFiServer"
42
43 char ssid[] = "NETGEAR99";         // your network SSID (name)
44 char pass[] = "jollysky325";            // your network password
45 int16_t status = WL_IDLE_STATUS;    // the Wifi radio's status
46
47 // Length of the IP address decimal notation string
48 #define IPNAMESIZE (16)
49
50 // Start offsets based on end of received data buffer
51 #define WIFI_RECBUF_IPADDR_OFFSET  (6)
52 #define WIFI_RECBUF_PORT_OFFSET    (2)
53
54 #define WIFI_RECBUF_IPADDR_SIZE    (WIFI_RECBUF_IPADDR_OFFSET - WIFI_RECBUF_PORT_OFFSET)
55 #define WIFI_RECBUF_PORT_SIZE      (WIFI_RECBUF_PORT_OFFSET - 0)
56 #define WIFI_RECBUF_FOOTER_SIZE    (WIFI_RECBUF_IPADDR_SIZE + WIFI_RECBUF_PORT_SIZE)
57
58 static CAResult_t CAArduinoInitUdpSocket(int16_t *port, int32_t *socketID);
59 static int32_t CAArduinoRecvData(int32_t sockFd, uint8_t *buf, uint32_t bufLen,
60                                  uint8_t *senderAddr, uint16_t *senderPort);
61 static CAResult_t CAArduinoGetInterfaceAddress(char *address, int32_t addrLen);
62 static void CAArduinoCheckData();
63 void CAPacketReceivedCallback(const char *ipAddress, const uint32_t port,
64                               const void *data, const uint32_t dataLength);
65
66 static CAWiFiPacketReceivedCallback gPacketReceivedCallback = NULL;
67 static int32_t gUnicastSocket = 0;
68 static bool gServerRunning = false;
69 static TimedAction gRcvAction = TimedAction(3000, CAArduinoCheckData);
70 static WiFiUDP Udp;
71
72 CAResult_t CAWiFiInitializeServer(void)
73 {
74     return CA_STATUS_OK;
75 }
76
77 void CAWiFiTerminateServer(void)
78 {
79
80 }
81
82 CAResult_t CAWiFiGetUnicastServerInfo(char **ipAddress, int *port, int32_t *serverID)
83 {
84     return CA_STATUS_OK;
85 }
86
87 CAResult_t CAArduinoInitUdpSocket(int16_t *port, int32_t *socketID)
88 {
89     OIC_LOG(DEBUG, MOD_NAME, "IN");
90     VERIFY_NON_NULL(port, MOD_NAME, "port");
91     VERIFY_NON_NULL(socketID, MOD_NAME, "socketID");
92
93     uint8_t sock;
94     //Is any socket available to work with ?
95     *socketID = -1;
96
97     sock = WiFiClass::getSocket();
98     if (sock != NO_SOCKET_AVAIL)
99     {
100         *socketID = (int32_t)sock;
101         OIC_LOG_V(ERROR, MOD_NAME, "socket: %d", *socketID);
102     }
103     else
104     {
105         OIC_LOG(DEBUG, MOD_NAME, "Error");
106         return CA_STATUS_FAILED;
107     }
108
109     OIC_LOG(DEBUG, MOD_NAME, "OUT");
110     return CA_STATUS_OK;
111 }
112
113 CAResult_t CAWiFiStartUnicastServer(const char *localAddress, int16_t *port,
114                                     const bool forceStart, int32_t *serverFD)
115 {
116     OIC_LOG(DEBUG, MOD_NAME, "IN");
117     VERIFY_NON_NULL(port, MOD_NAME, "port");
118
119     // WiFiClass WiFi;
120     if (WiFi.status() == WL_NO_SHIELD)
121     {
122         OIC_LOG(DEBUG, MOD_NAME, "Error");
123         return CA_STATUS_FAILED;
124     }
125
126     while (status != WL_CONNECTED)
127     {
128         OIC_LOG_V(ERROR, MOD_NAME, "connecting: %s", ssid);
129         status = WiFi.begin(ssid, pass);  // Connect to WPA/WPA2 network:
130
131         // wait 10 seconds for connection:
132         delay(10000);
133     }
134
135     char localIpAddress[CA_IPADDR_SIZE];
136     int32_t localIpAddressLen = sizeof(localIpAddress);
137     CAArduinoGetInterfaceAddress(localIpAddress, localIpAddressLen);
138     OIC_LOG_V(DEBUG, MOD_NAME, "address: %s", localIpAddress);
139
140     if (gServerRunning)
141     {
142         // already running
143         OIC_LOG(DEBUG, MOD_NAME, "Error");
144         return CA_STATUS_FAILED;
145     }
146
147     OIC_LOG_V(DEBUG, MOD_NAME, "port: %d", *port);
148     Udp.begin((uint16_t ) *port);
149
150     // start thread to monitor socket here
151     if (!gServerRunning)
152     {
153         gRcvAction.enable();
154         gServerRunning = true;
155     }
156     OIC_LOG(DEBUG, MOD_NAME, "OUT");
157     return CA_STATUS_OK;
158 }
159
160 CAResult_t CAWiFiStartMulticastServer(const char *localAddress, const char *multicastAddress,
161                                       const int16_t multicastPort, int32_t *serverFD)
162 {
163     // wifi shield do not support multicast
164     OIC_LOG(DEBUG, MOD_NAME, "IN");
165     OIC_LOG(DEBUG, MOD_NAME, "IN");
166     return CA_NOT_SUPPORTED;
167 }
168
169 CAResult_t CAWiFiStopUnicastServer()
170 {
171     OIC_LOG(DEBUG, MOD_NAME, "IN");
172     if (gUnicastSocket >= MAX_SOCK_NUM)
173     {
174         OIC_LOG(DEBUG, MOD_NAME, "Invalid sockfd");
175         return CA_STATUS_FAILED;
176     }
177
178     ServerDrv::stopClient(gUnicastSocket);
179     WiFiClass::_server_port[gUnicastSocket] = 0;
180     WiFiClass::_state[gUnicastSocket] = NA_STATE;
181     gUnicastSocket = 0;
182
183     // Terminate server thread
184     gRcvAction.disable();
185     gServerRunning = false;
186     OIC_LOG(DEBUG, MOD_NAME, "OUT");
187     return CA_STATUS_OK;
188 }
189
190 CAResult_t CAWiFiStopMulticastServer()
191 {
192     return CAWiFiStopUnicastServer();
193 }
194
195 void CAPacketReceivedCallback(const char *ipAddress, const uint32_t port,
196                               const void *data, const uint32_t dataLength)
197 {
198     OIC_LOG(DEBUG, MOD_NAME, "notifyCallback Entry");
199     if (gPacketReceivedCallback)
200     {
201         gPacketReceivedCallback(ipAddress, port, data, dataLength);
202         OIC_LOG(DEBUG, MOD_NAME, "Notified network packet");
203     }
204     OIC_LOG(DEBUG, MOD_NAME, "notifyCallback Exit");
205 }
206
207 void CAArduinoCheckData()
208 {
209     OIC_LOG(DEBUG, MOD_NAME, "CAACD Being called");
210     char *data = (char *)OICMalloc(COAP_MAX_PDU_SIZE);
211     int32_t dataLen = 0;
212     char addr[IPNAMESIZE] = {0};
213     uint16_t senderPort = 0;
214     int16_t packetSize = Udp.parsePacket();
215     OIC_LOG_V(DEBUG, MOD_NAME, "Rcv packet of size:%d ", packetSize);
216     senderPort = Udp.remotePort();
217     OIC_LOG_V(DEBUG, MOD_NAME, "senderport: %d", senderPort);
218     if (packetSize)
219     {
220         IPAddress remoteIp = Udp.remoteIP();
221         senderPort = Udp.remotePort();
222         OIC_LOG_V(DEBUG, MOD_NAME, "senderport: %d", senderPort);
223         sprintf(addr, "%d.%d.%d.%d", remoteIp[0], remoteIp[1], remoteIp[2], remoteIp[3]);
224         OIC_LOG_V(DEBUG, MOD_NAME, "remoteip: %s, port: %d", addr, senderPort);
225         // read the packet into packetBufffer
226         int16_t len = Udp.read(data, COAP_MAX_PDU_SIZE);
227         if (len > 0)
228         {
229             data[len] = 0;
230         }
231         CAPacketReceivedCallback(addr, senderPort, data, dataLen);
232     }
233     OICFree(data);
234 }
235
236 /// Retrieve any available data from UDP socket. This is a non-blocking call.
237 int32_t CAArduinoRecvData(int32_t sockFd, uint8_t *buf, uint32_t bufLen, uint8_t *senderAddr,
238                           uint16_t *senderPort)
239 {
240     OIC_LOG(DEBUG, MOD_NAME, "arduinoRecvData Entry");
241     /**Bug : When there are multiple UDP packets in Wiznet buffer, W5100.getRXReceivedSize
242      * will not return correct length of the first packet.
243      * Fix : Use the patch provided for arduino/libraries/Ethernet/utility/socket.cpp
244      */
245     //int32_t ret = 0;
246     uint16_t recvLen = 0;
247
248     VERIFY_NON_NULL(buf, MOD_NAME, "Invalid buf");
249     VERIFY_NON_NULL(senderAddr, MOD_NAME, "Invalid senderAddr");
250     VERIFY_NON_NULL(senderPort, MOD_NAME, "Invalid senderPort");
251
252     OIC_LOG(DEBUG, MOD_NAME, "arduinoRecvData Begin");
253     if (sockFd >= MAX_SOCK_NUM)
254     {
255         OIC_LOG(ERROR, MOD_NAME, "Invalid sockfd");
256         return -1;
257     }
258
259     recvLen = (int32_t)ServerDrv::availData((uint8_t)sockFd);
260     if (recvLen == 0)
261     {
262         return recvLen;
263     }
264
265     // Make sure buf is large enough for received data
266     if ((uint32_t)recvLen > bufLen)
267     {
268         OIC_LOG(ERROR, MOD_NAME, "Receive buffer too small");
269         return -1;
270     }
271
272     if (!ServerDrv::getDataBuf((uint8_t)sockFd, (uint8_t *)buf, &recvLen))
273     {
274         OIC_LOG(ERROR, MOD_NAME, "getDataBuf error");
275         return -1;
276     }
277
278     // Read IP Address and Port from end of receive buffer
279     memcpy(senderAddr, &buf[recvLen - WIFI_RECBUF_IPADDR_OFFSET], WIFI_RECBUF_IPADDR_SIZE);
280     // Change the endianness of the port number
281     *((uint8_t *)senderPort) = buf[recvLen - (WIFI_RECBUF_PORT_OFFSET - 1)];
282     *((uint8_t *)senderPort + 1) = buf[recvLen - (WIFI_RECBUF_PORT_OFFSET)];
283
284     recvLen -= WIFI_RECBUF_FOOTER_SIZE;
285     OIC_LOG(DEBUG, MOD_NAME, "arduinoRecvData End");
286     return (int32_t)recvLen;
287 }
288
289 void CAWiFiSetPacketReceiveCallback(CAWiFiPacketReceivedCallback callback)
290 {
291     OIC_LOG(DEBUG, MOD_NAME, "CAWSPRC Entry");
292     gPacketReceivedCallback = callback;
293     OIC_LOG(DEBUG, MOD_NAME, "CAWSPRC Exit");
294 }
295
296 void CAWiFiSetExceptionCallback(CAWiFiExceptionCallback callback)
297 {
298     // TODO
299 }
300
301 void CAWiFiPullData()
302 {
303     gRcvAction.check();
304 }
305
306 /// Retrieves the IP address assigned to Arduino Ethernet shield
307 CAResult_t CAArduinoGetInterfaceAddress(char *address, int32_t addrLen)
308 {
309     OIC_LOG(DEBUG, MOD_NAME, "IN");
310     // WiFiClass WiFi;
311     if (WiFi.status() == WL_NO_SHIELD)
312     {
313         OIC_LOG(DEBUG, MOD_NAME, "WIFI SHIELD NOT PRESENT");
314         return CA_STATUS_FAILED;
315     }
316
317     while ( status != WL_CONNECTED)
318     {
319         OIC_LOG_V(ERROR, MOD_NAME, "Attempting to connect to WPA SSID: %s", ssid);
320         status = WiFi.begin(ssid, pass);  // Connect to WPA/WPA2 network:
321
322         // wait 10 seconds for connection:
323         delay(10000);
324         OIC_LOG(DEBUG, MOD_NAME, "Attempting connection again");
325     }
326
327     VERIFY_NON_NULL(address, MOD_NAME, "Invalid address");
328     if (addrLen < IPNAMESIZE)
329     {
330         OIC_LOG_V(ERROR, MOD_NAME, "arduinoGetInterfaceAddress: addrLen MUST be atleast %d", IPNAMESIZE);
331         return CA_STATUS_FAILED;
332     }
333
334     IPAddress ip = WiFi.localIP();
335     sprintf((char *)address, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
336
337     OIC_LOG_V(DEBUG, MOD_NAME, "Wifi shield address is: %s", address);
338     OIC_LOG(DEBUG, MOD_NAME, "arduinoGetInterfaceAddress::Exit");
339     return CA_STATUS_OK;
340 }
341
342