Micro:bit IoT In C - Getting On WiFi
Written by Harry Fairhead   
Saturday, 16 July 2016
Article Index
Micro:bit IoT In C - Getting On WiFi
Setup
Utility Functions
Getting A Web Page
A Web Server
Listing

Some Utility Functions

Before we get into the details of connecting to a network and transferring data it is worth constructing some useful utility functions.

The need to wait for an "OK" or similar response is so common that it is worth having a function to do the job. 

int waitForWiFi(ManagedString target,
                        int retry,int pause){
 ManagedString s;
 do {
  uBit.sleep(pause);
  if(s.length()>500)s="";
  s = s + uBit.serial.read(500, ASYNC);
  retry--;
 } while (find(target, s) == 0 && retry != 0);
 if (DEBUG)debug("\n\r" + s + "\n\r");
 return retry;
}

Notice that now we can specify the target, a pause in milliseconds between polling attempts, and a timeout in terms of how many retries before the function gives up. Notice that the function returns 0 if there was a failure and the retry loop timed out and the number of retries remaining otherwise. 

Using this utility function the ATWiFi function can be written:

int ATWiFi() {
 uBit.serial.send("AT\r\n", SYNC_SPINWAIT);
 return waitForWiFi("OK",150,10);
}

This is a lot shorter and easier to understand.

Assuming that you have managed to make the AT command work it is time to move on to other AT commands. The first useful command is to find the Version number of the firmware. This is more or less the same as the AT function, but the command is AT+GMR and we get back more data - hence the longer wait time:

int getVersionWiFi() {
 uBit.serial.send("AT+GMR\r\n", SYNC_SPINWAIT);
 return waitForWiFi("OK",200,10);
}

The device in use returned:

AT+GMR
AT version:0.60.0.0(Jan 29 2016 15:10:17)
SDK version:1.5.2(7eee54f4)
Ai-Thinker Technology Co. Ltd.
May  5 2016 17:30:30
OK

The manual says that it should return AT, SDK and the time it was compiled - so we get a little extra with this third party device.

Another useful function is Reset. The device often gets stuck and then a reset is all that you can try. This is a software reset; another option is to use a GPIO line to connect to reset pin 6. By controlling this line you can force the device to hard reset. 

The soft reset command is AT+RST and all you get back in theory is "OK", but in practice the device sends a few hundred bytes of configuration data:

int resetWiFi() {
  uBit.serial.send("AT+RST\r\n", SYNC_SPINWAIT);    
  return waitForWiFi("OK", 1000, 10);
}

The final utility function is to set the serial connection parameters to 115200, 8 bits, 1 stop bit, no parity, no flow control:

int setUARTWiFi() {  
 uBit.serial.send("AT+UART_CUR=115200,8,1,0,0\r\n",
                                   SYNC_SPINWAIT);
 return waitForWiFi("OK", 200, 10);
}

If you change the baud rate to something other than what is in use you will, of course, lose communication with the device until you reconfigure the micro:bit's serial connection. 

Configuring WiFi

The first thing we need to configure is the operating mode. The ESP8622 can operate as an access point, i.e. it can allow other devices to connect to it. However, in most cases you will want it to work in client mode, i.e. connecting to your existing WiFi. 

Mode

A function to set its operating mode is:

int modeWiFi(int mode) {
 ManagedString cmd = "AT+CWMODE_CUR=" +
                ManagedString(mode) + "\r\n";
 uBit.serial.send(cmd, SYNC_SPINWAIT);
 return waitForWiFi("OK", 200, 10);
}

Notice that now we are constructing the command to send to the device in a separate step. If you try and do this on the fly in the function call the rate of transmission of the serial data varies and the device can time out. In practice, construct all commands to send to the device first and then send them. 

In this case the command is: 

AT+CWMODE_CUR=n

where n is 1 for client, 2 for access point and 3 for both.  If you want to make the change permanent then change CUR to DEF and the setting is stored in Flash. 

Older devices do not support CWMODE_CUR. Simply change it to CWMODE, which is deprecated.

To set client you would call:

modeWiFi(1);

and see OK sent back.

Scan

The scan function is one that everyone wants to try out, but in practice it isn't very useful. Why would you want a list of WiFi networks? There are some applications for this function, but not as many as you might think. In most cases you simply want to connect to a known WiFi network - which is what we do in the next section.

The scan command is easy - just send AT+CWLAP and the device sends you a complete list of WiFi networks.

The problem is that scanning takes a long time and often hangs. This is one case where we really need to specify a long timeout. 

int scanWiFi() {
 uBit.serial.send("AT+CWLAP\r\n", SYNC_SPINWAIT);
 return waitForWiFi("OK", 500, 50);
}

Sometimes the loop completes with a full list, sometimes it doesn't. It depends on the WiFi networks that are available and how they reply to requests. 

Connecting to WiFi

Our final and most useful functions connect the device to a known WiFi network. All you have to do is supply the SSID and password. There are other versions of the command that allow you to specify the connection more precisely, but this general form is the most useful. 

Connection to a network takes a while and there is quite a lot of data sent back, so we need to use the retry count loop introduced in the scan function:

int connectWiFi(ManagedString ssid,
                      ManagedString pass) {
 ManagedString cmd = "AT+CWJAP_CUR=\"" + ssid +
                        "\",\"" + pass + "\"\r\n";    
 uBit.serial.send(cmd, SYNC_SPINWAIT);
 return waitForWiFi("OK", 200, 20);
}

If you have an older device you might need to change CWJAP_CUR to the deprecated CWJAP command. There is also a CWJAP_DEF command that will save the connection in the Flash memory. 

When the connection is made:

connectWiFi("myWiFi","myPassword");

after a few seconds you should see:

AT+CWJAP_CUR="myWiFi","myPassword"
WIFI DISCONNECT
WIFI CONNECTED
WIFI GOT IP
OK

Once you are connected and the "WIFI GOT IP" message has been received you can ask what the IP address is:

int getIPWiFi() {
 uBit.serial.send("AT+CIFSR\r\n", SYNC_SPINWAIT);    
 return waitForWiFi("OK", 200, 10);
}

Of course, if you really need to know the IP address within a program you need to extract it from the string. The device replies with:

IP address:
AT+CIFSR
+CIFSR:STAIP,"192.168.253.4"
+CIFSR:STAMAC,"5c:cf:7f:16:97:ab"
OK

which makes it very easy to get the IP address even without the help of a regular expression. 



Last Updated ( Friday, 26 August 2016 )