Cheerlights client using WiFiDIPCortex and WS2801 RGB LED strip

Dependencies:   Adafruit_WS2801 HTTPClient cc3000_hostdriver_mbedsocket mbed

main.cpp

Committer:
SomeRandomBloke
Date:
2014-02-11
Revision:
0:98d83f5b309f
Child:
1:40027344b249

File content as of revision 0:98d83f5b309f:

/** WiFiDIPCortex Cheerlights
 *
 * @author Andrew Lindsay
 *
 * @section LICENSE
 *
 * Copyright (c) 2012 Andrew Lindsay (andrew [at] thiseldo [dot] co [dot] uk)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * This is a basic cheerlights client, http://www.cheerlights.com/ It uses the
 * API url http://api.thingspeak.com/channels/1417/field/1/last.txt to read the last
 * colour selected.
 *
 * The hardware is the WiFiDIPCortex from SolderSplash Labs http://www.soldersplash.co.uk/products/wifi-dipcortex/
 * This is a small, yet powerful LPC1347 Cortex M3 dev board with built in CC3000 WiFi module.
 * The CC3000 uses the TI SmartConfig to setup the WiFi connection without having to update any code.
 *
 * The WiFiDIPCortex requires 2 pushbuttons connected between:
 *     Reset:  Pin 1 (Reset) and GND, plus 10K resistor between Pin 1 and 3.3V, Pin 11
 *     Config: Pin 6 (P1_31) and GND, plus 10K resistor between Pin 1 and 3.3V, Pin 11
 *
 * The LED strip used in this example is based on the WS2801 chips and requires a CLK and DATA to use it.
 *     Pin 27 (P0_7)  LED strip Data
 *     Pin 28 (P1_28) LED strip Clk.
 * Ideally strip should be powered from a external 3.3V source and the GNDs connected between Power supply and
 * WiFiDIPCortex.
 *
 * Debug output is sent to UART connected to pins 19 and 20.
 *
 * To use SmartConfig you'll need either the Android or iOS app from http://www.ti.com/tool/SmartConfig.
 * The Java version hasnt worked so far, but could also be used.
 * To enter SmartConfig mode, hold down the Config button, then press and release Reset, release Config.
 * You then use the SmartConfig app to set your network parameters, when you get the notification that
 * it was successful the WiFiDIPCortex is configured. The settings are saved and available next time it is powered up.
 *
 * If SmartConfig fails, try again.
 *
 * After starting the WiFiDIPCortex will connect to cheerlights.com and retrieve the latest colour and
 * set the lights to the colour.
 * Every minute the colour is retrieved and if its different to the last one the new colour is shown.
 *
 * The basic framework can be changed to use different LEDs to suit your available hardware.
 *
 */

#include "mbed.h"
#include "cc3000.h"
#include "HTTPClient.h"
// Library to drive the LED strip
#include "Adafruit_WS2801.h"

// Some local defines

#define SERIAL_BAUD_RATE    115200

#define WIGO           1
#define WIFI_DIPCORTEX 2
#define UNDEFINED      3

#define MY_BOARD WIFI_DIPCORTEX

using namespace mbed_cc3000;

// LED to indicate smart config is running
DigitalOut LedSC(P0_1);
//
DigitalIn SCButton(P1_31);

PinName dataPin(P1_28);    // Yellow wire on Adafruit Pixels
PinName clockPin(P0_7);    // Green wire on Adafruit Pixels

/* cc3000 module declaration specific for user's board. Check also init() */
#if (MY_BOARD == WIGO)
cc3000 wifi(PTA16, PTA13, PTD0, SPI(PTD2, PTD3, PTC5), PORTA_IRQn);
Serial uart(USBTX,USBRX);
#elif (MY_BOARD == WIFI_DIPCORTEX)
cc3000 wifi(p28, p27, p30, SPI(p21, p14, p37));
Serial uart(p19, p20);
#else

#endif

#ifndef CC3000_UNENCRYPTED_SMART_CONFIG
const uint8_t smartconfigkey[] = {0x73,0x6d,0x61,0x72,0x74,0x63,0x6f,0x6e,0x66,0x69,0x67,0x41,0x45,0x53,0x31,0x36};
#else
const uint8_t smartconfigkey = 0;
#endif

