CC3000 test App

Dependencies:   CC3000HostDriver mbed

CC3000TestApp.cpp

Committer:
dflet
Date:
2013-09-14
Revision:
2:17c37c0b0534
Parent:
0:305844973572

File content as of revision 2:17c37c0b0534:

/**************************************************************************
*
*  CC3000TestApp.cpp - Basic connection test between the TI CC3000
*                          and an Mbed.
*
*  Mbed Version 1.0
* 
*  Copyright (C) 2013 
*
*  Note: Some or all of this software has been modified in some way to meet the 
*  requirements of the mbed libs and/or compiler. If you need a fresh copy of the TI
*  software please check TI's website.
*  If you need help please take the time to read Chris's notes below. 
* ( Yes I know they are for an Arduino, but some still do apply.) 
*  Most important!
*  The mbed will not supply the current that the CC3000 requires, if you try it will 
*  show up as the mbed resetting as soon as spi runs.
*
*  To associate with your WIFI router you will first need to insert your ssid and key into
*  functions, ManualConnect() and ManualAddProfile()
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*  Don't sue me if this code blows up your board and burns down your house and incinerates 
*  all life and property in this and any other universe!
****************************************************************************\

To connect an mbed to the CC3000 you'll need to make these 6 connections
(in addition to the WiFi antenna, power etc).

Name /          pin on CC3000EM board / purpose

cs             /  J4-8    SPI Chip Select
                          The Mbed will set this pin LOW when it wants to 
                          exchange data with the CC3000. This is
                          mbed pin 8, but any pin can be used. In this
                          program it will be called cs.
                          This is the mbed's pin 8.

MISO           /  J4-9    Data from the module to the mbed
                          This is mbed's MISO pin, and is how the CC3000
                          will get bytes to the mbed.
                          This is the mbed's pin 6. 

WLAN_IRQ       /  J4-10   CC3000 host notify
                          The CC3000 will drive this pin LOW to let the mbed
                          know it's ready to send data. In
                          this program it will be called WLAN_IRQ
                          This is the mbed's pin 9.
                          
MOSI           /  J4-11   Data from the Arduino to the CC3000
                          This is the Arduino's MOSI pin, and is how the Arduino
                          will get bytes to the CC3000. 
                          This is the mbed's pin 5.
                          
SCK            /  J4-12   SPI clock
                          This is the mbed's SCK pin 7. 

WLAN_EN        /  J5-5    Module enable
                          The Arduino will set this pin HIGH to turn the CC3000
                          on. Any pin can be used. In this program it will be
                          called WLAN_EN
                          This is the mbed's pin 10.
***************************************************************************/    

/**************************************************************************
*
*  ArduinoCC3000Test.ino - Basic connection test between the TI CC3000
*                          and an Arduino.
*
*  Version 1.0
* 
*  Copyright (C) 2013 Chris Magagna - cmagagna@yahoo.com
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*  Don't sue me if my code blows up your board and burns down your house
*
****************************************************************************



To connect an Arduino to the CC3000 you'll need to make these 6 connections
(in addition to the WiFi antenna, power etc).

Name / pin on CC3000 module / pin on CC3000EM board / purpose

SPI_CS     / 12 / J4-8 /  SPI Chip Select
                          The Arduino will set this pin LOW when it wants to 
                          exchange data with the CC3000. By convention this is
                          Arduino pin 10, but any pin can be used. In this
                          program it will be called WLAN_CS

SPI_DOUT   / 13 / J4-9 /  Data from the module to the Arduino
                          This is Arduino's MISO pin, and is how the CC3000
                          will get bytes to the Arduino. For most Arduinos
                          MISO is pin 12

SPI_IRQ    / 14 / J4-10 / CC3000 host notify
                          The CC3000 will drive this pin LOW to let the Arduino
                          know it's ready to send data. For a regular Arduino
                          (Uno, Nano, Leonardo) this will have to be connected
                          to pin 2 or 3 so you can use attachInterrupt(). In
                          this program it will be called WLAN_IRQ

SPI_DIN    / 15 / J4-11   Data from the Arduino to the CC3000
                          This is the Arduino's MOSI pin, and is how the Arduino
                          will get bytes to the CC3000. For most Arduinos
                          MOSI is pin 11

SPI_CLK    / 17 / J4-12   SPI clock
                          This is the Arduino's SCK pin. For most Arduinos
                          SCK is pin 13

VBAT_SW_EN / 26 / J5-5    Module enable
                          The Arduino will set this pin HIGH to turn the CC3000
                          on. Any pin can be used. In this program it will be
                          called WLAN_EN
                          
                          
WARNING #1: The CC3000 runs at 3.6V maximum so you can't run it from your
regular 5V Arduino power pin. Run it from 3.3V!


WARNING #2: When transmitting the CC3000 will use up to 275mA current. Most
Arduinos' 3.3V pins can only supply up to 50mA current, so you'll need a 
separate power supply for it (or a voltage regulator like the LD1117V33
connected to your Arduino's 5V power pin).


WARNING #3: The CC3000's IO pins are not 5V tolerant. If you're using a 5V
Arduino you will need a level shifter to convert these signals to 3.3V
so you don't blow up the module. 

You'll need to shift the pins for WLAN_CS, MOSI, SCK, and WLAN_EN. The other
2 pins (WLAN_IRQ and MISO) can be connected directly because they're input
pins for the Arduino, and the Arduino can read 3.3V signals directly.

You can use a level shifter chip like the 74LVC245 or TXB0104 or you can use
a pair of resistors to make a voltage divider like this:

Arduino pin -----> 560 Ohm -----> 1K Ohm -----> GND
                             |
                             |
                             +---> CC3000 pin


****************************************************************************/



