How to not looping through all the networks available for RSSI

This is a progress on RSSI scanner where @zach_l first mentioned in this topic in combination with Seetron GLO-216 screen in which I mentioned in this topic. By altering a default setting in wlan_ioctl_set_scan_params call we are able to get much faster refresh rate which is now at minimum of 1 second.

Which we ended up use something looks like this long errParams = wlan_ioctl_set_scan_params(1000,20,30,2,0x7ff,-80,0,205,aiIntervalList[16]); the fastest possible refresh rate and

However, with our following code, we are able to only looping through all available networks, one by one in each second. While we only want to check only RSSI of the current wifi network the core is on, ideally once every second. Now it would takes somewhere around 10-30 secs (or longer, depends on the number of wifi networks available in the environment) to loop back to its connected network. There is also this strange behavior while the core loop through all the networks but does not find the network it is currently on.

//------------------------------------------

// GLO-216G serial OLED display
// Natalia Fargasch Norman @ theelectronicshobbyist.com/blog

// GLO-216Y/G information: http://www.seetron.com/glo216.html
// Programming reference: http://seetron.com/glo216/glo216prog.html

/*
Parameters for setPosition and rightAlign instructions:
setPosition: position + 0x40
rightAlign: '0'-'7'
*/

/*
Parameter for escape instructions:
Define lower custom character: 'D', '0'-'7'
Define upper custom character: 'd', '0'-'7'
Recall saved text: 'E', '0'
Restore custom character set: 'e', '0'
Save text since last clearScreen: 'X', '0'
Store custom character set: 'x', '0'
*/

// Moves printing position to the first character of top line
char homeCursor() {  return 0x01;}
// Cycles the font size: normal -> tall -> wide -> big -> normal -> ...
char selectSize() {  return 0x02;}
// Sets font size to default of small on two lines of 16 characters
char defaultSize() {  return 0x03;}
// Behaves like the backspace key
char backspace() {  return 0x08;}
// Moves printing position to the next multiple of 4 location
char tab() {  return 0x09;}
// Moves the printing position down a line
char linefeed() {  return 0x0A;}
// Moves the printing position up a line
char verticalTab() {  return 0x0B;}
// Clears the screen and moves printing position to 0
char clearScreen() {  return 0x0C;}
// Moves to the first printing position of the next line
char carriageReturn() {  return 0x0D;}
// Turns on the OLED driver circuitry when it has been previously turned off
char turnOn() {  return 0x0E;}
// Turns off the OLED driver circuitry to save power
char turnOff() {  return 0x0F;}
// Sets the printing position according to value of next byte
char setPosition() {  return 0x10;}
// Prints text at the righthand end of a field of defined size from 2-8
char rightAlign() {  return 0x12;}
// Sets seven segment style font for large characters
char sevenSeg() {  return 0x13;}
// Sets text style font for large characters
char textStyle() {  return 0x14;}
// Begin multi-part instruction
char escape() {  return 0x1B;}
// See http://seetron.com/glo216/bpigloupgg.html
char bpkInstr() {  return 0xFE;}

//------------------------------------------
//character formats

      char instr[] = {
        clearScreen(),
        defaultSize(),
        selectSize(), // tall
        selectSize(), // wide
        selectSize(), // big
        textStyle(),
        NULL
      };

      // defines a new custom wifi shaped character
      char instr1[] = {
        // escape sequence to receive new custom character
        clearScreen(),
        defaultSize(),
        selectSize(), // tall
        selectSize(), // wide
        selectSize(), // big
        escape(), 'D', '0',
        // pattern tool at http://seetron.com/apps/app_cceditor.html
        0x80, 0x8E, 0x91, 0x84, 0x8A, 0x80, 0x84, 0x80,
        
        textStyle(),
        NULL
      };

      char instr2[] = {
        defaultSize(),
        textStyle(),
        NULL
      };


//------------------------------------------

int y = 1;
int incomingByte = 0;
unsigned char ucResults[64];
UINT32* aiIntervalList[16];


int ledPin1 = D0;
int ledPin2 = D1;
int ledPin3 = D2;


tNetappIpconfigRetArgs ipconfig;

void setup() {

    Serial.begin(115200);
    Serial.println("press 'a' to read Network data\n");

    Serial1.begin(9600);

    pinMode(ledPin1,OUTPUT);
    pinMode(ledPin2,OUTPUT);
    pinMode(ledPin3,OUTPUT);

    digitalWrite(ledPin1,HIGH);
    digitalWrite(ledPin2,HIGH);
    digitalWrite(ledPin3,HIGH);

    Serial1.print(instr);
    const char msg[] = "YESYESNO";
    Serial1.print(msg);

    delay(1000);

    digitalWrite(ledPin1,LOW);
    digitalWrite(ledPin2,LOW);
    digitalWrite(ledPin3,LOW);


}

