MODIFIED from mbed official WiflyInterface (interface for Roving Networks Wifly modules). Numerous performance and reliability improvements (see the detailed documentation). Also, tracking changes in mbed official version to retain functional parity.

Dependents:   Smart-WiFly-WebServer PUB_WiflyInterface_Demo

Fork of WiflyInterface by mbed official

Resources

Derivative from mbed Official

  • Documentation update, improved consistency, documented parameters that were inadvertently omitted.
  • Avoid c++ string handling, which causes dynamic allocation and free, side effect, fewer CPU cycles spent for same purpose.
  • Fixed socket APIs to support non-blocking mode.
  • Increase communication baud-rate to Wifly module
  • sendCommand - added retries for improved robustness.
  • setConnectionState - method to force the connection state (used by TCPSocketServer)
  • gethostbyname - added a length parameter to the size of the buffer being written
  • flushIn - a private method to flush the input buffer
  • Changed the timeout from 500 to 2500 msec for commands - measured some at 700 to 850 msec.
  • Performance improvements - reduced some unnecessary delays.
  • Added additional security options for the wi-fi connection (that are supported by the WiFly module).
  • Added setSecurity API which permits revising the security when connecting to, or selecting from, one of several access points.
  • Improved DEBUG interface (slightly more consistent printout).
  • gathers information from the Wifly module on reboot (SW version info), which permits customizing behavior based on Wifly capabilities (like the improved security).
  • Avoid potential for recursive crash (if exit fails, it calls sendcommand, which calls exit...)
  • Update to support permissible SSID and PassCode lengths.

Robustness testing

I've had some mixed behavior with the Wifly module, some of which seems to be traceable to the module itself, and some in my derivative code. The result, after running for minutes, hours, sometimes days, it hangs and I have to reset the module.

To test, I created a fairly simple test program -

  • check for Watchdog induced reset and count it.
  • initialize the Watchdog for 60 sec timeout.
  • Init the Wifly interface and connect to my network.
  • Wait 10 seconds and force mbed_reset().

If the Watchdog induces the restart, then it is pretty clear that either:

  • The communications hung with the Wifly module causing the failure.
  • The Wifly module decided to go unresponsive.

If it gets to the end, it typically takes about 4 to 6 seconds for the boot and connect, then the 10 second delay.

But I can't really pin down the root cause easily. My strongest theory is that the Wifly module has rebooted, and since I don't store the high baud rate I configure it for, it resets back to 9600.

Also, one of the objectives for my revised send( ) is to avoid the c++ string, as that can fragment memory, and it wasn't very well bounded in behavior.

Latest tests:

Warm BootsWatchdog EventsNotes
100's30An early version of my derivative WiflyInterface, including my derivative of "send( )" API. Let's call this version 0.1.
26684My derivative WiflyInterface, but with the mbed official "send( )" API. Much improved. This was over the course of about 12 hours.
24003Most recent derivative - incremental change to "send( )", but this relative number does not rule out the Wifly module itself.

I think with these numbers, +/- 1 means that the changes have had no measurable effect. Which is good, since this incremental change eliminates the c++ string handling.

Test Software

This is pieces of a test program, clipped and copied to here. What I have compiled and run for hours and hours is almost exactly what you see. This uses this simple Watchdog library.

#include "mbed.h"
#include "WiflyInterface.h"
#include "Watchdog.h"

Serial pc(USBTX, USBRX);

Watchdog wd;
extern "C" void mbed_reset();

// Pinout for SmartBoard
WiflyInterface wifly(p9, p10, p30, p29, "ssid", "pass", WPA);

