Implementation of the WifiPlusClick hardware module.

Dependents:   WifiPlusKlickExample

WifiPlusClick Libary

Overview

http://www.mikroe.com/img/development-tools/accessory-boards/click/wifi-plus/wifi_plus_click_main.png

This library implements the functionality exposed by a WifiPlusClick module from MikroElektronika (http://www.mikroe.com/click/wifi-plus/).

The WifiPlusClick module is an easy to handle module which provides access to up to 8 simultaneous socket objects - which is an an important aspect when you want to implement your own web server.

When I first started with the more commonly used Wifly module, I found out that the Wifly module does not reliably serve webpages which include other resources like images, JavaScript files or CSS files. The root cause seems to be the limitation that Wifly is only able to handle a single socket at this time. So I searched for an alternative and found this (actually cheaper) alternative :

WifiPlusClick HW Module

This module comes with its own limitations. The WifiPlusClick Module interface does not allow to use broadcasting or multicasting on UDP sockets. There are some additional limitations, but I think these are not so important. The following functionality is provided by the module and my library implementation :

  1. Wifi functionality
    1. Connections using AD-HOC or INFRASTRUCTURE mode
    2. List all available Wifi beacons
    3. WEP and WPA/WPA2 security modes including binary and ASCII keys
    4. reading binary WPA key after successfull Connection to speed up connection time
  2. Socket functionality
    1. UDP sockets
    2. TCP sockets

Limitations

I found the following limitations:

  1. UDP sockets cannot use multicasting or broadcasting
  2. set_option functionality is not provided by the HW
  3. 8 sockets can be configured with 1024 bytes of buffer each or 1 socket with 8192 bytes of buffer.

Sample application

Here is my sample application which you can use as a starting point.

Import programWifiPlusKlickExample

Example application of the WifiPlusClick library for use of WifiPlusClick HW Module from Mikroe.com

NOTE

The implementation of the Sockets in this library is still not completely tested. I only tested the TCP part of the sockets. Please let me know what your experiences are when using the library. I will be working on a multithreaded version of this library...

Committer:
leihen
Date:
Mon Jul 29 15:15:21 2013 +0000
Revision:
0:2a179bd4cc02
Initial Version of the WifiPlusClick Library.
; Tested in INFRASTRUCTURE mode only.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
leihen 0:2a179bd4cc02 1 /* Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
leihen 0:2a179bd4cc02 2 *
leihen 0:2a179bd4cc02 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
leihen 0:2a179bd4cc02 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
leihen 0:2a179bd4cc02 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
leihen 0:2a179bd4cc02 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
leihen 0:2a179bd4cc02 7 * furnished to do so, subject to the following conditions:
leihen 0:2a179bd4cc02 8 *
leihen 0:2a179bd4cc02 9 * The above copyright notice and this permission notice shall be included in all copies or
leihen 0:2a179bd4cc02 10 * substantial portions of the Software.
leihen 0:2a179bd4cc02 11 *
leihen 0:2a179bd4cc02 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
leihen 0:2a179bd4cc02 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
leihen 0:2a179bd4cc02 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
leihen 0:2a179bd4cc02 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
leihen 0:2a179bd4cc02 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
leihen 0:2a179bd4cc02 17 */
leihen 0:2a179bd4cc02 18 #include "mbed.h"
leihen 0:2a179bd4cc02 19 #include "DnsQuery.h"
leihen 0:2a179bd4cc02 20
leihen 0:2a179bd4cc02 21 #define DEBUG
leihen 0:2a179bd4cc02 22 #include "debug.h"
leihen 0:2a179bd4cc02 23
leihen 0:2a179bd4cc02 24
leihen 0:2a179bd4cc02 25
leihen 0:2a179bd4cc02 26 DnsQuery::DnsQuery(Wifi* wifi, IPADDRESS_t *dnsip)
leihen 0:2a179bd4cc02 27 : _wifi(wifi)
leihen 0:2a179bd4cc02 28 {
leihen 0:2a179bd4cc02 29 _dnsip.sin_addr.o1 = dnsip->sin_addr.o1;
leihen 0:2a179bd4cc02 30 _dnsip.sin_addr.o2 = dnsip->sin_addr.o2;
leihen 0:2a179bd4cc02 31 _dnsip.sin_addr.o3 = dnsip->sin_addr.o3;
leihen 0:2a179bd4cc02 32 _dnsip.sin_addr.o4 = dnsip->sin_addr.o4;
leihen 0:2a179bd4cc02 33 INFO("Setting DNS = %d.%d.%d.%d !", dnsip->sin_addr.o1, dnsip->sin_addr.o2, dnsip->sin_addr.o3, dnsip->sin_addr.o4);
leihen 0:2a179bd4cc02 34 INFO("Accepting DNS = %d.%d.%d.%d !", _dnsip.sin_addr.o1, _dnsip.sin_addr.o2, _dnsip.sin_addr.o3, _dnsip.sin_addr.o4);
leihen 0:2a179bd4cc02 35 }
leihen 0:2a179bd4cc02 36
leihen 0:2a179bd4cc02 37 bool DnsQuery::gethostbyname(const char* hostname, IPADDRESS_t &ipaddress)
leihen 0:2a179bd4cc02 38 {
leihen 0:2a179bd4cc02 39 int len = 0;
leihen 0:2a179bd4cc02 40 if (hostname == NULL)
leihen 0:2a179bd4cc02 41 return false;
leihen 0:2a179bd4cc02 42 len = strlen(hostname);
leihen 0:2a179bd4cc02 43 if ((len >128) || (len == 0))
leihen 0:2a179bd4cc02 44 return false;
leihen 0:2a179bd4cc02 45 memset (&ipaddress, 0, sizeof(ipaddress));
leihen 0:2a179bd4cc02 46
leihen 0:2a179bd4cc02 47 int packetlen = /* size of HEADER structure */ 12 + /* size of QUESTION Structure */5 + len + 1;
leihen 0:2a179bd4cc02 48 char *packet = new char[packetlen]; /* this is the UDP packet to send to the DNS */
leihen 0:2a179bd4cc02 49 if (packet == NULL)
leihen 0:2a179bd4cc02 50 return false;
leihen 0:2a179bd4cc02 51
leihen 0:2a179bd4cc02 52 // Fill the header
leihen 0:2a179bd4cc02 53 memset(packet, 0, packetlen);
leihen 0:2a179bd4cc02 54 packet[1] = 1; // ID = 1
leihen 0:2a179bd4cc02 55 packet[5] = 1; // QDCOUNT = 1 (contains one question)
leihen 0:2a179bd4cc02 56
leihen 0:2a179bd4cc02 57 int c = 13; // point to NAME element in question section or request
leihen 0:2a179bd4cc02 58 int cnt = 12; // points to the counter of
leihen 0:2a179bd4cc02 59 packet[cnt] = 0;
leihen 0:2a179bd4cc02 60 for (int i = 0 ; i < len ; i++) {
leihen 0:2a179bd4cc02 61 if (hostname[i] != '.') {
leihen 0:2a179bd4cc02 62 // Copy the character and increment the character counter
leihen 0:2a179bd4cc02 63 packet[cnt]++;
leihen 0:2a179bd4cc02 64 packet[c++] = hostname[i];
leihen 0:2a179bd4cc02 65 } else {
leihen 0:2a179bd4cc02 66 // Finished with this part, so go to the next
leihen 0:2a179bd4cc02 67 cnt = c++;
leihen 0:2a179bd4cc02 68 packet[cnt] = 0;
leihen 0:2a179bd4cc02 69 }
leihen 0:2a179bd4cc02 70 }
leihen 0:2a179bd4cc02 71
leihen 0:2a179bd4cc02 72 // Terminate this domain name with a zero entry
leihen 0:2a179bd4cc02 73 packet[c++] = 0;
leihen 0:2a179bd4cc02 74
leihen 0:2a179bd4cc02 75 // Set QTYPE
leihen 0:2a179bd4cc02 76 packet[c++] = 0;
leihen 0:2a179bd4cc02 77 packet[c++] = 1;
leihen 0:2a179bd4cc02 78 // Set QCLASS
leihen 0:2a179bd4cc02 79 packet[c++] = 0;
leihen 0:2a179bd4cc02 80 packet[c++] = 1;
leihen 0:2a179bd4cc02 81
leihen 0:2a179bd4cc02 82 // REMOVE ME !!!!
leihen 0:2a179bd4cc02 83 std::printf("--> DUMPING UDP PACKET : ");
leihen 0:2a179bd4cc02 84 int port;
leihen 0:2a179bd4cc02 85 for( int i = 0 ; i < c ; i++) {
leihen 0:2a179bd4cc02 86 std::printf("%02x ", packet[i]);
leihen 0:2a179bd4cc02 87 }
leihen 0:2a179bd4cc02 88 std::printf("\n\n\n");
leihen 0:2a179bd4cc02 89 // Ready to send to DNS
leihen 0:2a179bd4cc02 90 SOCKET_HANDLE_t sock = _wifi->SocketCreate(UDP);
leihen 0:2a179bd4cc02 91 if (sock == InvalidSocketHandle) {
leihen 0:2a179bd4cc02 92 delete packet;
leihen 0:2a179bd4cc02 93 return false;
leihen 0:2a179bd4cc02 94 }
leihen 0:2a179bd4cc02 95
leihen 0:2a179bd4cc02 96 INFO("Using %d.%d.%d.%d as DNS !", _dnsip.sin_addr.o1, _dnsip.sin_addr.o2, _dnsip.sin_addr.o3, _dnsip.sin_addr.o4);
leihen 0:2a179bd4cc02 97 if (!_wifi->SocketSendTo(sock, &_dnsip, 53, packet, packetlen)) {
leihen 0:2a179bd4cc02 98 delete packet;
leihen 0:2a179bd4cc02 99 _wifi->SocketClose(sock);
leihen 0:2a179bd4cc02 100 return false;
leihen 0:2a179bd4cc02 101 }
leihen 0:2a179bd4cc02 102
leihen 0:2a179bd4cc02 103 delete packet;
leihen 0:2a179bd4cc02 104
leihen 0:2a179bd4cc02 105 packet = new char [1024];
leihen 0:2a179bd4cc02 106 if (packet == NULL) {
leihen 0:2a179bd4cc02 107 _wifi->SocketClose(sock);
leihen 0:2a179bd4cc02 108 return false;
leihen 0:2a179bd4cc02 109 }
leihen 0:2a179bd4cc02 110
leihen 0:2a179bd4cc02 111 // Receive the answer from DNS
leihen 0:2a179bd4cc02 112 Timer t;
leihen 0:2a179bd4cc02 113 int recvd = 0;
leihen 0:2a179bd4cc02 114 t.start();
leihen 0:2a179bd4cc02 115
leihen 0:2a179bd4cc02 116 while (t.read_ms() < 10000) {
leihen 0:2a179bd4cc02 117 if ((recvd = _wifi->SocketRecvFrom (sock, NULL, &port, packet, 1024)) > 0 ) {
leihen 0:2a179bd4cc02 118 // process input
leihen 0:2a179bd4cc02 119 std::printf("Received %d bytes from DNS !\n", recvd);
leihen 0:2a179bd4cc02 120 if (!resolve(packet, ipaddress)) {
leihen 0:2a179bd4cc02 121 break;
leihen 0:2a179bd4cc02 122 }
leihen 0:2a179bd4cc02 123
leihen 0:2a179bd4cc02 124 // cleanup and return
leihen 0:2a179bd4cc02 125 delete packet;
leihen 0:2a179bd4cc02 126 _wifi->SocketClose(sock);
leihen 0:2a179bd4cc02 127 return true;
leihen 0:2a179bd4cc02 128 } else {
leihen 0:2a179bd4cc02 129 ERR("SocketRecvFrom returned %d !", recvd);
leihen 0:2a179bd4cc02 130 }
leihen 0:2a179bd4cc02 131 }
leihen 0:2a179bd4cc02 132
leihen 0:2a179bd4cc02 133 delete packet;
leihen 0:2a179bd4cc02 134
leihen 0:2a179bd4cc02 135 _wifi->SocketClose(sock);
leihen 0:2a179bd4cc02 136
leihen 0:2a179bd4cc02 137 return false;
leihen 0:2a179bd4cc02 138 }
leihen 0:2a179bd4cc02 139
leihen 0:2a179bd4cc02 140
leihen 0:2a179bd4cc02 141 bool DnsQuery::resolve(char* resp, IPADDRESS_t &ipaddress)
leihen 0:2a179bd4cc02 142 {
leihen 0:2a179bd4cc02 143 int ID = (((int)resp[0]) <<8) + resp[1];
leihen 0:2a179bd4cc02 144 int QR = resp[2] >>7;
leihen 0:2a179bd4cc02 145 int Opcode = (resp[2]>>3) & 0x0F;
leihen 0:2a179bd4cc02 146 int RCODE = (resp[3] & 0x0F);
leihen 0:2a179bd4cc02 147 int ANCOUNT = (((int)resp[6])<<8)+ resp[7];
leihen 0:2a179bd4cc02 148
leihen 0:2a179bd4cc02 149 INFO("Resolving response : ID = %d, QR = %d, Opcode = %d, RCODE = %d", ID, QR, Opcode, RCODE);
leihen 0:2a179bd4cc02 150 if ((ID != 1) || (QR != 1) || (Opcode != 0) || (RCODE != 0)) {
leihen 0:2a179bd4cc02 151 ERR("Received non matching response from DNS !");
leihen 0:2a179bd4cc02 152 return false;
leihen 0:2a179bd4cc02 153 }
leihen 0:2a179bd4cc02 154
leihen 0:2a179bd4cc02 155 int c = 12;
leihen 0:2a179bd4cc02 156 int d;
leihen 0:2a179bd4cc02 157 // Skip domain question
leihen 0:2a179bd4cc02 158 while( (d=resp[c++]) != 0) {
leihen 0:2a179bd4cc02 159 c+=d;
leihen 0:2a179bd4cc02 160 }
leihen 0:2a179bd4cc02 161 c+= 4; // skip QTYPE and QCLASS
leihen 0:2a179bd4cc02 162
leihen 0:2a179bd4cc02 163 // Here comes the resource record
leihen 0:2a179bd4cc02 164 for (int ans = 0 ; ans < ANCOUNT; ans++) {
leihen 0:2a179bd4cc02 165 if (parseRR(resp, c, ipaddress)) {
leihen 0:2a179bd4cc02 166 return true;
leihen 0:2a179bd4cc02 167 }
leihen 0:2a179bd4cc02 168 }
leihen 0:2a179bd4cc02 169
leihen 0:2a179bd4cc02 170 return false;
leihen 0:2a179bd4cc02 171 }
leihen 0:2a179bd4cc02 172
leihen 0:2a179bd4cc02 173 bool DnsQuery::parseRR(char *resp, int& c, IPADDRESS_t& adr )
leihen 0:2a179bd4cc02 174 {
leihen 0:2a179bd4cc02 175 int n = 0;
leihen 0:2a179bd4cc02 176
leihen 0:2a179bd4cc02 177 while( (n=resp[c++]) != 0) {
leihen 0:2a179bd4cc02 178 if ((n & 0xc0) != 0) {
leihen 0:2a179bd4cc02 179 // This is a link
leihen 0:2a179bd4cc02 180 c++;
leihen 0:2a179bd4cc02 181 break;
leihen 0:2a179bd4cc02 182 } else {
leihen 0:2a179bd4cc02 183 c+= n; // skip this segment, not interested in string domain names
leihen 0:2a179bd4cc02 184 }
leihen 0:2a179bd4cc02 185 }
leihen 0:2a179bd4cc02 186
leihen 0:2a179bd4cc02 187 int TYPE = (((int)resp[c])<<8) + resp[c+1];
leihen 0:2a179bd4cc02 188 int CLASS = (((int)resp[c+2])<<8) + resp[c+3];
leihen 0:2a179bd4cc02 189 int RDLENGTH = (((int)resp[c+8])<<8) + resp[c+9];
leihen 0:2a179bd4cc02 190
leihen 0:2a179bd4cc02 191 INFO("Record of TYPE=%d and CLASS=%d detected !", TYPE, CLASS);
leihen 0:2a179bd4cc02 192 c+= 10;
leihen 0:2a179bd4cc02 193 if ((CLASS == 1) && (TYPE == 1)) {
leihen 0:2a179bd4cc02 194 adr.sin_addr.o1 = resp[c];
leihen 0:2a179bd4cc02 195 adr.sin_addr.o2 = resp[c+1];
leihen 0:2a179bd4cc02 196 adr.sin_addr.o3 = resp[c+2];
leihen 0:2a179bd4cc02 197 adr.sin_addr.o4 = resp[c+3];
leihen 0:2a179bd4cc02 198 c+= RDLENGTH;
leihen 0:2a179bd4cc02 199 return true;
leihen 0:2a179bd4cc02 200 } else {
leihen 0:2a179bd4cc02 201 }
leihen 0:2a179bd4cc02 202 c+= RDLENGTH;
leihen 0:2a179bd4cc02 203
leihen 0:2a179bd4cc02 204 return false;
leihen 0:2a179bd4cc02 205 }