Cheerlights client using WiFiDIPCortex and WS2801 RGB LED strip

Dependencies:   Adafruit_WS2801 HTTPClient cc3000_hostdriver_mbedsocket mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /** WiFiDIPCortex Cheerlights
00002  *
00003  * @author Andrew Lindsay
00004  *
00005  * @section LICENSE
00006  *
00007  * Copyright (c) 2012 Andrew Lindsay (andrew [at] thiseldo [dot] co [dot] uk)
00008  *
00009  * Permission is hereby granted, free of charge, to any person obtaining a copy
00010  * of this software and associated documentation files (the "Software"), to deal
00011  * in the Software without restriction, including without limitation the rights
00012  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013  * copies of the Software, and to permit persons to whom the Software is
00014  * furnished to do so, subject to the following conditions:
00015 
00016  * The above copyright notice and this permission notice shall be included in
00017  * all copies or substantial portions of the Software.
00018  *
00019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025  * THE SOFTWARE.
00026  *
00027  * @section DESCRIPTION
00028  *
00029  * This is a basic cheerlights client, http://www.cheerlights.com/ It uses the
00030  * API url http://api.thingspeak.com/channels/1417/field/1/last.txt to read the last
00031  * colour selected.
00032  *
00033  * The hardware is the WiFiDIPCortex from SolderSplash Labs http://www.soldersplash.co.uk/products/wifi-dipcortex/
00034  * This is a small, yet powerful LPC1347 Cortex M3 dev board with built in CC3000 WiFi module.
00035  * The CC3000 uses the TI SmartConfig to setup the WiFi connection without having to update any code.
00036  *
00037  * The WiFiDIPCortex requires 2 pushbuttons connected between:
00038  *     Reset:  Pin 1 (Reset) and GND, plus 10K resistor between Pin 1 and 3.3V, Pin 11
00039  *     Config: Pin 6 (P1_31) and GND, plus 10K resistor between Pin 1 and 3.3V, Pin 11
00040  *
00041  * The LED strip used in this example is based on the WS2801 chips and requires a CLK and DATA to use it.
00042  *     Pin 27 (P0_7)  LED strip Data
00043  *     Pin 28 (P1_28) LED strip Clk.
00044  * Ideally strip should be powered from a external 3.3V source and the GNDs connected between Power supply and
00045  * WiFiDIPCortex.
00046  *
00047  * Debug output is sent to UART connected to pins 19 and 20.
00048  *
00049  * To use SmartConfig you'll need either the Android or iOS app from http://www.ti.com/tool/SmartConfig.
00050  * The Java version hasnt worked so far, but could also be used.
00051  * To enter SmartConfig mode, hold down the Config button, then press and release Reset, release Config.
00052  * You then use the SmartConfig app to set your network parameters, when you get the notification that
00053  * it was successful the WiFiDIPCortex is configured. The settings are saved and available next time it is powered up.
00054  *
00055  * If SmartConfig fails, try again.
00056  *
00057  * After starting the WiFiDIPCortex will connect to cheerlights.com and retrieve the latest colour and
00058  * set the lights to the colour.
00059  * Every minute the colour is retrieved and if its different to the last one the new colour is shown.
00060  *
00061  * The basic framework can be changed to use different LEDs to suit your available hardware.
00062  *
00063  */
00064 
00065 #include "mbed.h"
00066 #include "cc3000.h"
00067 #include "HTTPClient.h"
00068 // Library to drive the LED strip
00069 #include "Adafruit_WS2801.h"
00070 
00071 
00072 // Some local defines
00073 #define SERIAL_BAUD_RATE    115200
00074 
00075 #define NUM_PIXELS 50
00076 #define NUM_COL_HISTORY 5
00077 
00078 #define WIGO           1
00079 #define WIFI_DIPCORTEX 2
00080 #define UNDEFINED      3
00081 
00082 #define MY_BOARD WIFI_DIPCORTEX
00083 
00084 using namespace mbed_cc3000;
00085 
00086 // LED to indicate SmartConfig is running
00087 DigitalOut LedSC(P0_1);
00088 // Button to hold down during reset to enter SmartConfig mode
00089 DigitalIn SCButton(P1_31);
00090 
00091 // For Bit-Banging SPI use Pins 40 and 39
00092 PinName dataPin(p40);    // PIN 40 - Yellow wire on Adafruit Pixels
00093 PinName clockPin(p39);    // PIN 39 - Green wire on Adafruit Pixels
00094 
00095 // For hardware SPI use Pin 16 for Data and pin 13 for Clk
00096 
00097 /* cc3000 module declaration specific for user's board. Check also init() */
00098 #if (MY_BOARD == WIGO)
00099 cc3000 wifi(PTA16, PTA13, PTD0, SPI(PTD2, PTD3, PTC5), PORTA_IRQn);
00100 Serial uart(USBTX,USBRX);
00101 #elif (MY_BOARD == WIFI_DIPCORTEX)
00102 cc3000 wifi(p28, p27, p30, SPI(p21, p14, p37));
00103 Serial uart(p19, p20);
00104 #else
00105 
00106 #endif
00107 
00108 #ifndef CC3000_UNENCRYPTED_SMART_CONFIG
00109 //const uint8_t smartconfigkey[] = {0x73,0x6d,0x61,0x72,0x74,0x63,0x6f,0x6e,0x66,0x69,0x67,0x41,0x45,0x53,0x31,0x36};
00110 #else
00111 //const uint8_t smartconfigkey = 0;
00112 #endif
00113 
00114 tNetappIpconfigRetArgs ipinfo;
00115 extern char tmpBuffer[512];
00116 
00117 bool Connected = false;
00118 bool UsingSmartConfig = false;
00119 char _deviceName[] = "CC3000";
00120 
00121 HTTPClient http;
00122 
00123 // Set the first variable to the number of rows, the second to number of pixels. 32 = 32 pixels in a row
00124 Adafruit_WS2801 strip = Adafruit_WS2801(NUM_PIXELS, dataPin, clockPin);
00125 
00126 // Setup the colour table and mappings
00127 #define NUM_COLOURS 13
00128 struct ColourTable {
00129     char name[12];
00130     uint32_t value;
00131 } colTable[NUM_COLOURS] = {
00132     { "red",       0xff0000 },
00133     { "green",     0x008000 },
00134     { "blue",      0x0000ff },
00135     { "cyan",      0x00ffff },
00136     { "white",     0xffffff },
00137     { "warmwhite", 0xfdf5e6 },
00138     { "purple",    0x800080 },
00139     { "magenta",   0xff00ff },
00140     { "yellow",    0xffff00 },
00141     { "orange",    0xffa500 },
00142     { "pink",      0xff69b4 },
00143     { "oldlace",   0xfd5e56 },
00144     { "black",     0x000000 }
00145 };
00146 
00147 /** Get status of WiFi connection
00148  * displays and returns value
00149  */
00150 int32_t getWiFiStatus(void)
00151 {
00152     int32_t status = 0;
00153     const char * WIFI_STATUS[] = {"Disconnected", "Scanning", "Connecting", "Connected"};
00154 
00155     status = wifi._wlan.ioctl_statusget();
00156     if (( status > -1 ) && ( status < 4 )) {
00157         uart.printf(" Wifi Status    : %s\r\n", WIFI_STATUS[status]);
00158     } else {
00159         uart.printf(" Wifi Status    : %d\r\n", status);
00160     }
00161 
00162     return status;
00163 }
00164 
00165 /** Print info from CC3000
00166  *
00167  */
00168 void print_cc3000_info()
00169 {
00170     uint8_t myMAC[8];
00171     uint8_t buffer[2];
00172     tNetappIpconfigRetArgs ipinfo2;
00173     tUserFS cc_user_info;
00174 
00175     wifi.get_user_file_info((uint8_t *)&cc_user_info, sizeof(cc_user_info));
00176     wifi.get_mac_address(myMAC);
00177     uart.printf(" MAC address : %02x:%02x:%02x:%02x:%02x:%02x\r\n", myMAC[0], myMAC[1], myMAC[2], myMAC[3], myMAC[4], myMAC[5]);
00178 
00179     if (! wifi._nvmem.read_sp_version( (unsigned char*)&buffer ) ) {
00180         uart.printf(" CC3000 Firmware Version : %u.%u \r\n", buffer[0], buffer[1]);
00181     } else {
00182         uart.printf(" CC3000 Read nvmem failed!");
00183     }
00184     getWiFiStatus();
00185 
00186     if ( wifi.is_dhcp_configured() ) {
00187         wifi.get_ip_config(&ipinfo2);
00188         uart.printf(" Connected to   : %s \r\n", ipinfo2.uaSSID);
00189         uart.printf(" IP             : %d.%d.%d.%d \r\n", ipinfo2.aucIP[3], ipinfo2.aucIP[2], ipinfo2.aucIP[1], ipinfo2.aucIP[0]);
00190         uart.printf(" Gateway        : %d.%d.%d.%d \r\n", ipinfo2.aucDefaultGateway[3], ipinfo2.aucDefaultGateway[2], ipinfo2.aucDefaultGateway[1], ipinfo2.aucDefaultGateway[0]);
00191         uart.printf(" Subnet         : %d.%d.%d.%d \r\n", ipinfo2.aucSubnetMask[3], ipinfo2.aucSubnetMask[2], ipinfo2.aucSubnetMask[1], ipinfo2.aucSubnetMask[0]);
00192         uart.printf(" DNS            : %d.%d.%d.%d \r\n", ipinfo2.aucDNSServer[3], ipinfo2.aucDNSServer[2], ipinfo2.aucDNSServer[1], ipinfo2.aucDNSServer[0]);
00193 
00194         uart.printf(" Cached IP      : %s \r\n", wifi.getIPAddress());
00195         uart.printf(" Cached Gateway : %s \r\n", wifi.getGateway());
00196         uart.printf(" Cached Subnet  : %s \r\n", wifi.getNetworkMask());
00197 
00198     } else {
00199         uart.printf(" Not connected \r\n");
00200     }
00201 }
00202 
00203 
00204 /** Convert name to colour and set it on LEDs. With colour history, strip will be
00205  * changing colour for every new colour detected producing an almost random effect
00206  * @param colNum Number of the received colour, starts 0 to NUM_COL_HISTORY with highest being latest colour
00207  * @param colStr Received colour name
00208  */
00209 void setColour( int colNum, char *colStr )
00210 {
00211 //    uart.printf("received %s\r\n",colStr);
00212 
00213     for( int i=0; i < NUM_COLOURS; i++ ) {
00214         if( strncmp( colTable[i].name, colStr, strlen(colTable[i].name) ) == 0 ) {
00215             for (int n=colNum; n < strip.numPixels()+NUM_COL_HISTORY; n += NUM_COL_HISTORY) {
00216                 strip.setPixelColor(n, colTable[i].value);
00217             }
00218             // Update strip after colour has been set
00219             strip.show();
00220             // Slight pause 
00221             wait_ms(250);
00222             return;
00223         }
00224     }
00225     uart.printf("No colour found\r\n");
00226 
00227 }
00228 
00229 #define CL_BUFFSIZE 1024
00230 /** Read Cheerlights colour
00231  * Use http call to get last Cheerlights colour
00232  */
00233 void readCheerlight( void )
00234 {
00235     char responseStr[CL_BUFFSIZE];
00236     //GET data
00237     uart.printf("\r\nTrying to fetch page...\r\n");
00238     int ret = http.get("http://api.thingspeak.com/channels/1417/feed.csv?results=5", responseStr, CL_BUFFSIZE);
00239     if (!ret) {
00240         uart.printf("Page fetched successfully - read %d characters\r\n", strlen(responseStr));
00241         //uart.printf("Result: %s\r\n", responseStr);
00242         // Parse CSV and set colours
00243         // Get a line
00244         char *ptr = responseStr;
00245         // Skip header line
00246         while(*ptr++ != 0x0a ); // Header
00247         // 5 colours
00248         for( int i=0; i<5; i++ ) {
00249             while(*ptr++ != ',');   // Column 1 - Date, Skip
00250             while(*ptr++ != ',');   // Column 2 - ID, Skip
00251             char col[10];
00252             char *cPtr = col;
00253             while( *ptr != 0x0a ) { // Column 3 - colour
00254                 *cPtr++ = *ptr++;
00255             }
00256             *cPtr = '\0';
00257             uart.printf("%d %s\r\n",i,col);
00258             setColour( i, col );
00259         }
00260     } else {
00261         uart.printf("Error - ret = %d - HTTP return code = %d\r\n", ret, http.getHTTPResponseCode());
00262     }
00263 
00264     uart.printf("End of readCheerlights\n\r");
00265 }
00266 
00267 
00268 /** Initialisations
00269  * Hardware initialisations and any other setup needed
00270  */
00271 void init()
00272 {
00273     LedSC = 0;
00274     SCButton.mode(PullUp);
00275     NVIC_SetPriority(SSP1_IRQn, 0x0);
00276     NVIC_SetPriority(PIN_INT0_IRQn, 0x1);
00277 
00278     // SysTick set to lower priority than Wi-Fi SPI bus interrupt
00279     NVIC_SetPriority(SysTick_IRQn, 0x2);
00280 
00281     // Enable RAM1
00282     LPC_SYSCON->SYSAHBCLKCTRL |= (0x1 << 26);
00283 
00284     uart.baud(SERIAL_BAUD_RATE);
00285 
00286     strip.updatePins();    // Switch to Hardware SPI
00287     strip.begin();
00288 
00289     // Update LED contents, to start they are all 'off'
00290     strip.show();
00291 }
00292 
00293 /** Main loop, handle WiFi connection, check for button press to start SmartConfig process
00294  *
00295  */
00296 int main( void )
00297 {
00298     // Initalise the WiFi Module
00299     init();
00300 
00301     uart.printf("WiFiDIPCortex Smartconfig Cheerlights\r\n");
00302     wifi.start(0);
00303 
00304     // Check if button pressed during startup, if so then go into SmartConfig mode
00305     // otherwise just start wifi
00306     if(!SCButton) {
00307         uart.printf("Smartconfig button pressed\r\n");
00308 
00309         //SmartConfig();
00310         uart.printf("\r\nStarting Smart config, waiting for message from smartphone app ....\r\n");
00311         LedSC = 1;
00312         // We dont want to auto reconnect to an access point
00313         wifi._wlan.ioctl_set_connection_policy(0, 0, 0);
00314 
00315         // start smart config will disconnect, set the prefix
00316         // wait for a message via a SmartConfig app, store it to the profile list
00317         // finally it will reenable auto connection, triggering the module to connect to the new access point
00318         wifi.start_smart_config(0);
00319         LedSC = 0;
00320         UsingSmartConfig = true;
00321 
00322         uart.printf("Back from SmartConfig\r\n");
00323 
00324         wait(2);    // for dhcp to configure
00325 // TODO: Add this into start_smart_config
00326         if ( wifi.is_dhcp_configured() ) {
00327             if (!Connected) {
00328                 // We have just connected
00329                 Connected = true;
00330                 // This might need calling for mdsn advertiser to work.
00331                 //   uint32_t ip_addr[4] = {0,0,0,0};
00332                 //   wifi._socket.gethostbyname((uint8_t *)_deviceName, strlen(_deviceName), uint32_t *ip_addr);
00333 
00334                 // Start the mdns service, this tells any smart config apps listening we have succeeded
00335                 wifi._socket.mdns_advertiser(1, (uint8_t *)_deviceName, strlen(_deviceName));
00336 
00337                 UsingSmartConfig = false;
00338             }
00339         } else {
00340             Connected = false;
00341 
00342         }
00343     } else {
00344         uart.printf("Normal startup\r\n");
00345     }
00346 
00347     wait_ms(750);
00348 
00349     LedSC = 0;
00350     print_cc3000_info();
00351 
00352     // Check if we're connected to WiFi and have an IP address, if not then just flash LED until reset
00353     uint32_t status = getWiFiStatus();
00354     if( status != 3 || !wifi.is_dhcp_configured() ) {
00355         while( 1 ) {
00356             LedSC = !LedSC;
00357             wait_ms(500);
00358         }
00359     }
00360 
00361     while (1) {
00362         if( getWiFiStatus() == 0 ) {
00363             // Not connected, attempt reconnect
00364             ;
00365         }
00366         readCheerlight();
00367         // Pause for a minute before checking again
00368         wait(60);
00369     }
00370 }