1 //******************************************************************
3 // copyright 2014 intel corporation all rights reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
26 #include <EthernetUdp.h>
27 #include <IPAddress.h>
30 /// Ensures the literal string to be stored in Flash memory
31 #define PCF(str) ((const prog_char*)(F(str)))
34 #define MOD_NAME PCF("ocsocket")
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;} }
40 /// Length of the IP address decimal notation string
41 #define IPNAMESIZE (16)
43 /// IPv4 address representation for Arduino Ethernet Shield
45 uint32_t size; /// size of IP address and port bytes
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)
57 ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
59 VERIFY_NON_NULL(ardAddr);
61 memset(ardAddr, 0, sizeof(ArduinoAddr));
63 ardAddr->size = sizeof(ArduinoAddr) - sizeof(ardAddr->size);
68 ardAddr-> port = port;
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)
78 //TODO : Fix this for scenarios when this API is invoked when device is not connected
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;
86 if (addrType != AF_INET) {
87 return ERR_INVALID_INPUT;
89 W5100.getIPAddress(rawIPAddr);
90 sprintf((char *)addr,"%d.%d.%d.%d", rawIPAddr[0], rawIPAddr[1], rawIPAddr[2], rawIPAddr[3]);
92 OC_LOG_BUFFER(INFO, MOD_NAME, addr, addrLen);
97 /// Retrieves a empty socket and bind it for UDP with the input port
98 int32_t OCInitUDP(OCDevAddr* ipAddr, int32_t* sockfd)
101 ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
103 VERIFY_NON_NULL(ardAddr);
104 VERIFY_NON_NULL(sockfd);
106 OC_LOG(DEBUG, MOD_NAME, PCF("OCInitUDP Begin"));
107 //Is any socket available to work with ?
109 for (int i = 0; i < MAX_SOCK_NUM; i++) {
110 state = W5100.readSnSR(i);
111 if (state == SnSR::CLOSED || state == SnSR::FIN_WAIT) {
117 if ( *sockfd == -1) {
121 //Create a datagram socket on which to recv/send.
122 if (!socket(*sockfd, SnMR::UDP, ardAddr->port, 0)) {
126 OC_LOG(DEBUG, MOD_NAME, PCF("OCInitUDP End"));
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)
136 uint8_t mcastMacAddr[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00};
137 ArduinoAddr* ardAddr = (ArduinoAddr*)ipMcastMacAddr;
139 VERIFY_NON_NULL(ardAddr);
140 VERIFY_NON_NULL(sockfd);
142 OC_LOG(DEBUG, MOD_NAME, PCF("OCInitUDPMulticast Begin"));
143 //Is any socket available to work with ?
145 for (int i = 0; i < MAX_SOCK_NUM; i++) {
146 state = W5100.readSnSR(i);
147 if (state == SnSR::CLOSED || state == SnSR::FIN_WAIT) {
153 if ( *sockfd == -1) {
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);
165 //Create a datagram socket on which to recv/send.
166 if (!socket(*sockfd, SnMR::UDP, ardAddr->port, SnMR::MULTI)) {
170 OC_LOG(DEBUG, MOD_NAME, PCF("OCInitUDPMulticast End"));
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,
180 ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
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"));
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,
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
201 ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
203 VERIFY_NON_NULL(buf);
204 VERIFY_NON_NULL(ardAddr);
206 OC_LOG(DEBUG, MOD_NAME, PCF("OCRecvFrom Begin"));
207 recvLen = W5100.getRXReceivedSize(sockfd);
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);
216 OC_LOG(DEBUG, MOD_NAME, PCF("OCRecvFrom End"));
221 /// Close the socket and release all system resources.
222 int32_t OCClose(int32_t sockfd)
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 )
233 ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
235 if ( !ardAddr || !a || !b || !c || !d ) {
236 OC_LOG(FATAL, MOD_NAME, PCF("Invalid argument"));
237 return ERR_INVALID_INPUT;
249 /// Retrieve the IPv4 address embedded inside OCDev address data structure
250 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
252 ArduinoAddr* ardAddr = (ArduinoAddr*)ipAddr;
254 if ( !ardAddr || !port ) {
255 OC_LOG(FATAL, MOD_NAME, PCF("Invalid argument"));
256 return ERR_INVALID_INPUT;
259 *port = ardAddr->port;