void loop() {

    netapp_ipconfig(&ipconfig);
    char connectedSSID[32];
    sprintf(connectedSSID, "%s", ipconfig.uaSSID);

    digitalWrite(ledPin1,HIGH);
    delay(50);
    digitalWrite(ledPin1,LOW);
    delay(50);

    // should be done once prob...
    long errParams = wlan_ioctl_set_scan_params(1000,20,30,2,0x7ff,-80,0,205,aiIntervalList[16]);

    long errResults = wlan_ioctl_get_scan_results(0, ucResults);
    int _numEntry = ((uint8_t) ucResults[3] << 24) | ((uint8_t) ucResults[2] << 16) | ((uint8_t) ucResults[1] << 8) | ((uint8_t) ucResults[0]);

    if (errParams == 0 && errResults == 0 && _numEntry > 0) {


        Serial.println("num entry");
        Serial.println( _numEntry);


        digitalWrite(ledPin2,HIGH);
        delay(50);
        digitalWrite(ledPin2,LOW);

        int _stat = ((uint8_t) ucResults[7] << 24) | ((uint8_t) ucResults[6] << 16) | ((uint8_t) ucResults[5] << 8) | ((uint8_t) ucResults[4]);
        bool _valid = (uint8_t) ucResults[8]  & 0x1;
        int _rssi = (uint8_t) ucResults[8] >> 1;
        int _mode = ((uint8_t) ucResults[9] | 0xC0) & 0x3;
        int _ssidlen = (uint8_t) ucResults[9] >> 2;

        char ssid[32];
        memset(ssid, 0, 32);
        int idx = 0;
        while(idx < _ssidlen) {
            ssid[idx] = ucResults[idx+12];
            idx++;
        }
        ssid[_ssidlen] = (char) NULL;

        // while(strcmp(connectedSSID, ssid) != 0) {
        //     ssid[idx] = ucResults[idx+12];
        //     idx++;
        // }
        // ssid[_ssidlen] = (char) NULL;



        if (strcmp(connectedSSID, ssid) == 0){

            digitalWrite(ledPin3,HIGH);
            delay(100);
            digitalWrite(ledPin3,LOW);


            Serial.print("WiFi scan status: ");
            switch (_stat) {
                case 0:
                    Serial.print("aged, ");
                    break;
                case 1:
                    Serial.print("valid, ");
                    break;
                case 2:
                    Serial.print("no results, ");
                    break;
            }

            Serial.print(_numEntry);
            Serial.print(" nets found. ");
            Serial.print(ssid);

            if (_valid)
                Serial.print(" is valid, RSSI: ");
            else
                Serial.print("not valid, RSSI: ");

            Serial.print(_rssi);

          // print character 0x80, the newly defined heart
          const char msg1[] = { 0x80, NULL};
          Serial1.print(instr1);
          Serial1.print(msg1);


          const char msg2[] = " RSSI ";
          Serial1.print(instr2);
          Serial1.print(msg2);
      


            if (_rssi >= 90){ 
                const char msg3[] = {0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F};
                Serial1.print(msg3);
            }
            else if(90 > _rssi && _rssi >= 80){ 
                const char msg3[] = {0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x20};
                Serial1.print(msg3);
            }
            else if(80 > _rssi && _rssi >= 70){ 
                const char msg3[] = {0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x20,0x20};
                Serial1.print(msg3);
            }
            else if(70 > _rssi && _rssi >= 60){ 
                const char msg3[] = {0x88,0x89,0x8A,0x8B,0x8C,0x20,0x20,0x20};
                Serial1.print(msg3);
            }
            else if(60 > _rssi && _rssi >= 50){ 
                const char msg3[] = {0x88,0x89,0x8A,0x8B,0x20,0x20,0x20,0x20};
                Serial1.print(msg3);
            }
            else if(50 > _rssi && _rssi >= 40){ 
                const char msg3[] = {0x88,0x89,0x8A,0x20,0x20,0x20,0x20,0x20};
                Serial1.print(msg3);
            }
            else if(40 > _rssi && _rssi >= 30){ 
                const char msg3[] = {0x88,0x89,0x20,0x20,0x20,0x20,0x20,0x20};
                Serial1.print(msg3);
            }
            else if(30 > _rssi && _rssi >= 20){ 
                const char msg3[] = {0x88,0x20,0x20,0x20,0x20,0x20,0x20,0x20};
                Serial1.print(msg3);
            }
            else { 
                const char msg3[] = {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20};
                Serial1.print(msg3);
            }

            Serial1.print(ssid);
            Serial1.print(" : ");
            Serial1.print(_rssi);
            

            Serial.print(", mode: ");
            switch (_mode) {
                case 0:
                    Serial.println("OPEN");
                    break;
                case 1:
                    Serial.println("WEP");
                    break;
                case 2:
                    Serial.println("WPA");
                    break;
                case 3:
                    Serial.println("WPA2");
                    break;
            }

        }

        else {
            Serial.print(connectedSSID);
            Serial.print(" >______< ");
            Serial.println(ssid);
        }

        incomingByte = Serial.read();
        //key press 'a' to get data
        if (incomingByte == 97){
            Serial.println(Network.localIP());
            Serial.println(Network.subnetMask());
            Serial.println(Network.gatewayIP());
            Serial.println(Network.SSID());
        }


    }
    else{
        Serial.println("oops,,,");
    }

}

