BSSID management

From openPicus Wiki
Jump to: navigation, search

Contents

What you are going to learn

This tutorial explains how to control the WiFi transceiver and specifically how to manage the BSSID parameter also in relation to roaming.

Disclaimer

The Signal Level information made available by the Microchip Transceiver is not metrically accurate, meaning it does not provide any real scientifically valid measure. You could expect dB/m or something like that, unfortunately this is not the case. The measure is absolute but relative to the Flyport transceiver, so there is a range from 0 to 128 which means no reception to maximum possible reception.

Introduction

Since version 2.4, the Flyport Libraries provide a much finer configuration of the WiFi profiles enabling BSSID management.

The BSSID (which stands for Basic Service Set IDentification) is the MAC address of the base station. By exploiting control over this parameter it is possible to seek or reject a specific access point. In conjunction with the power level measure (see the RSSI Signal Level Tutorial) it is even possible to enable a kind of roaming.
!!! NOTE !!!
The roaming mentioned in this tutorial is not the actual roaming specified in document WR-SP-WiFi-ROAM-I01-100729 of the 802.11 standard. This is a fake roaming enabled via sampling the signal level, but it is in no way a production level algorithm and/or protocol.

So we are first going to show how to control the BSSID, and then how to play around with it.

What you need

In order to complete this tutorial you need two WiFi access points. Any two. Could be two smartphones (with wireless-ap mode), a home router and a smartphone, two routers. The combination is not relevant as long as you can have access to two access points.

