This program calculate location of Wi-Fi receiver, by using AP beacon. Please check the Japanese magazine "Interface 2012/12".

Dependencies:   TextLCD mbed

WiFiScanner.h

Committer:
nakata
Date:
2012-09-10
Revision:
1:2f2f793fcf4f
Parent:
0:4eaf38ccb19c

File content as of revision 1:2f2f793fcf4f:

#include <string.h>

#define BAUD_RATE 115200

#define MULTI_CHANNEL
#ifdef  MULTI_CHANNEL
#define TOTAL_CHANNELS  13
#else
#define TOTAL_CHANNELS  1
#endif
#define MAX_AP_COUNT    (10 * TOTAL_CHANNELS)
//#define PASSIVE_SCAN  // uncommnet here when you need passive scan

#define CR  '\r'
#define SHORT_WAIT  0.00032
#define BUFF_LEN    4096
#define ESSID_LEN   33
#define MACADDR_LEN 6

struct apinfo {
    unsigned char essid[ESSID_LEN];
    unsigned char bssid[MACADDR_LEN];
    int power;
};

struct apinfo apinfos[MAX_AP_COUNT];
int apinfo_count;

Serial wifi(p13, p14);

DigitalOut PRST(p15);

class WiFiScanner {
private:
    int sequence;
    unsigned char buff[BUFF_LEN];
        
    void wifiPutc(int c)
    {
        wifi.putc(c);
    }

    int wifiGetc()
    {
        return wifi.getc();
    }

    int num2hex(int i)
    {
        static const char hexadecimal[] = "0123456789ABCDEF";
    
        if ( i < 0 || i > 15 )
            return '0';

        return ((int)hexadecimal[i]);
    }

    int hex2num(int i)
    {
        switch (i) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            return (i - '0');
        case 'A':
        case 'B':
        case 'C':
        case 'D':
        case 'E':
        case 'F':
            return ( i - 'A' + 10);
        case 'a':
        case 'b':
        case 'c':
        case 'd':
        case 'e':
        case 'f':
            return ( i - 'a' + 10);
        }
        return (-1);
    }

    void delayedPutc(unsigned char c)
    {
        wifiPutc(c);
        wait(SHORT_WAIT);
    }

 
    void wifiWrite(unsigned char *data)
    {
        int i;
        int len = ((int)data[3]) * 256 + data[2];

        delayedPutc('*');
        delayedPutc(num2hex((len >> 4) & 0xf));
        delayedPutc(num2hex(len & 0xf));
        delayedPutc('4');
        delayedPutc(num2hex((len >> 8) & 0xf)); 
        for ( i = 0; i < len; i++ ) {
            if ( i == 1 ) {
                delayedPutc(num2hex((sequence >> 4) & 0x0f));
                delayedPutc(num2hex(sequence & 0x0f));
            } else {
                delayedPutc(num2hex((data[i] >> 4) & 0x0f));
                delayedPutc(num2hex(data[i] & 0x0f));
            }
        }
        delayedPutc(CR);
        sequence++;
    }

    int wifiRead()
    {
        int len = 0;
        int index = 0;
        int c;
    
        while (true) {
            c = wifiGetc();
            if ( c == CR ) {
                if ( (index - 5) >= len * 2 ) {
                    break;
                }

                len = 0;
                index = 0;
                continue;
            }
            if ( index == 0 ) {
                if ( c == '*' ) {
                    index++;
                } else {
                    while (wifiGetc() != CR)
                        ;   //empty loop body
                }
                continue;
            }

            c = hex2num(c);
            if ( c < 0 ) {
                while (wifiGetc() != CR)
                    ;   // empty loop body
                len = 0;
                index = 0;
                continue;
            }
            if ( index == 1 ) {
                len = c << 4;
            } else if ( index == 2 ) {
                len |= c;
            } else if ( index == 3 ) {
                if ( c != 3 ) {
                    return -3;
                }
            } else if ( index == 4 ) {
                len |= c << 8;
            } else if ( index & 1 ) {
                buff[(index - 5)/2] = c << 4;
            } else {
                buff[(index - 5)/2] |= c;
            }
            index++;
        }
        return len;
    }