#include "wlan.h" 
#include "evnt_handler.h"    // callback function declaration
#include "nvmem.h"
#include "socket.h"
#include "netapp.h"
#include "host_driver_version.h"
#include "cc3000.h"
//#include "common.h"
//#include "demo_config.h"
//#include "HttpString.h"
#include "spi.h"
#include "CC3000TestApp.h"
#include "CC3000Core.h"
//#include <msp430.h>
#include "mbed.h"
//#include "Board.h"
//#include "HttpCore.h"
//#include "Wheel.h"
//#include "dispatcher.h"
#include "DigitalClass.h"

#define FALSE 0
int8_t isInitialized = false;
InterruptIn intr(p9);

DigitalOut ind1(LED1);
DigitalOut ind2(LED2);
DigitalOut ind3(LED3);
DigitalOut ind4(LED4);

Serial usb(USBTX, USBRX);

void IntSpi()
{
    
    IntSpiGPIOHandler();// spi.cpp
    
}

int main()
{

intr.fall(&IntSpi);
usb.baud(115200);

// Start CC3000 State Machine
    resetCC3000StateMachine();
    
    
char cmd;


while (1) {
    printf("\r\n");
    printf("+-------------------------------------------+\r\n");
    printf("|      Mbed CC3000 Demo Program             |\r\n");
    printf("+-------------------------------------------+\r\n");
    printf("\r\n");
    printf("  1 - Initialize the CC3000\r\n");
    printf("  2 - Show RX & TX buffer sizes, & free RAM\r\n");
    printf("  3 - Start Smart Config\r\n");
    printf("  4 - Manually connect to AP\r\n");
    printf("  5 - Manually add connection profile\r\n");
    printf("  6 - List access points\r\n");
    printf("  7 - Show CC3000 information\r\n");
    printf("\r\n");

    //for (;;) {
        while (1) {
            if (asyncNotificationWaiting) {
                asyncNotificationWaiting = false;
                AsyncEventPrint();
                }
     //       }
        cmd = usb.getc();
        if (cmd!='\n' && cmd!='\r') {
            break;
            }
        }


    switch(cmd) {
        case '1':       
            IntSpi();
            initDriver();
            isInitialized = true;
            break;
        case '2':
            //ShowBufferSize();

            break;
        case '3':
            StartSmartConfig();
            break;
        case '4':
            ManualConnect();
            break;
        case '5':
            ManualAddProfile();
            break;
        case '6':
            ListAccessPoints();
            break;
        case '7':
            ShowInformation();
            break;
        default:
            printf("**Unknown command ");
            printf("%d",cmd);
            printf("**\r\n");
            break;
        }
  
    };
    return 0;
}


void AsyncEventPrint()
{
    switch(lastAsyncEvent) {
            printf("CC3000 Async event: Simple config done\r\n");
            break;

        case HCI_EVNT_WLAN_UNSOL_CONNECT:
            printf("CC3000 Async event: Unsolicited connect\r\n");
            break;

        case HCI_EVNT_WLAN_UNSOL_DISCONNECT:
            printf("CC3000 Async event: Unsolicted disconnect\r\n");
            break;

        case HCI_EVNT_WLAN_UNSOL_DHCP:
            printf("CC3000 Async event: Got IP address via DHCP: ");
            printf("%d",dhcpIPAddress[0]);
            printf(".");
            printf("%d",dhcpIPAddress[1]);
            printf(".");
            printf("%d",dhcpIPAddress[2]);
            printf(".");
            printf("%d\r\n",dhcpIPAddress[3]);
            break;

        case HCI_EVENT_CC3000_CAN_SHUT_DOWN:
            printf("CC3000 Async event: OK to shut down\r\n");
            break;

        case HCI_EVNT_WLAN_KEEPALIVE:
            // Once initialized, the CC3000 will send these keepalive events
            // every 20 seconds.
            //printf(F("CC3000 Async event: Keepalive"));
            //return;
            break;

        default:
            printf("AsyncCallback called with unhandled event! ");
            printf("%x",lastAsyncEvent);
            printf("\r\n");
            break;
        }
        
    printf("\r\n");
    }