You also need to write down the MAC address of both APs, and configure them to have the very same SSID (that's the wifi network name), security type and password.

In this tutorial we are going to use notions introduced in the How to read Wifi Power signal using Flyport Wifi - G so it should be best to read that first.

Step 1: force BSSID

The first step is very simple and forces the Flyport to connect to a specific access point. First of all open the IDE, and create a new WIFI-G -> BASIC project. Open the Wizard and configure the connection entering the correct SSID, security and password (which, as stated above, must be identical for both APs).

Now use the following as your taskFlyport.c

#include "taskFlyport.h"
void FlyportTask()
{	
	char mymac[6]={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	NETSetParam(BSSID,mymac);
	WFConnect(WF_CUSTOM);
	while (WFStatus != CONNECTED);
	UARTWrite(1,"Flyport connected... hello world!\r\n");
	vTaskDelay(200);
	while(!DHCPAssigned);
	vTaskDelay(100);
 
	while(1)
	{
		vTaskDelay(1000);
	}
}

You have to substitute all the 0xFF in the char array with the correct bytes representing the MAC address of the access point you want to connect to.

If everything is correct, you should see a message saying the Flyport has a new IP address which means it has been enumerated by the access point and issued a valid IP by the dhcp server. To be sure the connection is effectively working, just open a command prompt and ping the Flyport's IP.

Step 2: switch on best AP

This is where we are going to use the How to read Wifi Power signal using Flyport Wifi - G tutorial. The firmware will keep checking the RSSI signal level of both access points, and switch to the strongest one.

The Code

Let's start from the signal metering part. The initial part is identical to that in the previous section, but after that many pieces are added. Take note of the exact name of your SSID because you need to put that in the code below.


#include "taskFlyport.h"
BOOL macsEqual(BYTE mac1[], BYTE mac2[]);
void macCopy (BYTE macin[], BYTE macout[]);
 
extern BOOL ScanCompleted;
 
{   
    int init = FALSE;
    char msg[150];
    int i=0;
    tWFNetwork mystruct;
 
    // Connection to Network
    char mymac[6]={0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
    NETSetParam(BSSID,mymac);
    WFConnect(WF_CUSTOM);
    while (WFStatus != CONNECTED);
 
    UARTWrite(1,"Flyport connected... hello world!\r\n");
    vTaskDelay(200);
    while(!DHCPAssigned);
    vTaskDelay(100);    
 
    while(1)
    {
        UARTWrite(1,"\n\n~~~~  NEW CYCLE ~~~~\n");
        if(init == 0)
        {   
            UARTWrite(1,"Initiating scan\n");
            WFScan();
            init = TRUE;
        }
 
        if (ScanCompleted==TRUE)
        {
            newsignal=0; oldsignal=0;
            WF_CPGetBssid(1, oldmac);
            sprintf(msg,"\nSaved BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",oldmac[0],oldmac[1],oldmac[2],oldmac[3],oldmac[4],oldmac[5]);
            UARTWrite(1,msg);
            for (i=1; i<WFNetworkFound+1; i++)
            {
                mystruct = WFScanList(i);
                if(strcmp(mystruct.ssid,"!!! NAME OF YOUR SSID !!!") == 0)
                {
                    if(macsEqual(mymac,mystruct.bssid))
                    {
                        sprintf(msg,"Home RSSI: %d\n",mystruct.signal);
                        UARTWrite(1,msg);
                    }
                    else
                    {
                        sprintf(msg,"New RSSI: %d\n",mystruct.signal);
                        UARTWrite(1,msg);
                    }
 
                    if (macsEqual(oldmac,mystruct.bssid))
                        oldsignal = mystruct.signal;
 
                    else
                    {
                        macCopy(mystruct.bssid,newmac);
                        newsignal = mystruct.signal;
                    }
                }
            }
            if ((newsignal != 0) && (oldsignal != 0) && (newsignal > oldsignal))
            {
                sprintf(msg,"New : %d\nOld : %d\n",newsignal,oldsignal);
                UARTWrite(1,msg);
                sprintf(msg,"SWITCHING TO NEW!\n%02X:%02X:%02X:%02X:%02X:%02X\n",newmac[0],newmac[1],newmac[2],newmac[3],newmac[4],newmac[5]);
                UARTWrite(1,msg);
                WFDisconnect();
                NETSetParam(BSSID,newmac);
                WFConnect(WF_CUSTOM);
                while (WFStatus != CONNECTED);
 
                UARTWrite(1,"Flyport connected... hello world!\r\n");
                vTaskDelay(200);
                while(!DHCPAssigned);
                vTaskDelay(100);
            }
            ScanCompleted = FALSE;
            init = FALSE;
        }
 
    }
}
 
BOOL macsEqual(BYTE mac1[], BYTE mac2[])
{
    int i,result=0;
    for (i=0; i<6; i++)
        result += (mac1[i] == mac2[i]);
    if (result == 6)
        return TRUE;
    return FALSE;
}
 
void macCopy (BYTE macin[], BYTE macout[])
{
    int i;
    for (i=0;i<6;i++)
        macout[i]=macin[i];
}

The Explanation

This is intended to work with just 2 APs broadcasting the same SSID, to support more APs changes must be made.
The switching logic is also very simple

if ((newsignal != 0) && (oldsignal != 0) && (newsignal > oldsignal))

It's just a sanity check on both variables (meaning we want to have sure readings for both) and then just a greater than.

Notice the code makes use of two service functions to make it more readable, the name of the functions should be clear enough

  1. macCopy - copy MAC addresses
  2. macsEqual - verify two MAC addresses are equal

So lets concentrate on what happens. After initialization and connection, the main cycle initiates a scan. You'll see an output similar to the following

DHCP client successful
 
New IP Address: 192.168.1.104
 
 
----  NEW CYCLE ----
Initiating scan
 
 
----  NEW CYCLE ----
 
 
----  NEW CYCLE ----
 
 
----  NEW CYCLE ----
 
 
----  NEW CYCLE ----
Event: Scan Results Ready, 6 results
 
 
----  NEW CYCLE ----
 
Saved BSSID: 01:02:03:04:05:06
Home RSSI: 70



Now turn on the second AP. At the next scan, you should see something like this

----  NEW CYCLE ----
Initiating scan
 
 
----  NEW CYCLE ----
 
 
----  NEW CYCLE ----
 
 
----  NEW CYCLE ----
 
 
----  NEW CYCLE ----
Event: Scan Results Ready, 5 results
 
 
----  NEW CYCLE ----
 
Saved BSSID: 01:02:03:04:05:06
New RSSI: 98
Home RSSI: 74
New : 98
Old : 74
SWITCHING TO NEW!
01:02:03:04:05:06


Now that there are two APs broadcasting, the scan reports them and the check

if(strcmp(mystruct.ssid,"!!! NAME OF YOUR SSID !!!") == 0)

is true two times. The order of these two times is not important. One will be the AP we are connected to, and the other time will be the new AP. The subsequent IFs serve to distinguish these cases:

if (macsEqual(oldmac,mystruct.bssid))
	oldsignal = mystruct.signal;
 
else
{
	macCopy(mystruct.bssid,newmac);
	newsignal = mystruct.signal;
}

Either the detected MAC is the one we are already connected to (1st intance), or is a new one (2nd instance). In both cases we save the signal strength, but just in case it's a new MAC we also save the MAC itself just in case we have to connect to it (may be the first instead of the last, so we can't be sure that the mystruct.bssid will contain exactly that value when we need it).

When the scan is complete the code will check if it has encountered a stronger AP, and in that case start the new connection sequence.

Variations

This code is pretty simple and lacks a number of features: filtering on the RSSI values (noise may easily trigger fast reconnections), connectivity loss management (if a connection is lost, the code will just try to connect to the previous station), more than 2 APs with the same SSID, and more.

All of the above can be done, but it's left to you to implement, this tutorial should be taken as guide to better understand the properties of the Flyport Libs.

Personal tools
Namespaces

Variants
Actions
START HERE
DEVELOPMENT
HARDWARE INFO
RESOURCES
PHASED OUT
Toolbox