This application shows an example of how to control the RGB LED over RPC. The app also contains an HTTP server and uses other components such as the LCD and Temperature Sensor to display additional information.

Dependencies:   C12832_lcd EthernetInterface HTTPServer LM75B MutexLocker mbed-rpc mbed-rtos mbed

main.cpp

Committer:
cabledev
Date:
2014-05-19
Revision:
2:1c34cfdbc18a
Parent:
1:784afed9dbfe

File content as of revision 2:1c34cfdbc18a:

/**
 * Notice:
 * 
 * Neither CableLabs nor any member company is responsible to any party for any liability of any nature whatsoever
 * resulting from or arising out of use or reliance upon this software. This software is furnished on an "AS IS" basis
 * and neither CableLabs nor its members provides any representation or warranty, express or implied, regarding the
 * accuracy, completeness, or fitness for a particular purpose of this software.
 * 
 * (C)Copyright 2014 Cable Television Laboratories, Inc. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * -----------------------------------------------------------------------------
 * 
 * File: main.cpp
 * 
 */

#include "mbed.h"

// LCD
#include "C12832_lcd.h"
#include "Small_7.h"

// HTTPServer
#include "HTTPServer.h"
#include "FsHandler.h"
#include "LocalFileSystem.h"
#include "RpcHandler.h"
#include "mbed_rpc.h"

// Temperature sensor
#include "mutexlocker.h"
#include "LM75B.h"

#define ON 1
#define OFF 0
#define DIM 0.3
#define SERIAL_BAUD 115200 // 9600
#define HTTP_LISTEN_PORT 80

// blinks LED1 when the HTTP server is listening for connections
//#define LISTENING_LED

// for some reason, getting the return code causes the HTTP server to be unresponsive
#define ETH_CONNECTION_STATUS

// uncomment the following line for static IP address
//#define STATIC_IP
#define STATIC_IP_ADDRESS "192.168.1.177"
#define STATIC_IP_NETMASK "255.255.255.0"
#define STATIC_IP_GATEWAY "192.168.1.1"

#define TEMPERATURE_ACTIVE

// LCD
// LCD object
C12832_LCD lcd;

// the led's are connected to vcc, so a PwmOut of 100% will shut off the led and 0% will let it shine!
PwmOut r(p23);
PwmOut g(p24);
PwmOut b(p25);
RpcPwmOut rpc_r(p23,"r");
RpcPwmOut rpc_g(p24,"g");
RpcPwmOut rpc_b(p25,"b");
// used to restore the rgb value after turning LED off and back on 
bool powerOn = true;
float lastH = 0.0;
float lastS = 0.0;
float lastV = -1.0;

AnalogIn Pot1(p19);
AnalogIn Pot2(p20);

// Ethernet
EthernetInterface eth;
bool ethConnected;

// HTTPServer
#ifdef LISTENING_LED
// Use LED1 to indicate that the main loop is still executing
DigitalOut listeningLed(LED1);
#endif
// Use the serial connection 'pc' to dump debug information
Serial pc(USBTX, USBRX, "pc");
// Instantiate a HTTPServer to handle incoming requests
HTTPServer  svr;
// Instantiate a local file system handler named 'local' which will be used later to access files on the mbed.
LocalFileSystem local("local");

// Temperature sensor
Mutex mutex;
LM75B temperatureSensor(p28,p27);

// RPC Variables
/*
//First create the variables you wish to use
float f;
int i;
char c;
//Then attach them to an RPCVariable Object
RPCVariable<float> rpc_f(&f, "f");
RPCVariable<int> rpc_i(&i, "i");
RPCVariable<char> rpc_c(&c, "c");
*/

// RPC Functions
void setLight(Arguments* input, Reply* output);

// invoke with "http://<eth_ip>/RPC/setLightColor/run <H> <S> <V> <brightness> <powerOn>",
//  where 0 <= H <= 360, 0 <= S <= 1, 0 <= V <= 1
RPCFunction rpc_setLight(&setLight, "setLight");

// function to convert hue , saturation and  value to RGB
// see http://en.wikipedia.org/wiki/HSL_and_HSV
void hsv2rgb(float H,float S, float V)
{
    float f,h,p,q,t;
    int i;
    if( S == 0.0) {
        r = 1.0 - V;  // invert pwm !
        g = 1.0 - V;
        b = 1.0 - V;
        return;
    }
    if(H > 360.0) H = 0.0;   // check values
    if(S > 1.0) S = 1.0; 
    if(S < 0.0) S = 0.0;
    if(V > 1.0) V = 1.0;
    if(V < 0.0) V = 0.0;
    h = H / 60.0;
    i = (int) h;
    f = h - i;
    p = V * (1.0 - S);
    q = V * (1.0 - (S * f));
    t = V * (1.0 - (S * (1.0 - f)));

    switch(i) {
        case 0:
            r = 1.0 - V;  // invert pwm !
            g = 1.0 - t;
            b = 1.0 - p;
            break;
        case 1:
            r = 1.0 - q;
            g = 1.0 - V;
            b = 1.0 - p;
            break;
        case 2:
            r = 1.0 - p;
            g = 1.0 - V;
            b = 1.0 - t;
            break;
        case 3:
            r = 1.0 - p;
            g = 1.0 - q;
            b = 1.0 - V;
            break;
        case 4:
            r = 1.0 - t;
            g = 1.0 - p;
            b = 1.0 - V;
            break;
        case 5:
        default:
            r = 1.0 - V;
            g = 1.0 - p;
            b = 1.0 - q;
            break;
    }
}