/*
    This is an example of how you'd connect the CC3000 to an AP without using
    Smart Config or a stored profile.
    
    All the code above wlan_connect() is just for this demo program; if you're
    always going to connect to your network this way you wouldn't need it.
*/

void ManualConnect() {

    char ssidName[] = "***********";
    char AP_KEY[] = "************";
    int8_t rval;

    if (!isInitialized) {
        printf("CC3000 not initialized; can't run manual connect.\r\n");
        return;
        }

    printf("Starting manual connect...\r\n");
    
    printf(("  Disabling auto-connect policy...\r\n"));
    rval = wlan_ioctl_set_connection_policy(DISABLE, DISABLE, DISABLE);

    printf("  Deleting all existing profiles...\r\n");
    rval = wlan_ioctl_del_profile(255);

    printf("  Waiting until disconnected...\r\n");
    while (ulCC3000Connected == 1) {
        wait_ms(100);
        }
    
    printf("  Manually connecting...\r\n");

    // Parameter 1 is the security type: WLAN_SEC_UNSEC, WLAN_SEC_WEP,
    //              WLAN_SEC_WPA or WLAN_SEC_WPA2
    // Parameter 3 is the MAC adddress of the AP. All the TI examples
    //              use NULL. I suppose you would want to specify this
    //              if you were security paranoid.
    rval = wlan_connect(WLAN_SEC_WPA2,
                ssidName,
                strlen(ssidName),
                NULL,
                (unsigned char *)AP_KEY,
                strlen(AP_KEY));

    if (rval==0) {
        printf("  Manual connect success.\r\n");
        }
    else {
        printf("  Unusual return value: ");
        printf("%d\r\n",rval);
        }
        return;
    }
/*
    This is an example of manually adding a WLAN profile to the CC3000. See
    wlan_ioctl_set_connection_policy() for more details of how profiles are
    used but basically there's 7 slots where you can store AP info and if
    the connection policy is set to auto_start then the CC3000 will go
    through its profile table and try to auto-connect to something it knows
    about after it boots up.
    
    Note the API documentation for wlan_add_profile is wrong. It says it
    returns 0 on success and -1 on failure. What it really returns is
    the stored profile number (0-6, since the CC3000 can store 7) or
    255 on failure.
    
    Unfortunately the API doesn't give you any way to see how many profiles
    are in use or which profile is stored in which slot, so if you want to
    manage multiple profiles you'll need to do that yourself.
*/

void ManualAddProfile() {
    char ssidName[] = "*****************";
    char AP_KEY[] = "***********";

    if (!isInitialized) {
        printf("CC3000 not initialized; can't run manual add profile.\r\n");
        return;
        }

    printf("Starting manual add profile...\r\n");

    printf("  Disabling auto connection...\r\n");
    wlan_ioctl_set_connection_policy(DISABLE, DISABLE, DISABLE);

    printf("  Adding profile...\r\n");
    int8_t rval = wlan_add_profile  (
                    WLAN_SEC_WPA2,      // WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
                    (unsigned char *)ssidName,
                    strlen(ssidName),
                    NULL,               // BSSID, TI always uses NULL
                    0,                  // profile priority
                    0x18,               // key length for WEP security, undocumented why this needs to be 0x18
                    0x1e,               // key index, undocumented why this needs to be 0x1e
                    0x2,                // key management, undocumented why this needs to be 2
                    (unsigned char *)AP_KEY,    // WPA security key
                    strlen(AP_KEY)      // WPA security key length
                    );

    if (rval!=255) {

        // This code is lifted from http://e2e.ti.com/support/low_power_rf/f/851/p/180859/672551.aspx;
        // the actual API documentation on wlan_add_profile doesn't specify any of this....

        printf("  Manual add profile success, stored in profile: ");
        printf("%d\r\n",rval);

        printf("  Enabling auto connection...\r\n");
        wlan_ioctl_set_connection_policy(DISABLE, DISABLE, ENABLE);

        printf("  Stopping CC3000...\r\n");
        wlan_stop();

        printf("  Stopping for 5 seconds...\r\n");
        wait_ms(5000);

        printf("  Restarting CC3000...\r\n");
        wlan_start(0);
        
        printf("  Manual add profile done!\r\n");

        }
    else {
        printf("  Manual add profile failured (all profiles full?).\r\n");
        }
        return; 
    }
    

    
