Porting TBStack Functionality to Arduino. The following changes were made
[platform/upstream/iotivity.git] / csdk / ocsocket / src / ocsocket_arduino.cpp
1 //******************************************************************
2 //
3 // copyright 2014 intel corporation 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 <Arduino.h>
22 #include <Ethernet.h>
23 #include <socket.h>
24 #include <w5100.h>
25 #include <ocsocket.h>
26 #include <EthernetUdp.h>
27 #include <IPAddress.h>
28 #include <logger.h>
29
30 /// Ensures the literal string to be stored in Flash memory
31 #define PCF(str) ((const prog_char*)(F(str)))
32
33 /// Module Name
34 #define MOD_NAME PCF("ocsocket")
35
36 /// Macro to verify the validity of input argument
37 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG_V(FATAL, MOD_NAME, "%s is NULL", #arg); \
38          return ERR_INVALID_INPUT;} }
39
40 /// Length of the IP address decimal notation string
41 #define IPNAMESIZE (16)
42
43 /// IPv4 address representation for Arduino Ethernet Shield
44 typedef struct {
45     uint32_t size;  /// size of IP address and port bytes
46     uint8_t a;
47     uint8_t b;
48     uint8_t c;
49     uint8_t d;
50     uint16_t port;
51 } ArduinoAddr;
52
53
54 /// Builds a socket interface address using IP address and port number
55 int32_t OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port, OCDevAddr *ipAddr)
56 {
57     ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
58
59     VERIFY_NON_NULL(ardAddr);
60
61     memset(ardAddr, 0, sizeof(ArduinoAddr));
62
63     ardAddr->size =  sizeof(ArduinoAddr) - sizeof(ardAddr->size);
64     ardAddr-> a = a;
65     ardAddr-> b = b;
66     ardAddr-> c = c;
67     ardAddr-> d = d;
68     ardAddr-> port = port;
69
70     return ERR_SUCCESS;
71 }
72
73
74 /// Retrieves the IP address assigned to Arduino Ethernet shield
75 int32_t OCGetInterfaceAddress(uint8_t* ifName, uint32_t ifNameLen, uint16_t addrType,
76              uint8_t *addr,  uint32_t addrLen)
77 {
78     //TODO : Fix this for scenarios when this API is invoked when device is not connected
79     uint8_t rawIPAddr[4];
80     VERIFY_NON_NULL(addr);
81     if (addrLen < IPNAMESIZE) {
82         OC_LOG(FATAL, MOD_NAME, PCF("OCGetInterfaceAddress: addrLen MUST be atleast 16"));
83         return ERR_INVALID_INPUT;
84     }
85
86     if (addrType != AF_INET) {
87         return ERR_INVALID_INPUT;
88     }
89     W5100.getIPAddress(rawIPAddr);
90     sprintf((char *)addr,"%d.%d.%d.%d", rawIPAddr[0], rawIPAddr[1], rawIPAddr[2], rawIPAddr[3]);
91
92     OC_LOG_BUFFER(INFO, MOD_NAME, addr, addrLen);
93
94     return ERR_SUCCESS;
95 }
96
97 /// Retrieves a empty socket and bind it for UDP with the input port
98 int32_t OCInitUDP(OCDevAddr* ipAddr, int32_t* sockfd)
99 {
100     uint8_t state;
101     ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
102
103     VERIFY_NON_NULL(ardAddr);
104     VERIFY_NON_NULL(sockfd);
105
106     OC_LOG(DEBUG, MOD_NAME, PCF("OCInitUDP Begin"));
107     //Is any socket available to work with ?
108     *sockfd = -1;
109     for (int i = 0; i < MAX_SOCK_NUM; i++) {
110         state = W5100.readSnSR(i);
111         if (state == SnSR::CLOSED || state == SnSR::FIN_WAIT) {
112             *sockfd = i;
113             break;
114         }
115     }
116
117     if ( *sockfd == -1) {
118         return ERR_UNKNOWN;
119     }
120
121     //Create a datagram socket on which to recv/send.
122     if (!socket(*sockfd, SnMR::UDP, ardAddr->port, 0)) {
123         return ERR_UNKNOWN;
124     }
125
126     OC_LOG(DEBUG, MOD_NAME, PCF("OCInitUDP End"));
127     return ERR_SUCCESS;
128 }
129
130
131
132 /// Retrieves a empty socket and bind it for UDP with the input multicast ip address/port
133 int32_t OCInitUDPMulticast(OCDevAddr* ipMcastMacAddr, int32_t* sockfd)
134 {
135     uint8_t state;
136     uint8_t mcastMacAddr[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00};
137     ArduinoAddr* ardAddr = (ArduinoAddr*)ipMcastMacAddr;
138
139     VERIFY_NON_NULL(ardAddr);
140     VERIFY_NON_NULL(sockfd);
141
142     OC_LOG(DEBUG, MOD_NAME, PCF("OCInitUDPMulticast Begin"));
143     //Is any socket available to work with ?
144     *sockfd = -1;
145     for (int i = 0; i < MAX_SOCK_NUM; i++) {
146         state = W5100.readSnSR(i);
147         if (state == SnSR::CLOSED || state == SnSR::FIN_WAIT) {
148             *sockfd = i;
149             break;
150         }
151     }
152
153     if ( *sockfd == -1) {
154         return ERR_UNKNOWN;
155     }
156
157     //Calculate Multicast MAC address
158     mcastMacAddr[3] = ardAddr->b & 0x7F;
159     mcastMacAddr[4] = ardAddr->c;
160     mcastMacAddr[5] = ardAddr->d;
161     W5100.writeSnDIPR(*sockfd, (uint8_t*)&(ardAddr->a));
162     W5100.writeSnDHAR(*sockfd, mcastMacAddr);
163     W5100.writeSnDPORT(*sockfd, ardAddr->port);
164
165     //Create a datagram socket on which to recv/send.
166     if (!socket(*sockfd, SnMR::UDP, ardAddr->port, SnMR::MULTI)) {
167         return ERR_UNKNOWN;
168     }
169
170     OC_LOG(DEBUG, MOD_NAME, PCF("OCInitUDPMulticast End"));
171     return ERR_SUCCESS;
172 }
173
174
175 /// Send data to requested end-point using UDP socket
176 int32_t OCSendTo(int32_t sockfd, const uint8_t* buf, uint32_t bufLen, uint32_t flags,
177             OCDevAddr * ipAddr)
178 {
179     int32_t ret;
180     ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
181
182     VERIFY_NON_NULL(buf);
183     VERIFY_NON_NULL(ardAddr);
184     OC_LOG(DEBUG, MOD_NAME, PCF("OCSendTo Begin"));
185     ret = sendto( sockfd, buf, bufLen, (uint8_t*)&(ardAddr->a), ardAddr->port);
186     OC_LOG(DEBUG, MOD_NAME, PCF("OCSendTo End"));
187     return ret;
188 }
189
190
191 /// Retrieve any available data from UDP socket. This is a non-blocking call.
192 int32_t OCRecvFrom(int32_t sockfd, uint8_t* buf, uint32_t bufLen, uint32_t flags,
193             OCDevAddr * ipAddr)
194 {
195     /**Bug : When there are multiple UDP packets in Wiznet buffer, W5100.getRXReceivedSize
196      * will not return correct length of the first packet.
197      * Fix : Use the patch provided for arduino/libraries/Ethernet/utility/socket.cpp
198      */
199     int32_t ret = 0;
200     uint16_t recvLen;
201     ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
202
203     VERIFY_NON_NULL(buf);
204     VERIFY_NON_NULL(ardAddr);
205
206     OC_LOG(DEBUG, MOD_NAME, PCF("OCRecvFrom Begin"));
207     recvLen = W5100.getRXReceivedSize(sockfd);
208     if (recvLen == 0) {
209         return recvLen;
210     }
211
212     // Read available data.
213     ret = recvfrom(sockfd, buf, bufLen, (uint8_t*)&(ardAddr->a), (uint16_t*)&(ardAddr->port));
214     ardAddr->size =  sizeof(ArduinoAddr) - sizeof(ardAddr->size);
215
216     OC_LOG(DEBUG, MOD_NAME, PCF("OCRecvFrom End"));
217     return ret;
218 }
219
220
221 /// Close the socket and release all system resources.
222 int32_t OCClose(int32_t sockfd)
223 {
224     close(sockfd);
225     return ERR_SUCCESS;
226 }
227
228
229 /// Retrieve the IPv4 address embedded inside OCDev address data structure
230 int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
231             uint8_t *c, uint8_t *d )
232 {
233     ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
234
235     if ( !ardAddr || !a || !b || !c || !d ) {
236         OC_LOG(FATAL, MOD_NAME, PCF("Invalid argument"));
237         return ERR_INVALID_INPUT;
238     }
239
240     *a = ardAddr->a;
241     *b = ardAddr->b;
242     *c = ardAddr->c;
243     *d = ardAddr->d;
244
245     return ERR_SUCCESS;
246 }
247
248
249 /// Retrieve the IPv4 address embedded inside OCDev address data structure
250 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
251 {
252     ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
253
254     if ( !ardAddr || !port ) {
255         OC_LOG(FATAL, MOD_NAME, PCF("Invalid argument"));
256         return ERR_INVALID_INPUT;
257     }
258
259     *port = ardAddr->port;
260
261     return ERR_SUCCESS;
262 }
263