tNetappIpconfigRetArgs ipinfo;
extern char tmpBuffer[512];

bool Connected = false;
bool UsingSmartConfig = false;
char _deviceName[] = "CC3000";

HTTPClient http;
//char str[128];
uint32_t lastColour = 0;

// Set the first variable to the number of rows, the second to number of pixels. 32 = 32 pixels in a row
Adafruit_WS2801 strip = Adafruit_WS2801(1,32, dataPin, clockPin);

// Setup the colour table and mappings
#define NUM_COLOURS 12
struct ColourTable {
    char name[12];
    uint32_t value;
} colTable[NUM_COLOURS] = {
    { "red",       0xFF0000 },
    { "green",     0x008000 },
    { "blue",      0x0000FF },
    { "cyan",      0x00FFFF },
    { "white",     0xFFFFFF },
    { "warmwhite", 0xFDF5E6 },
    { "purple",    0x800080 },
    { "magenta",   0xFF00FF },
    { "yellow",    0xFFFF00 },
    { "orange",    0xFFA500 },
    { "pink",      0xff69b4 },
    { "oldlace",   0xfd5e56 }
};



/** Get status of WiFi connection
 * displays and returns value
 */
int32_t getWiFiStatus(void)
{
    int32_t status = 0;
    const char * WIFI_STATUS[] = {"Disconnected", "Scanning", "Connecting", "Connected"};

    status = wifi._wlan.ioctl_statusget();
    if (( status > -1 ) && ( status < 4 )) {
        uart.printf(" Wifi Status    : %s\r\n", WIFI_STATUS[status]);
    } else {
        uart.printf(" Wifi Status    : %d\r\n", status);
    }

    return status;
}

/** Print info from CC3000
 *
 */
void print_cc3000_info()
{
    uint8_t myMAC[8];
    uint8_t buffer[2];
    tNetappIpconfigRetArgs ipinfo2;
    tUserFS cc_user_info;

    wifi.get_user_file_info((uint8_t *)&cc_user_info, sizeof(cc_user_info));
    wifi.get_mac_address(myMAC);
    uart.printf(" MAC address : %02x:%02x:%02x:%02x:%02x:%02x\r\n", myMAC[0], myMAC[1], myMAC[2], myMAC[3], myMAC[4], myMAC[5]);

    if (! wifi._nvmem.read_sp_version( (unsigned char*)&buffer ) ) {
        uart.printf(" CC3000 Firmware Version : %u.%u \r\n", buffer[0], buffer[1]);
    } else {
        uart.printf(" CC3000 Read nvmem failed!");
    }
    getWiFiStatus();

    if ( wifi.is_dhcp_configured() ) {
        wifi.get_ip_config(&ipinfo2);
        uart.printf(" Connected to   : %s \r\n", ipinfo2.uaSSID);
        uart.printf(" IP             : %d.%d.%d.%d \r\n", ipinfo2.aucIP[3], ipinfo2.aucIP[2], ipinfo2.aucIP[1], ipinfo2.aucIP[0]);
        uart.printf(" Gateway        : %d.%d.%d.%d \r\n", ipinfo2.aucDefaultGateway[3], ipinfo2.aucDefaultGateway[2], ipinfo2.aucDefaultGateway[1], ipinfo2.aucDefaultGateway[0]);
        uart.printf(" Subnet         : %d.%d.%d.%d \r\n", ipinfo2.aucSubnetMask[3], ipinfo2.aucSubnetMask[2], ipinfo2.aucSubnetMask[1], ipinfo2.aucSubnetMask[0]);
        uart.printf(" DNS            : %d.%d.%d.%d \r\n", ipinfo2.aucDNSServer[3], ipinfo2.aucDNSServer[2], ipinfo2.aucDNSServer[1], ipinfo2.aucDNSServer[0]);

        uart.printf(" Cached IP      : %s \r\n", wifi.getIPAddress());
        uart.printf(" Cached Gateway : %s \r\n", wifi.getGateway());
        uart.printf(" Cached Subnet  : %s \r\n", wifi.getNetworkMask());

    } else {
        uart.printf(" Not connected \r\n");
    }
}