/*
    All the data in all the fields from netapp_ipconfig() are reversed,
    e.g. an IP address is read via bytes 3,2,1,0 instead of bytes
    0,1,2,3 and the MAC address is read via bytes 5,4,3,2,1,0 instead
    of 0,1,2,3,4,5.
    
    N.B. TI is inconsistent here; nvmem_get_mac_address() returns them in
    the right order etc.
*/

void ShowInformation() {

    tNetappIpconfigRetArgs inf;
    char localB[33];

    if (!isInitialized) {
        printf("CC3000 not initialized; can't get information.\r\n");
        return;
        }
        
    printf("CC3000 information:");
    
    netapp_ipconfig(&inf);
    
    printf("  IP address: ");
    PrintIPBytes(inf.aucIP);
    
    printf("  Subnet mask: ");
    PrintIPBytes(inf.aucSubnetMask);
    
    printf("  Gateway: ");
    PrintIPBytes(inf.aucDefaultGateway);
    
    printf("  DHCP server: ");
    PrintIPBytes(inf.aucDHCPServer);
    
    printf("  DNS server: ");
    PrintIPBytes(inf.aucDNSServer);
    
    printf("  MAC address: ");
    for (int i=(MAC_ADDR_LEN-1); i>=0; i--) {
        if (i!=(MAC_ADDR_LEN-1)) {
            printf(":");
            }
        printf("%x",inf.uaMacAddr[i]);
        }
    printf("\r\n");
    
    memset(localB, 0, 32);
    memcpy(localB, inf.uaSSID, 32);

    printf("  Connected to SSID: ");
    printf("%s",localB);

    } 
    
void PrintIPBytes(unsigned char *ipBytes) {

    printf("%d",ipBytes[3]);
    printf(".");
    printf("%d",ipBytes[2]);
    printf(".");
    printf("%d",ipBytes[1]);
    printf(".");
    printf("%d\r\n",ipBytes[0]);
    }  
    
/*
    The call wlan_ioctl_get_scan_results returns this structure. I couldn't
    find it in the TI library so it's defined here. It's 50 bytes with
    a semi weird arrangement but fortunately it's not as bad as it looks.
    
    numNetworksFound - 4 bytes - On the first call to wlan_ioctl_get_scan_results
                    this will be set to how many APs the CC3000 sees. Although
                    with 4 bytes the CC3000 could see 4 billion APs in my testing
                    this number was always 20 or less so there's probably an
                    internal memory limit.
    
    results - 4 bytes - 0=aged results, 1=results valid, 2=no results. Why TI
                    used 32 bits to store something that could be done in 2,
                    and how this field is different than isValid below, is
                    a mystery to me so I just igore this field completely.
                    
    isValid & rssi - 1 byte - a packed structure. The top bit (isValid)
                    indicates whether or not this structure has valid data,
                    the bottom 7 bits (rssi) are the signal strength of this AP.
                    
    securityMode & ssidLength - 1 byte - another packed structure. The top 2
                    bits (securityMode) show how the AP is configured:
                        0 - open / no security
                        1 - WEP
                        2 - WPA
                        3 - WPA2
                    ssidLength is the lower 6 bytes and shows how many characters
                    (up to 32) of the ssid_name field are valid
                    
    frameTime - 2 bytes - how long, in seconds, since the CC3000 saw this AP
                    beacon
                    
    ssid_name - 32 bytes - The ssid name for this AP. Note that this isn't a
                    regular null-terminated C string so you can't use it
                    directly with a strcpy() or printf() etc. and you'll
                    need a 33-byte string to store it (32 valid characters +
                    null terminator)
                    
    bssid - 6 bytes - the MAC address of this AP
*/
    
typedef struct scanResults {
    unsigned long numNetworksFound;
    unsigned long results;
    unsigned isValid:1;
    unsigned rssi:7;
    unsigned securityMode:2;
    unsigned ssidLength:6;
    unsigned short frameTime;
    unsigned char ssid_name[32];
    unsigned char bssid[6];
    } scanResults;

#define NUM_CHANNELS    16