int main() {
    pc.baud(460800);                         // I like a snappy terminal
    
    wd.Configure(60.0);                     // Set time limit for the test to 1 minute
    LPC_RTC->GPREG0++;                      // Count boots here
    if (wd.WatchdogCausedReset()) {
        LPC_RTC->GPREG1++;                  // Count Watchdog events here
        pc.printf("\r\n\r\nWatchdog event.\r\n");
    }
    pc.printf("\r\nWifly Test: %d boots, %d watchdogs. %s %s\r\n", LPC_RTC->GPREG0, LPC_RTC->GPREG1, __DATE__, __TIME__);
    
    wifly.init(); // use DHCP
    pc.printf("Connect...  ");
    while (!wifly.connect());               // join the network
    pc.printf("Address is %s.  ", wifly.getIPAddress());
    pc.printf("Disconnect...  ");
    wifly.disconnect();
    pc.printf("OK. Reset in 10 sec...\r\n");
    wait(10);
    if (pc.readable()) {
        if (pc.getc() == 'r') {             // secret 'r'eset of the counters
            LPC_RTC->GPREG0 = 0;
            LPC_RTC->GPREG1 = 0;
            pc.printf("counters reset\r\n");
        }
    }
    mbed_reset();                           // reset here indicates successful communication
}
Committer:
WiredHome
Date:
Mon Dec 03 02:06:24 2018 +0000
Revision:
78:a03a5dade5b5
Parent:
WiflyInterface.cpp@76:d94cd478c7fc
Renamed the WiflyInterface header and class name to EthernetInterface to be more readily swapped with the wired version. The TimeInterface then works directly.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 78:a03a5dade5b5 1 #include "EthernetInterface.h"
WiredHome 51:a4831b1cb9a4 2
WiredHome 73:59d0bbc4f905 3
WiredHome 75:4f8817f67f67 4 //#define DEBUG "WFLY" //Debug is disabled by default
WiredHome 73:59d0bbc4f905 5
WiredHome 73:59d0bbc4f905 6 // How to use this debug macro
WiredHome 73:59d0bbc4f905 7 //
WiredHome 73:59d0bbc4f905 8 // ...
WiredHome 73:59d0bbc4f905 9 // INFO("Stuff to show %d", var); // new-line is automatically appended
WiredHome 73:59d0bbc4f905 10 // [I myfile 23] Stuff to show 23\r\n
WiredHome 73:59d0bbc4f905 11 //
WiredHome 73:59d0bbc4f905 12 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 73:59d0bbc4f905 13 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 73:59d0bbc4f905 14 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 73:59d0bbc4f905 15 #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 73:59d0bbc4f905 16 #else
WiredHome 73:59d0bbc4f905 17 #define INFO(x, ...)
WiredHome 73:59d0bbc4f905 18 #define WARN(x, ...)
WiredHome 73:59d0bbc4f905 19 #define ERR(x, ...)
WiredHome 73:59d0bbc4f905 20 #endif
WiredHome 73:59d0bbc4f905 21
WiredHome 73:59d0bbc4f905 22 static char myName[33]; // name cannot exceed 32 chars
WiredHome 73:59d0bbc4f905 23
WiredHome 78:a03a5dade5b5 24 EthernetInterface::EthernetInterface( PinName tx, PinName rx, PinName reset, PinName tcp_status,
WiredHome 51:a4831b1cb9a4 25 const char * ssid, const char * phrase, Security sec) :
WiredHome 51:a4831b1cb9a4 26 Wifly(tx, rx, reset, tcp_status, ssid, phrase, sec)
WiredHome 51:a4831b1cb9a4 27 {
WiredHome 51:a4831b1cb9a4 28 ip_set = false;
WiredHome 72:9499f5c1e00b 29 mac_set = false;
WiredHome 73:59d0bbc4f905 30 myName[0] = '\0';
WiredHome 51:a4831b1cb9a4 31 }
WiredHome 51:a4831b1cb9a4 32
WiredHome 78:a03a5dade5b5 33 int EthernetInterface::init()
WiredHome 51:a4831b1cb9a4 34 {
WiredHome 51:a4831b1cb9a4 35 state.dhcp = true;
WiredHome 72:9499f5c1e00b 36 ip_set = false;
WiredHome 51:a4831b1cb9a4 37 reset();
WiredHome 67:557ea7ad15c1 38 configure();
WiredHome 51:a4831b1cb9a4 39 return 0;
WiredHome 51:a4831b1cb9a4 40 }
WiredHome 51:a4831b1cb9a4 41
WiredHome 78:a03a5dade5b5 42 int EthernetInterface::init(const char* ip, const char* mask, const char* gateway)
WiredHome 51:a4831b1cb9a4 43 {
WiredHome 51:a4831b1cb9a4 44 state.dhcp = false;
WiredHome 51:a4831b1cb9a4 45 this->ip = ip;
WiredHome 51:a4831b1cb9a4 46 strcpy(ip_string, ip);
WiredHome 51:a4831b1cb9a4 47 ip_set = true;
WiredHome 51:a4831b1cb9a4 48 this->netmask = mask;
WiredHome 51:a4831b1cb9a4 49 this->gateway = gateway;
WiredHome 51:a4831b1cb9a4 50 reset();
WiredHome 67:557ea7ad15c1 51 configure();
WiredHome 51:a4831b1cb9a4 52 return 0;
WiredHome 51:a4831b1cb9a4 53 }
WiredHome 51:a4831b1cb9a4 54
WiredHome 78:a03a5dade5b5 55 void EthernetInterface::setSecurity(const char * ssid, const char * phrase, Security sec)
WiredHome 51:a4831b1cb9a4 56 {
WiredHome 51:a4831b1cb9a4 57 Wifly::SetSecurity(ssid, phrase, sec);
WiredHome 45:21b7bbaad62b 58 }
WiredHome 51:a4831b1cb9a4 59
WiredHome 78:a03a5dade5b5 60 int EthernetInterface::connect()
WiredHome 51:a4831b1cb9a4 61 {
WiredHome 63:fee0b25f1bf5 62 return (join()) ? 0 : -1;
WiredHome 51:a4831b1cb9a4 63 }
WiredHome 51:a4831b1cb9a4 64
WiredHome 78:a03a5dade5b5 65 int EthernetInterface::disconnect()
WiredHome 51:a4831b1cb9a4 66 {
WiredHome 72:9499f5c1e00b 67 ip_set = false;
WiredHome 51:a4831b1cb9a4 68 return Wifly::disconnect();
WiredHome 51:a4831b1cb9a4 69 }
WiredHome 51:a4831b1cb9a4 70
WiredHome 72:9499f5c1e00b 71 // command "get mac\r"
WiredHome 72:9499f5c1e00b 72 // response "MAC Addr=##:##:##:##:##:##\n<4.40> "
WiredHome 78:a03a5dade5b5 73 char * EthernetInterface::getMACAddress()
WiredHome 72:9499f5c1e00b 74 {
WiredHome 72:9499f5c1e00b 75 char buffer[50];
WiredHome 72:9499f5c1e00b 76 char * match = buffer;
WiredHome 72:9499f5c1e00b 77 char * p;
WiredHome 72:9499f5c1e00b 78 if (!mac_set) {
WiredHome 76:d94cd478c7fc 79 mac_string[0] = '\0';
WiredHome 72:9499f5c1e00b 80 if (!sendCommand("get mac\r", NULL, buffer))
WiredHome 72:9499f5c1e00b 81 return NULL;
WiredHome 72:9499f5c1e00b 82 exit();
WiredHome 72:9499f5c1e00b 83 flush();
WiredHome 73:59d0bbc4f905 84 INFO("buffer is '%s'", buffer);
WiredHome 72:9499f5c1e00b 85 // revised to find the mac address string, following a small
WiredHome 72:9499f5c1e00b 86 // change where \r are permitted in the captured
WiredHome 72:9499f5c1e00b 87 // reply to a command.
WiredHome 72:9499f5c1e00b 88 while (*match && (*match != '='))
WiredHome 72:9499f5c1e00b 89 match++;
WiredHome 72:9499f5c1e00b 90 if (*match) {
WiredHome 72:9499f5c1e00b 91 match++; // Advance past '='
WiredHome 72:9499f5c1e00b 92 p = match;
WiredHome 72:9499f5c1e00b 93 while (strchr("0123456789abcdefABCDEF:", *p))
WiredHome 72:9499f5c1e00b 94 p++;
WiredHome 72:9499f5c1e00b 95 *p = '\0';
WiredHome 72:9499f5c1e00b 96 if (strlen(match) <= 17) { // 192.168.101.202
WiredHome 72:9499f5c1e00b 97 strcpy(mac_string, match);
WiredHome 72:9499f5c1e00b 98 mac_set = true;
WiredHome 72:9499f5c1e00b 99 }
WiredHome 72:9499f5c1e00b 100 }
WiredHome 72:9499f5c1e00b 101 }
WiredHome 73:59d0bbc4f905 102 return mac_string;
WiredHome 72:9499f5c1e00b 103 }
WiredHome 72:9499f5c1e00b 104
WiredHome 51:a4831b1cb9a4 105 // typical response might be
WiredHome 51:a4831b1cb9a4 106 // \r192.168.43.107\r
WiredHome 51:a4831b1cb9a4 107 // <4.40>
WiredHome 78:a03a5dade5b5 108 char * EthernetInterface::getIPAddress()
WiredHome 51:a4831b1cb9a4 109 {
WiredHome 65:427518ba7b01 110 char buffer[50];
WiredHome 65:427518ba7b01 111 char * match = buffer;
WiredHome 65:427518ba7b01 112 char * p;
WiredHome 51:a4831b1cb9a4 113 if (!ip_set) {
WiredHome 65:427518ba7b01 114 if (!sendCommand("get ip a\r", NULL, buffer))
WiredHome 51:a4831b1cb9a4 115 return NULL;
WiredHome 51:a4831b1cb9a4 116 exit();
WiredHome 51:a4831b1cb9a4 117 flush();
WiredHome 51:a4831b1cb9a4 118 // revised to find the IP string, following a small
WiredHome 51:a4831b1cb9a4 119 // change where \r are permitted in the captured
WiredHome 51:a4831b1cb9a4 120 // reply to a command.
WiredHome 51:a4831b1cb9a4 121 while (*match && (*match < '0' || *match > '9'))
WiredHome 51:a4831b1cb9a4 122 match++;
WiredHome 65:427518ba7b01 123 p = match;
WiredHome 65:427518ba7b01 124 while (strchr("0123456789.", *p))
WiredHome 65:427518ba7b01 125 p++;
WiredHome 65:427518ba7b01 126 *p = '\0';
WiredHome 65:427518ba7b01 127 if (strlen(match) <= 15) { // 192.168.101.202
WiredHome 65:427518ba7b01 128 strcpy(ip_string, match);
WiredHome 65:427518ba7b01 129 ip_set = true;
WiredHome 65:427518ba7b01 130 }
WiredHome 51:a4831b1cb9a4 131 }
WiredHome 51:a4831b1cb9a4 132 return ip_string;
WiredHome 51:a4831b1cb9a4 133 }
WiredHome 72:9499f5c1e00b 134
WiredHome 73:59d0bbc4f905 135 static bool inRange(char testChar, char minChar, char maxChar)
WiredHome 73:59d0bbc4f905 136 {
WiredHome 73:59d0bbc4f905 137 if (testChar >= minChar && testChar <= maxChar)
WiredHome 73:59d0bbc4f905 138 return true;
WiredHome 73:59d0bbc4f905 139 else
WiredHome 73:59d0bbc4f905 140 return false;
WiredHome 73:59d0bbc4f905 141 }
WiredHome 72:9499f5c1e00b 142
WiredHome 78:a03a5dade5b5 143 int EthernetInterface::setName(const char * myname)
WiredHome 72:9499f5c1e00b 144 {
WiredHome 73:59d0bbc4f905 145 char buffer[60]; // hold the whole command
WiredHome 73:59d0bbc4f905 146 int i;
WiredHome 73:59d0bbc4f905 147
WiredHome 73:59d0bbc4f905 148 strncpy(myName, myname, 32);
WiredHome 73:59d0bbc4f905 149 myName[32] = '\0'; // be sure it is NULL terminated.
WiredHome 73:59d0bbc4f905 150 // make the name 'safe'
WiredHome 73:59d0bbc4f905 151 for (i=0; i<32 && myName[i]; i++) {
WiredHome 73:59d0bbc4f905 152 if (!inRange(myName[i], '0', '9')
WiredHome 73:59d0bbc4f905 153 && !inRange(myName[i], 'A', 'Z')
WiredHome 73:59d0bbc4f905 154 && !inRange(myName[i], 'a', 'z'))
WiredHome 73:59d0bbc4f905 155 myName[i] = '-';
WiredHome 73:59d0bbc4f905 156 }
WiredHome 73:59d0bbc4f905 157 sprintf(buffer, "set opt deviceid %s\r", myname);
WiredHome 73:59d0bbc4f905 158 if (!sendCommand(buffer, "OK"))
WiredHome 73:59d0bbc4f905 159 return -1; // fail
WiredHome 72:9499f5c1e00b 160 return 0; // indicate success...
WiredHome 72:9499f5c1e00b 161 }
WiredHome 72:9499f5c1e00b 162
WiredHome 78:a03a5dade5b5 163 const char * EthernetInterface::getName(void)
WiredHome 72:9499f5c1e00b 164 {
WiredHome 73:59d0bbc4f905 165 return myName;
WiredHome 72:9499f5c1e00b 166 }
WiredHome 73:59d0bbc4f905 167
WiredHome 78:a03a5dade5b5 168 int EthernetInterface::get_connection_speed(void)
WiredHome 73:59d0bbc4f905 169 {
WiredHome 73:59d0bbc4f905 170 char bigbuf[200]; // big enough?
WiredHome 73:59d0bbc4f905 171 int res = 0;
WiredHome 73:59d0bbc4f905 172
WiredHome 73:59d0bbc4f905 173 if (sendCommand("get wlan\r", NULL, bigbuf)) {
WiredHome 73:59d0bbc4f905 174 // "Rate=15, 54 Mb\r"
WiredHome 73:59d0bbc4f905 175 char * p = strstr(bigbuf, "Rate=");
WiredHome 73:59d0bbc4f905 176
WiredHome 73:59d0bbc4f905 177 if (p) {
WiredHome 73:59d0bbc4f905 178 p += 5; // strlen("Rate=");
WiredHome 73:59d0bbc4f905 179 while (*p && *p != ' ')
WiredHome 73:59d0bbc4f905 180 p++;
WiredHome 73:59d0bbc4f905 181 while (*p && *p == ' ')
WiredHome 73:59d0bbc4f905 182 p++;
WiredHome 73:59d0bbc4f905 183 res = atoi(p);
WiredHome 73:59d0bbc4f905 184
WiredHome 73:59d0bbc4f905 185 }
WiredHome 73:59d0bbc4f905 186 }
WiredHome 73:59d0bbc4f905 187 return res;
WiredHome 73:59d0bbc4f905 188 }