Sorry for did not clean up the Seetron part out of the code (guess it could be helpful for someone though!), and there is also these LED I put in just to see which part of the loop the core are going through (which indeed slow things down a bit, but it looks really cute.) Anyway, the serial print out should work just fine without either the screen and the LEDs.

Any suggestion? Thanks!

some picture of how the prototype casing looks like

also, we've read that calling this function often might kill the eeprom?

If it still not fixed in the upcoming patch, there is a workaround you can employ. It involves rebooting your CC3000 module every few seconds and installing hardware to protect your EEPROM, since frequent calls to wlan_ioctl_set_scan_params(...) will exhaust it in a matter of days.

this is something to definitely move out of the loop function @firmread

@zach_l, you are correct, this is not a call you should make in loop(). The information you found is very interesting and needs to be considered since that same call can be used to change the highest channel the CC3000 scans to and for Europe, that is up to channel 13. Making this call with 0x1FFF instead of 0x07FF is what allows that.

However, the part about exhausting the EEPROM is important since we were considering making this call in WiFi.on() to allow European routers set on channels higher than 11 to connect by default. Now, we may need to reconsider this. Good catch! :smile:

@zachary, @AndyW, will need to know about this.

@peekay123 I wonder if there’s a way to read the params, check if they need to be changed, then change them if need be? (I guess this would allow you to make a one time change, right?)

I’m 99% sure we bricked a spark by letting this code @firmread posted run overnight… Just a warning!

@zach_l, good question. From what I can see in the firmware source code, those settings are not configured and use the CC3000 defaults. I have flagged this topic to @zachary, the Spark CTO for him to comment.

This is a problem I’m very much interested in solving. I’m working on a project that needs to determine the RSSI of the wifi network that the spark core is connected to. I also need to do this in as close to realtime as possible. Has there been any comment from @zachary about this issue?

So the problem in the above code is that it calls wlan_ioctrl_set_scan_params() in a loop which uses up all the writes to control memory on the TI CC3000. It doesn’t have to do it that way–a better way is have a sketch that you run once that just sets the faster scan rate on the TI part and stops. You can then read the RSSI at a faster rate. The function to read the RSSI is now in the WifI class in the Spark firmware.

That said, I think you might be in for some disappointment if you are counting on the RSSI being very accurate. A pair of my cores side-by-side will have RSSI numbers for the same router that are 5-10 dB different. Putting your hand in front of the antenna can cause a 5-10 dB drop too. If you are trying to do distance measurements based on RSSI, you should understand that the accuracy will be quite low and quite variable.

1 Like

Ah, good to know. Ok, so I’ll put that statement in the setup() function to avoid exhausting the EEPROM. But the behavior is to still scan all available networks before returning the RSSI of the connected network? Is there a way to prevent that from happening, or is that the only way the CC3000 works? I took a quick look at spark_wiring_wifi.cpp. I found the WiFi.RSSI() function. Not sure what to do with it yet, but maybe the answer is here?:

    int8_t WiFiClass::RSSI()
{
        _functionStart = millis();
        _returnValue = 0;
        while ((millis() - _functionStart) < 1000)
        {
                _loopCount = 0;
                while (_loopCount++ < 16)
                {
                        unsigned char wlan_scan_results_table[50];
                        char wlan_scan_results_ssid[32];
                        if(wlan_ioctl_get_scan_results(0, wlan_scan_results_table) != 0) return(1);
                        for (int i = 12; i <= 43; i++)
                        {
                                int arrayPos = i - 12;
                                wlan_scan_results_ssid[arrayPos] = wlan_scan_results_table[i];
                        }
                        if (*wlan_scan_results_ssid == *ip_config.uaSSID) _returnValue = ((wlan_scan_results_table[8] >> 1) - 127);
                        if (wlan_scan_results_table[0] == 0) break;
                }
                if (_returnValue != 0) return(_returnValue);
        }
        return(2);
}

The TI part returns the scan results table and you need to search it for the SSID that matches your current SSID if you want the RSSI for the current connection. That is what this code is doing.

Hi-- Thanks very much for clearing this up!

Hello,

Have you had any luck increasing the resolution of the RSSI reporting? I am currently working on the same, with the intention to move to the P2P uses, and measure many connections. Any help is greatly apprecieated.

Apologies, I don’t fully understand the answer about the WiFI.RSSI() function above and the Firmware documentation does not appear to show a return of anything other than an integer.

If I want to scan available wifi networks and then allow the local user to enter a security code and run wifi.credentials() to connect to the selected network, how can I first get a list of available networks?

Could someone help with a sample? Thanks

Sorry to revive this ancient thread, but wouldn't it be simpler to write:
wlan_scan_results_ssid[i - 12] = wlan_scan_results_table[i];
...removing the int arrayPos = i - 12;?
Seems to me that it wouldn't involve the stack as much--but please do note that I'm not very experienced with C. Elites know best... :wink:

We are discussing adding WiFi.scan() over here