void ListAccessPoints() {
    unsigned long aiIntervalList[NUM_CHANNELS];
    int8_t rval;
    scanResults sr;
    int apCounter;
    char localB[33];
    
    if (!isInitialized) {
        printf(("CC3000 not initialized; can't list access points.\r\n"));
        return;
        }
        
    printf(("List visible access points\r\n"));
    
    printf(("  Setting scan paramters...\r\n"));
    
    for (int i=0; i<NUM_CHANNELS; i++) {
        aiIntervalList[i] = 2000;
        }
    
    rval = wlan_ioctl_set_scan_params(
            1000,   // enable start application scan
            100,    // minimum dwell time on each channel
            100,    // maximum dwell time on each channel
            5,      // number of probe requests
            0x7ff,  // channel mask
            -80,    // RSSI threshold
            0,      // SNR threshold
            205,    // probe TX power
            aiIntervalList  // table of scan intervals per channel
            );
    if (rval!=0) {
        printf("  Got back unusual result from wlan_ioctl_set_scan_params, can't continue: ");
        printf("%d\r\n",rval);
        return;
        }
        
    printf("  Sleeping 5 seconds to let the CC3000 discover APs...");
    wait_ms(5000);
    
    printf("  Getting AP count...\r\n");
    
    // On the first call to get_scan_results, sr.numNetworksFound will return the
    // actual # of APs currently seen. Get that # then loop through and print
    // out what's found.
    
    if ((rval=wlan_ioctl_get_scan_results(2000, (unsigned char *)&sr))!=0) {
        printf("  Got back unusual result from wlan_ioctl_get scan results, can't continue: ");
        printf("%d\r\n",rval);
        return;
        }
        
    apCounter = sr.numNetworksFound;
    printf(("  Number of APs found: "));
    printf("%d\r\n",apCounter);
    
    do {
        if (sr.isValid) {
            printf(("    "));
            switch(sr.securityMode) {
                case WLAN_SEC_UNSEC:    // 0
                    printf(("OPEN "));
                    break;
                case WLAN_SEC_WEP:      // 1
                    printf(("WEP  "));
                    break;
                case WLAN_SEC_WPA:      // 2
                    printf(("WPA  "));
                    break;
                case WLAN_SEC_WPA2:     // 3
                    printf(("WPA2 "));
                    break;
                    }
            sprintf(localB, "%3d  ", sr.rssi);
            printf(localB);
            memset(localB, 0, 33);
            memcpy(localB, sr.ssid_name, sr.ssidLength);
            printf(localB);
            }
            
        if (--apCounter>0) {
            if ((rval=wlan_ioctl_get_scan_results(2000, (unsigned char *)&sr))!=0) {
                printf(("  Got back unusual result from wlan_ioctl_get scan results, can't continue: "));
                printf("%d\r\n",rval);
                return;
                }
            }
        } while (apCounter>0);
        
    printf(("  Access Point list finished."));
    }  
    

//*****************************************************************************
//
//!  turnLedOn
//!
//! @param  ledNum is the LED Number
//!
//! @return none
//!
//! @brief  Turns a specific LED on
//
//*****************************************************************************
void turnLedOn(char ledNum)
{
    switch(ledNum)
        {
          case 1:
              ind1 = 1;
            break;
          case 2:
              ind2 = 1;
            break;
          case 3:
              ind3 = 1;
            break;
          case 4:
              ind4 = 1;
            break;
          case 5:
              ind1 = 1;
            break;
          case 6:
              ind4 = 1;
            break;
          case 7:
              
            break;
          case 8:
              
            break;
        }

}

//*****************************************************************************
//
//! turnLedOff
//!
//! @param  ledNum is the LED Number
//!
//! @return none
//!
//! @brief  Turns a specific LED Off
//
//*****************************************************************************    
void turnLedOff(char ledNum)
{              
    switch(ledNum)
        {
          case 1:
             ind1 = 0; 
            break;
          case 2:
              ind2 = 0; 
            break;
          case 3:
              ind3 = 0; 
            break;
          case 4:
              ind4 = 0; 
            break;
          case 5:
              ind1 = 0; 
            break;
          case 6:
              ind4 = 0; 
            break;
          case 7:
              
            break;
          case 8:
              
            break;
        }  
}

//*****************************************************************************
//
//! toggleLed
//!
//! @param  ledNum is the LED Number
//!
//! @return none
//!
//! @brief  Toggles a board LED
//
//*****************************************************************************    

void toggleLed(char ledNum)
{
    switch(ledNum)
        {
          case 1:
              ind1 = 0;
            break;
          case 2:
              ind2 = 0;
            break;
          case 3:
              ind3 = 0;
            break;
          case 4:
              ind4 = 0;
            break;
          case 5:
              ind1 = 0;
            break;
          case 6:
              ind4 = 0;
            break;
          case 7:
              
            break;
          case 8:
              
            break;
        }

}