void setLightProperties(float h, float s, float v, bool power)
{
    printf("setLightProperties: HSV = '(%2f, %2f, %2f)', Power = '%s'\n\r", h, s, v, (power ? "ON" : "OFF"));
    
    if (powerOn)
    {
        hsv2rgb(h, s, v);
    }
    else
    {
        r = 1.0;
        g = 1.0;
        b = 1.0;
    }
}

void setLight(Arguments* input, Reply* output)
{
    // Arguments are already parsed into argv array of char*
    printf("Object name = %s\n\r",input->obj_name);
    printf("Method name = %s\n\r",input->method_name);
    for (int i=0; i < input->argc; i++)
    {
        printf("argv[%1d] = %s \n\r",i,input->argv[i]);
    }
    
    if (input->argc > 4)
    {
        char* strH = input->argv[0];
        char* strS = input->argv[1];
        char* strV = input->argv[2];
        char* strBrightness = input->argv[3];
        char* strPower = input->argv[4];
        
        float h;
        float s;
        float v;
        float brightness;
        int power;
        
        if ((strH != NULL) && (strlen(strH) > 0) && (strcmp(strH, "null") != 0))
        {
            // assume that if we got an H, we also got an S & V
            sscanf(strH, "%f", &h);
            sscanf(strS, "%f", &s);
            sscanf(strV, "%f", &v);
            
            lastH = h;
            lastS = s;
            lastV = v;
printf("*** set lastV from color to %f\n\r", lastV);
        }
        
        if ((strBrightness != NULL) && (strlen(strBrightness) > 0) && (strcmp(strBrightness, "null") != 0))
        {
            sscanf(strBrightness, "%f", &brightness);
            brightness = brightness / 100.0;
            brightness = brightness*brightness; // normalization, because in general, the LED is too bright
            lastV = brightness;
printf("*** set lastV from brightness to %f\n\r", lastV);
        }
        
        if ((strPower != NULL) && (strlen(strPower) > 0) && (strcmp(strPower, "null") != 0))
        {
            sscanf(strPower, "%i", &power);
            
            powerOn = (power == ON);
        }
        
        printf("setLight: HSV = '(%s, %s, %s)', Brightness = '%s', Power = '%s'\n\r", strH, strS, strV, strBrightness, strPower);
        
        setLightProperties(lastH, lastS, lastV, powerOn);
    }
}

void startHttpServer(void const* arg)
{
    // Ethernet
#ifdef STATIC_IP
    pc.printf("Configuring Ethernet with Static IP Address.\n\r");
    //eth.init("192.168.1.177", "255.255.255.0", "192.168.1.1");
    eth.init(STATIC_IP_ADDRESS, STATIC_IP_NETMASK, STATIC_IP_GATEWAY);
#else
    pc.printf("Configuring Ethernet with DHCP IP Address.\n\r");
    eth.init(); //Use DHCP
#endif
    
#ifdef ETH_CONNECTION_STATUS
//pc.printf("*** eth.connect()!\n\r");
    int connected = eth.connect(); // success == 0
//pc.printf("*** Eth.connect returned %i\n\r", connected);
    if (connected != 0)
    {
        lcd.printf("Ethernet not connected");
    }
    else
    {
#else
//pc.printf("*** eth.connect()!\n\r");
    eth.connect();
#endif
        char* ipAddr = eth.getIPAddress();
//pc.printf("*** ipAddr: %s\n\r", ipAddr);
        ethConnected = ((ipAddr != NULL) && (strlen(ipAddr) > 0));

        if (ethConnected)
        {
            mutex.lock();
            lcd.locate(10,0);
            lcd.printf("IP Address: %s", eth.getIPAddress());
            mutex.unlock();
            
#ifndef TEMPERATURE_ACTIVE
            mutex.lock();
            lcd.locate(10,10);
            lcd.printf("WebServer started");
            mutex.unlock();
#endif
        }
        else
        {
            lcd.printf("No IP Address");
        }
#ifdef ETH_CONNECTION_STATUS
    }
#endif
    
    svr.addHandler<HTTPFsRequestHandler>("/");
    svr.addHandler<HTTPRpcRequestHandler>("/RPC");
    
    svr.setPort(HTTP_LISTEN_PORT);
    svr.setEthernetInterface(&eth);
    svr.start();
}

void startTemperatureMonitor(void const* arg)
{
    float tempC = 0;
    float tempF = 0;
    while(true)
    {
        tempC = temperatureSensor.read();
        tempF = (tempC * 1.8f) + 32.0f;
        
        mutex.lock();
        lcd.locate(10,10);        
        lcd.printf("Temp: %.3f F\n", tempF);
        mutex.unlock();
        wait(1.0);
    }
}

int main()
{
    lcd.cls();
    lcd.set_font((unsigned char*) Small_7);
    
    r.period(0.001); // set pwm period
    
    // LED
    lastH = 120;
    lastS = 1;
    lastV = 0.5f;
    setLightProperties(lastH, lastS, lastV, true);
    
    //HTTPServer
    pc.baud(SERIAL_BAUD);
    
    // add the interfaces that can be created dynamically
    RPC::add_rpc_class<RpcDigitalOut>();
    RPC::add_rpc_class<RpcPwmOut>();
    
    HTTPFsRequestHandler::mount("/local/", "/");
    
    ethConnected = false;
    Thread httpsvr( &startHttpServer );
    
#ifdef TEMPERATURE_ACTIVE
    Thread tempMonitor(&startTemperatureMonitor );
#endif
    
    while (true)
    {
#ifdef LISTENING_LED
        if (ethConnected)
        {
            listeningLed = ON;
            wait(0.2);
            listeningLed = OFF;
            wait(0.2);
        }
#endif
    }
}