public:
    WiFiScanner()
    {
        sequence = 0;
    }
    
    void reset()
    {
        wifi.baud(BAUD_RATE);
        wifi.format(8, Serial::None, 1);
    
        sequence = 0;
        PRST = 0;       // reset BP3591
        wait(1.0);    // perhaps needs 1 sec
        PRST = 1;
    }

    void serialInit()
    {
        int i;
        int c = 0;
    
        while (true) {
            wifiPutc('A');
            if (wifi.readable()) {
               if ( c == '*' ) {
                    c = wifiGetc();
                    if ( c == CR ) {
                        break;
                    }
                } else {
                    c = wifiGetc();
                }
            }
            wait(SHORT_WAIT);  // this wait is important
        }

        while (wifi.readable())
            wifiGetc();
        for ( i = 0; i < 8; i++ ) {
            delayedPutc(0xf1);
        }
        c = 0;
        while (true) {
            if (wifi.readable()) {
                if ( c == '*' ) {
                    c = wifiGetc();
                    if ( c == CR ) {
                        break;
                    }
                } else {
                    c = wifiGetc();
                }
            }
        }
    }

    void waitStartup()
    {
        int i;
        int len = 0;
        bool loopFlag = true;
        for (i = 0; loopFlag || len <= 0 || wifi.readable(); i++) {
            len = wifiRead();
            if ( len == 8 && buff[5] == 0x00 && buff[4] == 0x3d) {
                loopFlag = false;
            }
            lcd.putc('+');
        }
    }

    void scanMode()
    {
        // WID_SSID
        unsigned char cmd0[] = { 0x57, 0x00, 0x08, 0x00, 0x00, 0x30, 0x01, 0x00 };
        wifiWrite(cmd0);
        while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
            wait(SHORT_WAIT);
        
        // WID_BSS_TYPE
        unsigned char cmd1[] = { 0x57, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00 };
        wifiWrite(cmd1);
        while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
            wait(SHORT_WAIT);
        
        // WID_BCAST_SSID
        unsigned char cmd2[] = { 0x57, 0x00, 0x08, 0x00, 0x15, 0x00, 0x01, 0x01 };
        wifiWrite(cmd2);
        while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
            wait(SHORT_WAIT);
        
        // WID_SCAN_TYPE
#ifdef  PASSIVE_SCAN
        unsigned char cmd3[] = { 0x57, 0x00, 0x08, 0x00, 0x07, 0x00, 0x01, 0x00 };
#else
        unsigned char cmd3[] = { 0x57, 0x00, 0x08, 0x00, 0x07, 0x00, 0x01, 0x01 };
#endif
        wifiWrite(cmd3);
        while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
            wait(SHORT_WAIT);

        // WID_ENABLE_CHANNEL
        unsigned char cmd4[] = { 0x57, 0x02, 0x0b, 0x00, 0x24, 0x20, 0x04, 0xff, 0x1f, 0x00, 0x00 };
        wifiWrite(cmd4);
        while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
            wait(SHORT_WAIT);

        // WID_SITE_SURVEY
#ifdef  MULTI_CHANNEL
        unsigned char cmd5[] = { 0x57, 0x01, 0x08, 0x00, 0x0e, 0x00, 0x01, 0x11 };
#else
        unsigned char cmd5[] = { 0x57, 0x01, 0x08, 0x00, 0x0e, 0x00, 0x01, 0x01 };
#endif
        wifiWrite(cmd5);
        while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
            wait(SHORT_WAIT);
        
        // WID_SCAN_FILTER
#ifdef  MULTI_CHANNEL
        unsigned char cmd6[] = { 0x57, 0x02, 0x08, 0x00, 0x36, 0x00, 0x01, 0x00 };
#else
        unsigned char cmd6[] = { 0x57, 0x02, 0x08, 0x00, 0x36, 0x00, 0x01, 0x00 };
#endif
        wifiWrite(cmd6);
        while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
            wait(SHORT_WAIT);

#ifdef  PASSIVE_SCAN
        // WID_SITE_SURVEY_SCAN_TIME
        unsigned char cmd7[] = { 0x57, 0x00, 0x09, 0x00, 0x0e, 0x10, 0x02, 0x00, 0x02 };
        wifiWrite(cmd7);
        while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
            wait(SHORT_WAIT);
#endif
    }

    void doScan()
    {
        int i, len, channel;
        int count, write_index;
    
        apinfo_count = 0;
        for (channel = 0; channel < TOTAL_CHANNELS; channel++ ) {
            myled1 = (channel >> 3) & 1;
            myled2 = (channel >> 2) & 1;
            myled3 = (channel >> 1) & 1;
            myled4 = channel & 1;
        
            // WID_CURRENT_CHANNEL
#ifdef  MULTI_CHANNEL
            unsigned char cmd8[] = { 0x57, 0x02, 0x08, 0x00, 0x02, 0x00, 0x01, 0x10 };
            cmd8[7] = channel + 1; // 1 origin
            wifiWrite(cmd8);
            while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
                wait(SHORT_WAIT);
#endif
            // WID_START_SCAN_REQ
            unsigned char cmd9[] = { 0x57, 0x02, 0x08, 0x00, 0x1e, 0x00, 0x01, 0x01 };
            wifiWrite(cmd9);
            while ( wifiRead() <= 0 || (buff[5] != 0x00 || buff[4] != 0x05 || buff[7] != 1))
                wait(SHORT_WAIT);

#ifdef  PASSIVE_SCAN
            wait(0.5);
#else
            wait(0.02);
#endif
    
            // WID_SITE_SURVER_RESULTS
            unsigned char cmd10[] = { 0x51, 0x03, 0x06, 0x00, 0x12, 0x30 };
            wifiWrite(cmd10);
            while ( (len = wifiRead()) <= 0 || (buff[5] != 0x30 || buff[4] != 0x12))
                wait(SHORT_WAIT);
            if ( len < 10 ) {
                continue;
            }
            count = (buff[7] - 2) / 44;
            for ( i = 0; i < count; i++ ) {
                for ( write_index = 0; write_index < apinfo_count; write_index++) {
                    if ( memcmp(apinfos[write_index].essid, buff + (9 + i *44), 33) == 0 &&
                         memcmp(apinfos[write_index].bssid, buff + (9 + i * 44 + 36), 6) == 0 ) {
                        break;  // already recorded
                    }
                }
                if ( write_index == apinfo_count ) {
                    memcpy(apinfos[write_index].essid, buff + (9 + i * 44), 33);
                    memcpy(apinfos[write_index].bssid, buff + (9 + i * 44 + 36), 6);
                    apinfos[write_index].power = (signed char)buff[9 + i * 44 + 42];
                    apinfo_count++;
                } else if ( apinfos[write_index].power < (signed char)buff[9 + i * 44 + 42] ) {
                    apinfos[write_index].power = (signed char)buff[9 + i * 44 + 42];
                }
            }
        }
    }
};