// Light resource implementation

#include "mbed.h"
#include "rgb.h"

#define RGB_COLOUR_RES_ID    "308/0/0"
#define RGB_SETPT_RES_ID    "308/0/5900"
#define RGB_UNITS_RES_ID    "308/0/5701"

extern Serial pc;

static int rgb[] = {0, 0, 0};

class RGB {
public:
    RGB();
    void show(float r, float g, float b);

private:
    PwmOut rout;
    PwmOut gout;
    PwmOut bout;
};
RGB::RGB() : rout(p23), gout(p24), bout(p25) {
    pc.printf("RGB.ctor()\r\n");
    rout.period(0.001);
    gout.period(0.001);
    bout.period(0.001);
}

/*
The RGB LED is common anode, so that "0" is on, and "1" is off. For PWM, the closer to 0.0 the brighter, the closer to 1.0 the dimmer. 
This method uses (1.0 - rgb value) to invert.
*/
void RGB::show(float r, float g, float b) {
    rout = 1 - r;
    gout = 1 - g;
    bout = 1 - b;
}

/*
Convert the r|g|b string into the integer parts, each in the range [0,255]
*/
static void decode_rgb(char *rgbstr)
{
    char tmp[4];
    memset(tmp, 0, sizeof(tmp));
    char *next;
    char *token = rgbstr;
    int index = 0;
    while((next = strchr(token, '|')) != NULL) {
        int len = next - token;
        strncpy(tmp, token, len);
        rgb[index ++] = atoi(tmp);
        token = next + 1;
    }
    rgb[index] = atoi(token);
    pc.printf("decode_rgb(%s) = %d,%d,%d\r\n", rgbstr, rgb[0], rgb[1], rgb[2]);
}

static float RGB_SCALE = 1.0 / 255.0;
/*
The RGB LED is common anode, so that "0" is on, and "1" is off. For PWM, the closer to 0.0 the brighter, the closer to 1.0 the dimmer. 
This method uses (1.0 - rgb value) to invert.
*/
static void setRGB()
{
    static RGB rgbLed;
    pc.printf("Changing to RGB(%d,%d,%d)\r\n", rgb[0], rgb[1], rgb[2]);
    float r = rgb[0] * RGB_SCALE;
    float g = rgb[1] * RGB_SCALE;
    float b = rgb[2] * RGB_SCALE;
    rgbLed.show(r, g, b);
}
    
/* Only GET and PUT method allowed */
static uint8_t rgb_resource_cb(sn_coap_hdr_s *received_coap_ptr, sn_nsdl_addr_s *address, sn_proto_info_s * proto)
{
    sn_coap_hdr_s *coap_res_ptr = 0;
    char rgbstr[16];

    pc.printf("rgb callback\r\n");

    if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET)
    {
        coap_res_ptr = sn_coap_build_response(received_coap_ptr, COAP_MSG_CODE_RESPONSE_CONTENT);
  
        sprintf(rgbstr, "%d|%d|%d", rgb[0], rgb[1], rgb[2]);

        coap_res_ptr->payload_len = strlen(rgbstr);
        coap_res_ptr->payload_ptr = (uint8_t*)rgbstr;
        sn_nsdl_send_coap_message(address, coap_res_ptr);
    }
    else if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT)
    {
        memcpy(rgbstr, (char *)received_coap_ptr->payload_ptr, received_coap_ptr->payload_len);
        rgbstr[received_coap_ptr->payload_len] = '\0';
        decode_rgb(rgbstr);
        setRGB();

        coap_res_ptr = sn_coap_build_response(received_coap_ptr, COAP_MSG_CODE_RESPONSE_CHANGED);
        sn_nsdl_send_coap_message(address, coap_res_ptr);
    }

    sn_coap_parser_release_allocated_coap_msg_mem(coap_res_ptr);
    return 0;
}

int create_rgb_resource(sn_nsdl_resource_info_s *resource_ptr)
{
    nsdl_create_dynamic_resource(resource_ptr, sizeof(RGB_SETPT_RES_ID)-1, (uint8_t*)RGB_SETPT_RES_ID, 0, 0, 0, &rgb_resource_cb, (SN_GRS_GET_ALLOWED | SN_GRS_PUT_ALLOWED));
    nsdl_create_static_resource(resource_ptr, sizeof(RGB_COLOUR_RES_ID)-1, (uint8_t*) RGB_COLOUR_RES_ID, 0, 0,  (uint8_t*) "RBG LED Colour", sizeof("RBG LED Colour")-1);
    nsdl_create_static_resource(resource_ptr, sizeof(RGB_UNITS_RES_ID)-1, (uint8_t*) RGB_UNITS_RES_ID, 0, 0,  (uint8_t*) "(R|G|B)0-255", sizeof("(R|G|B)0-255")-1);
    setRGB();
    return 0;
}
void zero_rgb()
{
    memset(rgb, 0, sizeof(rgb));
    setRGB();
}