/** Convert name to colour
 * @param colStr Received colour name
 */
void setColour( char *colStr )
{
//    uart.printf("received %s\r\n",colStr);

    for( int i=0; i < NUM_COLOURS; i++ ) {
        if( strncmp( colTable[i].name, colStr, strlen(colTable[i].name) ) == 0 ) {
            for (int n=0; n < strip.numPixels(); n++) {
                strip.setPixelColor(n, colTable[i].value);
                strip.show();
                wait_ms(50);
            }
            return;
        }
    }
    uart.printf("No colour found\r\n");

}

/** Read Cheerlights colour
 * Use http call to get last Cheerlights colour
 */
void readCheerlight( void )
{
    char str[128];
    //GET data
    uart.printf("\r\nTrying to fetch page...\r\n");
    int ret = http.get("http://api.thingspeak.com/channels/1417/field/1/last.txt", str, 128);
    if (!ret) {
        uart.printf("Page fetched successfully - read %d characters\r\n", strlen(str));
        uart.printf("Result: %s\r\n", str);
        setColour( str );
    } else {
        uart.printf("Error - ret = %d - HTTP return code = %d\r\n", ret, http.getHTTPResponseCode());
    }

}


/** Initialisations
 * Hardware initialisations and any other setup needed
 */
void init()
{
    LedSC = 0;
    SCButton.mode(PullUp);
    NVIC_SetPriority(SSP1_IRQn, 0x0);
    NVIC_SetPriority(PIN_INT0_IRQn, 0x1);

    // SysTick set to lower priority than Wi-Fi SPI bus interrupt
    NVIC_SetPriority(SysTick_IRQn, 0x2);

    // Enable RAM1
    LPC_SYSCON->SYSAHBCLKCTRL |= (0x1 << 26);

    uart.baud(SERIAL_BAUD_RATE);

    strip.begin();

    // Update LED contents, to start they are all 'off'
    strip.show();
}

/** Main loop, handle WiFi connection, check for button press to start SmartConfig process
 *
 */
int main( void )
{
    // Initalise the WiFi Module
    init();

    uart.printf("WiFiDIPCortex Smartconfig Cheerlights\r\n");
    wifi.start(0);

    // Check if button pressed during startup, if so then go into SmartConfig mode
    // otherwise just start wifi
    if(!SCButton) {
        uart.printf("Smartconfig button pressed\r\n");

        //SmartConfig();
        uart.printf("\r\nStarting Smart config, waiting for message from smartphone app ....\r\n");
        LedSC = 1;
        // We dont want to auto reconnect to an access point
        wifi._wlan.ioctl_set_connection_policy(0, 0, 0);

        // start smart config will disconnect, set the prefix
        // wait for a message via a SmartConfig app, store it to the profile list
        // finally it will reenable auto connection, triggering the module to connect to the new access point
        wifi.start_smart_config(0);
        LedSC = 0;
        UsingSmartConfig = true;

        uart.printf("Back from SmartConfig\r\n");

        wait(2);    // for dhcp to configure

        if ( wifi.is_dhcp_configured() ) {
            if (!Connected) {
                // We have just connected
                Connected = true;

                // Start the mdns service, this tells any smart config apps listening we have succeeded
                wifi._socket.mdns_advertiser(1, (uint8_t *)_deviceName, strlen(_deviceName));

                UsingSmartConfig = false;
            }
        } else {
            Connected = false;

        }
    } else {
        uart.printf("Normal startup\r\n");
    }

    wait_ms(750);

    LedSC = 0;
    print_cc3000_info();
    
    // Check if we're connected to WiFi and have an IP address, if not then just flash LED
    uint32_t status = getWiFiStatus();
    if( status != 3 || !wifi.is_dhcp_configured() ) {
        while( 1 ) {
            LedSC = !LedSC;
            wait_ms(500);
        }    
    }

    while (1) {
        getWiFiStatus();
        readCheerlight();
        // Pause for a minute before checking again
        wait(60);
    }
}