- Added setBaud() function - Added CheckNetworkStatus() function - Improved messaging system

Dependents:   IoT_Ex BatteryModelTester BatteryModelTester

Fork of WiflyInterface by Components

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Wifly.cpp Source File

Wifly.cpp

00001 /* Copyright (C) 2012 mbed.org, MIT License
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
00004  * and associated documentation files (the "Software"), to deal in the Software without restriction,
00005  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
00006  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
00007  * furnished to do so, subject to the following conditions:
00008  *
00009  * The above copyright notice and this permission notice shall be included in all copies or
00010  * substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
00013  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00014  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
00015  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00016  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00017  */
00018 
00019 #include "mbed.h"
00020 #include "Wifly.h"
00021 #include <string>
00022 #include <algorithm>
00023 
00024 //#define DEBUG
00025 #define INFOMESSAGES
00026 #define WARNMESSAGES
00027 #define ERRMESSAGES
00028 #define FUNCNAME "Wifly"
00029 #include "messages.h"
00030 
00031 #define MAX_TRY_JOIN 3
00032 
00033 Wifly * Wifly::inst;
00034 
00035 Wifly::Wifly(   PinName tx, PinName rx, PinName _reset, PinName tcp_status, const char * ssid, const char * phrase, Security sec):
00036     wifi(tx, rx), reset_pin(_reset), tcp_status(tcp_status), buf_wifly(1024)
00037 {
00038     // Set the default baud rate:
00039     serial_baudrate = 9600;
00040     
00041     memset(&state, 0, sizeof(state));
00042     state.sec = sec;
00043 
00044     // change all ' ' in '$' in the ssid and the passphrase
00045     strcpy(this->ssid, ssid);
00046     for (int i = 0; i < strlen(ssid); i++) {
00047         if (this->ssid[i] == ' ')
00048             this->ssid[i] = '$';
00049     }
00050     strcpy(this->phrase, phrase);
00051     for (int i = 0; i < strlen(phrase); i++) {
00052         if (this->phrase[i] == ' ')
00053             this->phrase[i] = '$';
00054     }
00055 
00056     inst = this;
00057     attach_rx(false);
00058     state.cmd_mode = false;
00059     DBG("Wifly Constructed");
00060 }
00061 
00062 void Wifly::setBaud(int baudrate)
00063 {
00064     char cmd[28];
00065     // Save the baudrate:
00066     if(baudrate > 0){
00067         serial_baudrate = baudrate;
00068     }
00069     DBG("Setting wifi shield baudrate to: %d.", serial_baudrate);
00070     // This sets the baud rate 'instantly'
00071     sprintf(cmd, "set u i %d\r", serial_baudrate);
00072     // This one sets it some other way that does not work
00073     //sprintf(cmd, "set u b %d\r", baudrate);
00074     // Set baud rate of wifly:
00075     sendCommand(cmd, NULL);
00076     wait(0.5);
00077     // Set baud rate of UART:
00078     wifi.baud(serial_baudrate);
00079     wait(0.5);
00080     exit();
00081 }
00082 
00083 bool Wifly::join()
00084 {
00085     char cmd[28];
00086 
00087     for (int i= 0; i < MAX_TRY_JOIN; i++) {
00088 
00089         // no auto join
00090         if (!sendCommand("set w j 0\r", "AOK"))
00091             continue;
00092 
00093         //no echo
00094         if (!sendCommand("set u m 1\r", "AOK"))
00095             continue;
00096 
00097         // set time
00098         if (!sendCommand("set c t 30\r", "AOK"))
00099             continue;
00100 
00101         // set size
00102         if (!sendCommand("set c s 1024\r", "AOK"))
00103             continue;
00104 
00105         // red led on when tcp connection active
00106         if (!sendCommand("set s i 0x40\r", "AOK"))
00107             continue;
00108 
00109         // no string sent to the tcp client
00110         if (!sendCommand("set c r 0\r", "AOK"))
00111             continue;
00112 
00113         // tcp protocol
00114         if (!sendCommand("set i p 2\r", "AOK"))
00115             continue;
00116 
00117         // tcp retry
00118         if (!sendCommand("set i f 0x7\r", "AOK"))
00119             continue;
00120             
00121         // set dns server
00122         if (!sendCommand("set d n rn.microchip.com\r", "AOK"))
00123             continue;
00124 
00125         //dhcp
00126         sprintf(cmd, "set i d %d\r", (state.dhcp) ? 1 : 0);
00127         if (!sendCommand(cmd, "AOK"))
00128             continue;
00129 
00130         // ssid
00131         sprintf(cmd, "set w s %s\r", ssid);
00132         if (!sendCommand(cmd, "AOK", NULL, 1000))
00133             continue;
00134 
00135         //auth
00136         sprintf(cmd, "set w a %d\r", state.sec);
00137         if (!sendCommand(cmd, "AOK"))
00138             continue;
00139 
00140         // if no dhcp, set ip, netmask and gateway
00141         if (!state.dhcp) {
00142             DBG("not dhcp\r");
00143 
00144             sprintf(cmd, "set i a %s\r\n", ip);
00145             if (!sendCommand(cmd, "AOK"))
00146                 continue;
00147 
00148             sprintf(cmd, "set i n %s\r", netmask);
00149             if (!sendCommand(cmd, "AOK"))
00150                 continue;
00151 
00152             sprintf(cmd, "set i g %s\r", gateway);
00153             if (!sendCommand(cmd, "AOK"))
00154                 continue;
00155         }
00156 
00157         //key step
00158         if (state.sec != NONE) {
00159             if ((state.sec == WPA)||(state.sec == WPA2))
00160                 sprintf(cmd, "set w p %s\r", phrase);
00161             else if (state.sec == WEP_128)
00162                 sprintf(cmd, "set w k %s\r", phrase);
00163 
00164             if (!sendCommand(cmd, "AOK", NULL, 1000))
00165                 continue;
00166         }
00167 
00168         //join the network
00169         sprintf(cmd, "join\r");
00170         if (!sendCommand(cmd, "Associated", NULL, 3000))
00171             continue;
00172         
00173         if (!sendCommand("", "IP=", NULL, 10000))
00174             continue;
00175 
00176         if (state.dhcp) {
00177             if (!sendCommand("get i\r", "DHCP=ON", NULL, 3000))
00178                 continue;
00179         }
00180 
00181         if (!sendCommand("save\r", "Stor"))
00182             continue;
00183 
00184         exit();
00185 
00186         state.associated = true;
00187         INFO("ssid: %s", this->ssid);
00188         INFO("phrase: %s", this->phrase);
00189         INFO("security: %s", getStringSecurity());
00190 
00191         return true;
00192     }
00193     return false;
00194 }
00195 
00196 
00197 bool Wifly::setProtocol(Protocol p)
00198 {
00199     // use udp auto pairing
00200     char cmd[20];
00201     sprintf(cmd, "set i p %d\r", p);
00202     if (!sendCommand(cmd, "AOK"))
00203         return false;
00204 
00205     switch(p) {
00206         case TCP:
00207             // set ip flags: tcp retry enabled
00208             if (!sendCommand("set i f 0x07\r", "AOK"))
00209                 return false;
00210             break;
00211         case UDP:
00212             // set ip flags: udp auto pairing enabled
00213             if (!sendCommand("set i h 0.0.0.0\r", "AOK"))
00214                 return false;
00215             if (!sendCommand("set i f 0x40\r", "AOK"))
00216                 return false;
00217             break;
00218     }
00219     state.proto = p;
00220     return true;
00221 }
00222 
00223 char * Wifly::getStringSecurity()
00224 {
00225     switch(state.sec) {
00226         case NONE:
00227             return "NONE";
00228         case WEP_128:
00229             return "WEP_128";
00230         case WPA:
00231             return "WPA";
00232         case WPA2:
00233             return "WPA2";
00234     }
00235     return "UNKNOWN";
00236 }
00237 
00238 bool Wifly::connect(const char * host, int port)
00239 {
00240     char rcv[28];
00241     char cmd[28];
00242     
00243     
00244 
00245     // try to open
00246     sprintf(cmd, "open %s %d\r", host, port);
00247     DBG("CMD1: %s",cmd);
00248     if (sendCommand(cmd, "OPEN", rcv, 10000)) {
00249         state.tcp = true;
00250         state.cmd_mode = false;
00251         return true;
00252     }
00253     DBG("CMD2: %s",cmd);
00254     DBG("CMD4: %s",rcv);
00255     // if failed, retry and parse the response
00256     if (sendCommand(cmd, NULL, rcv, 5000)) {
00257         DBG("CMD5: %s",rcv);
00258         if (strstr(rcv, "OPEN") == NULL) {
00259             if (strstr(rcv, "Connected") != NULL) {
00260                 wait(0.25);
00261                 if (!sendCommand("close\r", "CLOS"))
00262                     return false;
00263                 wait(0.25);
00264                 if (!sendCommand(cmd, "OPEN", NULL, 10000))
00265                     return false;
00266             } else {
00267                 return false;
00268             }
00269         }
00270     } else {
00271         DBG("CMD5: %s",rcv);
00272         return false;
00273     }
00274     
00275 
00276     state.tcp = true;
00277     state.cmd_mode = false;
00278 
00279     return true;
00280 }
00281 
00282 
00283 bool Wifly::gethostbyname(const char * host, char * ip)
00284 {
00285     string h = host;
00286     char cmd[30], rcv[100];
00287     int l = 0;
00288     char * point;
00289     int nb_digits = 0;
00290 
00291     // no dns needed
00292     int pos = h.find(".");
00293     if (pos != string::npos) {
00294         string sub = h.substr(0, h.find("."));
00295         nb_digits = atoi(sub.c_str());
00296     }
00297     if (count(h.begin(), h.end(), '.') == 3 && nb_digits > 0) {
00298         strcpy(ip, host);
00299     }
00300     // dns needed
00301     else {
00302         nb_digits = 0;
00303         sprintf(cmd, "lookup %s\r", host);
00304         if (!sendCommand(cmd, NULL, rcv))
00305             return false;
00306 
00307         // look for the ip address
00308         char * begin = strstr(rcv, "=") + 1;
00309         for (int i = 0; i < 3; i++) {
00310             point = strstr(begin + l, ".");
00311             DBG("str: %s", begin + l);
00312             l += point - (begin + l) + 1;
00313         }
00314         DBG("str: %s", begin + l);
00315         while(*(begin + l + nb_digits) >= '0' && *(begin + l + nb_digits) <= '9') {
00316             DBG("digit: %c", *(begin + l + nb_digits));
00317             nb_digits++;
00318         }
00319         memcpy(ip, begin, l + nb_digits);
00320         ip[l+nb_digits] = 0;
00321         DBG("ip from dns: %s", ip);
00322     }
00323     return true;
00324 }
00325 
00326 
00327 void Wifly::flush()
00328 {
00329     buf_wifly.flush();
00330 }
00331 
00332 bool Wifly::sendCommand(const char * cmd, const char * ack, char * res, int timeout)
00333 {
00334     if (!state.cmd_mode) {
00335         cmdMode();
00336     }
00337     if (send(cmd, strlen(cmd), ack, res, timeout) == -1) {
00338         ERR("sendCommand: cannot (%s)", cmd);
00339         if(strcmp(cmd, "exit") != 0){
00340             exit();
00341         }else{
00342             WARN("Manually setting cmd_mode to false.");
00343             state.cmd_mode = false;
00344         }
00345         return false;
00346     }
00347     return true;
00348 }
00349 
00350 bool Wifly::cmdMode()
00351 {
00352     // if already in cmd mode, return
00353     if (state.cmd_mode)
00354         return true;
00355         
00356     if (send("$$$", 3, "CMD") == -1 && send("\r",1,">") != true) {
00357         ERR("cannot enter in cmd mode");
00358         exit();
00359         return false;
00360     }
00361     state.cmd_mode = true;
00362     return true;
00363 }
00364 
00365 bool Wifly::disconnect()
00366 {
00367     // if already disconnected, return
00368     if (!state.associated)
00369         return true;
00370 
00371     if (!sendCommand("leave\r", "DeAuth"))
00372         return false;
00373     exit();
00374 
00375     state.associated = false;
00376     return true;
00377 
00378 }
00379 
00380 bool Wifly::is_connected()
00381 {
00382     return (tcp_status.read() ==  1) ? true : false;
00383 }
00384 
00385 
00386 void Wifly::reset()
00387 {
00388     
00389     reset_pin = 0;
00390     wifi.baud(9600);
00391     flush();
00392     state.cmd_mode = false;
00393     wait(0.5);
00394     reset_pin = 1;
00395     // Set the serial port baud rate back to default:
00396     wait(0.5);
00397     INFO("Wifi Shield Reset");
00398     setBaud(-1);
00399     DBG("Baud Rate updated from Reset.");
00400 }
00401 
00402 bool Wifly::reboot()
00403 {
00404     // if already in cmd mode, return
00405     if (!sendCommand("reboot\r"))
00406         return false;
00407     
00408     wait(0.3);
00409 
00410     state.cmd_mode = false;
00411     return true;
00412 }
00413 
00414 bool Wifly::close()
00415 {
00416     // if not connected, return
00417     if (!state.tcp)
00418         return true;
00419 
00420     wait(0.25);
00421     if (!sendCommand("close\r", "CLOS"))
00422         return false;
00423     exit();
00424 
00425     state.tcp = false;
00426     return true;
00427 }
00428 
00429 
00430 int Wifly::putc(char c)
00431 {
00432     while (!wifi.writeable());
00433     return wifi.putc(c);
00434 }
00435 
00436 
00437 bool Wifly::exit()
00438 {
00439     flush();
00440     if (!state.cmd_mode)
00441         return true;
00442     if (!sendCommand("exit\r", "EXIT"))
00443         return false;
00444     state.cmd_mode = false;
00445     flush();
00446     return true;
00447 }
00448 
00449 
00450 int Wifly::readable()
00451 {
00452     return buf_wifly.available();
00453 }
00454 
00455 int Wifly::writeable()
00456 {
00457     return wifi.writeable();
00458 }
00459 
00460 char Wifly::getc()
00461 {
00462     char c;
00463     //DBG("Waiting for buf_wifly.available() to return true...");
00464     while (!buf_wifly.available());
00465     //DBG("Dequeue-ing c...");
00466     buf_wifly.dequeue(&c);
00467     //DBG("Return c:(%c)",c);
00468     return c;
00469 }
00470 
00471 void Wifly::handler_rx(void)
00472 {
00473     //read characters
00474     while (wifi.readable())
00475         buf_wifly.queue(wifi.getc());
00476 }
00477 
00478 void Wifly::attach_rx(bool callback)
00479 {
00480     if (!callback)
00481         wifi.attach(NULL);
00482     else
00483         wifi.attach(this, &Wifly::handler_rx);
00484 }
00485 
00486 
00487 int Wifly::send(const char * str, int len, const char * ACK, char * res, int timeout)
00488 {
00489     char read;
00490     size_t found = string::npos;
00491     string checking;
00492     Timer tmr;
00493     int result = 0;
00494     
00495     // Don't display the string that we will be sending because it is encoded, thus may screw up printf()
00496     if(ACK == NULL){
00497         DBG("Will send a string, no ACK requested.");
00498     }else{
00499         DBG("Will send a string, looking for ACK: %s", ACK);
00500     }
00501 
00502     attach_rx(false);
00503 
00504     //We flush the buffer
00505     while (wifi.readable())
00506         wifi.getc();
00507 
00508     if (!ACK || !strcmp(ACK, "NO")) {
00509         for (int i = 0; i < len; i++)
00510             result = (putc(str[i]) == str[i]) ? result + 1 : result;
00511     } else {
00512         //We flush the buffer
00513         while (wifi.readable())
00514             wifi.getc();
00515 
00516         tmr.start();
00517         for (int i = 0; i < len; i++)
00518             result = (putc(str[i]) == str[i]) ? result + 1 : result;
00519 
00520         while (1) {
00521             if (tmr.read_ms() > timeout) {
00522                 //We flush the buffer
00523                 while (wifi.readable())
00524                     wifi.getc();
00525 
00526                 DBG("check: %s", checking.c_str());
00527                 DBG("result ignored: %d", result)
00528                 attach_rx(true);
00529                 return -1;
00530             } else if (wifi.readable()) {
00531                 read = wifi.getc();
00532                 if ( read != '\r' && read != '\n') {
00533                     checking += read;
00534                     found = checking.find(ACK);
00535                     if (found != string::npos) {
00536                         wait(0.01);
00537 
00538                         //We flush the buffer
00539                         while (wifi.readable())
00540                             wifi.getc();
00541 
00542                         break;
00543                     }
00544                 } 
00545             }
00546         }
00547         DBG("check: %s", checking.c_str());
00548         DBG("result: %d", result)
00549         attach_rx(true);
00550         return result;
00551     }
00552 
00553     //the user wants the result from the command (ACK == NULL, res != NULL)
00554     if ( res != NULL) {
00555         int i = 0;
00556         Timer timeout;
00557         timeout.start();
00558         tmr.reset();
00559         while (1) {
00560             if (timeout.read() > 2) {
00561                 if (i == 0) {
00562                     res = NULL;
00563                     break;
00564                 }
00565                 res[i] = '\0';
00566                 DBG("user str 1: %s", res);
00567 
00568                 break;
00569             } else {
00570                 if (tmr.read_ms() > 300) {
00571                     res[i] = '\0';
00572                     DBG("user str2: %s", res);
00573 
00574                     break;
00575                 }
00576                 if (wifi.readable()) {
00577                     tmr.start();
00578                     read = wifi.getc();
00579 
00580                     // we drop \r and \n
00581                     if ( read != '\r' && read != '\n') {
00582                         res[i++] = read;
00583                     }
00584                 }
00585             }
00586         }
00587         DBG("user str3: %s", res);
00588     }
00589 
00590     //We flush the buffer
00591     while (wifi.readable())
00592         wifi.getc();
00593 
00594     attach_rx(true);
00595     DBG("result: %d", result)
00596     return result;
00597 }
00598 
00599 int Wifly::checkNetworkStatus(void){
00600     int status = 0;   
00601     char rcv[128];
00602     unsigned int ConnectionReg;
00603     
00604     if(!sendCommand("show c\r", NULL, rcv, 5000)){
00605         status = 0;
00606         // the sendCommand function quits command mode if there is an error
00607     }else{
00608         // check the response:
00609         sscanf(rcv, "%x%*s", &ConnectionReg);
00610         if(((ConnectionReg & CC_ASSOCIATION)>0) && ((ConnectionReg & CC_AUTHENTICATION)>0)){
00611             // Associated and Authenticated:
00612             status = 3;
00613         }else if((ConnectionReg & CC_ASSOCIATION)>0){
00614             // Associated:
00615             status = 1;
00616         }else if((ConnectionReg & CC_AUTHENTICATION)>0){
00617             // Athenticated:
00618             status = 2;
00619         }else{
00620             // Disconnected:
00621             status = 0;
00622         }
00623         INFO("Wifly Check network response: 0x%x, Status: %d", ConnectionReg, status);
00624         exit(); // Quit command mode
00625     }
00626     
00627     return status;
00628 }
00629 
00630 void Wifly::sleep(void){
00631     // This function puts the module to sleep:
00632     sendCommand("sleep\r", NULL);
00633     // It will wake up from sleep if any characters are sent to it.
00634     return;
00635 }