Ambilight d\'appart // XBMC & arduino
Publié : lun. 12 nov. 2012 21:00
ca marche sous win j'ia fait une tite vidéo maintenatn j'essai de le monter sur la hdbox avec ubuntu cpa tout a fait gagné
niveau soft

/* * boblight * Copyright (C) Bob 2009 * * boblight is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * boblight is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "util/inclstdint.h" #include #include //debug #include #include "boblight_client.h" #include "util/misc.h" #include "util/timeutils.h" #include "protocolversion.h" using namespace std; using namespace boblight; #define GAMMASIZE (sizeof(m_gammacurve) / sizeof(m_gammacurve[0])) CLight::CLight() { #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) variable = default; #include "options.h" #undef BOBLIGHT_OPTION m_singlechange = 0.0; m_width = -1; m_height = -1; memset(m_rgb, 0, sizeof(m_rgb)); m_rgbcount = 0; memset(m_prevrgb, 0, sizeof(m_prevrgb)); memset(m_hscanscaled, 0, sizeof(m_hscanscaled)); memset(m_vscanscaled, 0, sizeof(m_vscanscaled)); for (int i = 0; i < GAMMASIZE; i++) m_gammacurve = i; } string CLight::SetOption(const char* option, bool& send) { string stroption = option; string strname; send = false; if (!GetWord(stroption, strname)) return "emtpy option"; //string with only whitespace #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) \ if (strname == #name) \ { \ type value; \ if (#type == "bool")\ {\ if (!StrToBool(stroption, *(bool*)(&value)))\ return "invalid value " + stroption + " for option " + strname + " with type " + #type; \ }\ else\ {\ stringstream stream; \ stream > value; \ if (stream.fail()) return "invalid value " + stroption + " for option " + strname + " with type " + #type; \ \ }\ variable = value; \ postprocess\ \ return ""; \ } #include "options.h" #undef BOBLIGHT_OPTION return "unknown option " + strname; } std::string CLight::GetOption(const char* option, std::string& output) { string stroption = option; string strname; if (!GetWord(stroption, strname)) return "emtpy option"; //string with only whitespace #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) \ if (#name == strname)\ {\ output = ToString(variable);\ return "";\ } #include "options.h" #undef BOBLIGHT_OPTION return "unknown option"; } void CLight::AddPixel(int* rgb) { if (rgb[0] >= m_threshold || rgb[1] >= m_threshold || rgb[2] >= m_threshold) { if (m_gamma == 1.0) { m_rgb[0] += Clamp(rgb[0], 0, 255); m_rgb[1] += Clamp(rgb[1], 0, 255); m_rgb[2] += Clamp(rgb[2], 0, 255); } else { m_rgb[0] += m_gammacurve[Clamp(rgb[0], 0, GAMMASIZE - 1)]; m_rgb[1] += m_gammacurve[Clamp(rgb[1], 0, GAMMASIZE - 1)]; m_rgb[2] += m_gammacurve[Clamp(rgb[2], 0, GAMMASIZE - 1)]; } } m_rgbcount++; } void CLight::GetRGB(float* rgb) { //if no pixels are set, the denominator is 0, so just return black if (m_rgbcount == 0) { for (int i = 0; i < 3; i++) { rgb = 0.0f; m_rgb = 0.0f; } return; } //convert from numerator/denominator to float for (int i = 0; i < 3; i++) { rgb = Clamp(m_rgb / (float)m_rgbcount / 255.0f, 0.0f, 1.0f); m_rgb = 0.0f; } m_rgbcount = 0; //this tries to set the speed based on how fast the input is changing //it needs sync mode to work properly if (m_autospeed > 0.0) { float change = Abs(rgb[0] - m_prevrgb[0]) + Abs(rgb[1] - m_prevrgb[1]) + Abs(rgb[2] - m_prevrgb[2]); change /= 3.0; //only apply singlechange if it's large enough, otherwise we risk sending it continously if (change > 0.001) m_singlechange = Clamp(change * m_autospeed / 10.0, 0.0, 1.0); else m_singlechange = 0.0; } memcpy(m_prevrgb, rgb, sizeof(m_prevrgb)); //we need some hsv adjustments if (m_value != 1.0 || m_valuerange[0] != 0.0 || m_valuerange[1] != 1.0 || m_saturation != 1.0 || m_satrange[0] != 0.0 || m_satrange[1] != 1.0) { //rgb - hsv conversion, thanks wikipedia! float hsv[3]; float max = Max(rgb[0], rgb[1], rgb[2]); float min = Min(rgb[0], rgb[1], rgb[2]); if (min == max) //grayscale { hsv[0] = -1.0f; //undefined hsv[1] = 0.0; //no saturation hsv[2] = min; //value } else { if (max == rgb[0]) //red zone { hsv[0] = (60.0f * ((rgb[1] - rgb[2]) / (max - min)) + 360.0f); while (hsv[0] >= 360.0f) hsv[0] -= 360.0f; } else if (max == rgb[1]) //green zone { hsv[0] = 60.0f * ((rgb[2] - rgb[0]) / (max - min)) + 120.0f; } else if (max == rgb[2]) //blue zone { hsv[0] = 60.0f * ((rgb[0] - rgb[1]) / (max - min)) + 240.0f; } hsv[1] = (max - min) / max; //saturation hsv[2] = max; //value } //saturation and value adjustment hsv[1] = Clamp(hsv[1] * m_saturation, m_satrange[0], m_satrange[1]); hsv[2] = Clamp(hsv[2] * m_value, m_valuerange[0], m_valuerange[1]); if (hsv[0] == -1.0f) //grayscale { for (int i = 0; i < 3; i++) rgb = hsv[2]; } else { int hi = (int)(hsv[0] / 60.0f) % 6; float f = (hsv[0] / 60.0f) - (float)(int)(hsv[0] / 60.0f); float s = hsv[1]; float v = hsv[2]; float p = v * (1.0f - s); float q = v * (1.0f - f * s); float t = v * (1.0f - (1.0f - f) * s); if (hi == 0) { rgb[0] = v; rgb[1] = t; rgb[2] = p; } else if (hi == 1) { rgb[0] = q; rgb[1] = v; rgb[2] = p; } else if (hi == 2) { rgb[0] = p; rgb[1] = v; rgb[2] = t; } else if (hi == 3) { rgb[0] = p; rgb[1] = q; rgb[2] = v; } else if (hi == 4) { rgb[0] = t; rgb[1] = p; rgb[2] = v; } else if (hi == 5) { rgb[0] = v; rgb[1] = p; rgb[2] = q; } } for (int i = 0; i < 3; i++) rgb = Clamp(rgb, 0.0f, 1.0f); } } //scale the light's scanrange to the dimensions set with boblight_setscanrange() void CLight::SetScanRange(int width, int height) { m_width = width; m_height = height; m_hscanscaled[0] = Round32(m_hscan[0] / 100.0 * ((float)width - 1)); m_hscanscaled[1] = Round32(m_hscan[1] / 100.0 * ((float)width - 1)); m_vscanscaled[0] = Round32(m_vscan[0] / 100.0 * ((float)height - 1)); m_vscanscaled[1] = Round32(m_vscan[1] / 100.0 * ((float)height - 1)); } int CBoblight::Connect(const char* address, int port, int usectimeout) { CMessage message; CTcpData data; int64_t now; int64_t target; string word; //set address m_usectimeout = usectimeout; if (address) m_address = address; else m_address = "127.0.0.1"; //set port if (port >= 0) m_port = port; else m_port = 19333; //try to open a tcp connection if (m_socket.Open(m_address, m_port, m_usectimeout) != SUCCESS) { m_error = m_socket.GetError(); return 0; } //write hello to the server, we should get hello back if (!WriteDataToSocket("hello\n")) return 0; if (!ReadDataToQueue()) return 0; message = m_messagequeue.GetMessage(); if (!ParseWord(message, "hello")) { m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; return 0; } //get the protocol version from the server if (!WriteDataToSocket("get version\n")) return 0; if (!ReadDataToQueue()) return 0; message = m_messagequeue.GetMessage(); if (!ParseWord(message, "version") || !GetWord(message.message, word)) { m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; return 0; } //if we don't get the same protocol version back as we have, we can't work together if (word != PROTOCOLVERSION) { m_error = "version mismatch, " + m_address + ":" + ToString(m_port) + " has version \"" + word + "\", libboblight has version \"" + PROTOCOLVERSION + "\""; return 0; } //get lights info, like number, names and area if (!WriteDataToSocket("get lights\n")) return 0; if (!ReadDataToQueue()) return 0; message = m_messagequeue.GetMessage(); if (!ParseLights(message)) { m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; return 0; } return 1; } CBoblight::CBoblight() { int padsize = 1; //get option name pad size so it looks pretty #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) \ if (strlen(#name) + 1 > padsize)\ padsize = strlen(#name) + 1; #include "options.h" #undef BOBLIGHT_OPTION //stick in a line that describes the options string option = "name"; option.append(Max(padsize - option.length(), 1), ' '); option += "type min max default"; m_options.push_back(option); //fill vector with option strings #define BOBLIGHT_OPTION(name, type, min, max, default, variable, postprocess) \ {\ string option = #name;\ option.append(padsize - strlen(#name), ' ');\ \ option += #type;\ option.append(Max(8 - strlen(#type), 1), ' ');\ \ option += #min;\ option.append(Max(8 - strlen(#min), 1), ' ');\ \ option += #max;\ option.append(Max(8 - strlen(#max), 1), ' ');\ \ if (strcmp(#default, "-1.0") == 0)\ option += "set by boblightd";\ else\ option += #default;\ \ m_options.push_back(option);\ } #include "options.h" #undef BOBLIGHT_OPTION } //reads from socket until timeout or one message has arrived bool CBoblight::ReadDataToQueue() { CTcpData data; int64_t now = GetTimeUs(); int64_t target = now + m_usectimeout; int nrmessages = m_messagequeue.GetNrMessages(); while (now < target && m_messagequeue.GetNrMessages() == nrmessages) { if (m_socket.Read(data) != SUCCESS) { m_error = m_socket.GetError(); return false; } m_messagequeue.AddData(data.GetData()); if (m_messagequeue.GetRemainingDataSize() > MAXDATA) { m_error = m_address + ":" + ToString(m_port) + " sent too much data"; return false; } now = GetTimeUs(); } if (nrmessages == m_messagequeue.GetNrMessages()) { m_error = m_address + ":" + ToString(m_port) + " read timed out"; return false; } return true; } bool CBoblight::WriteDataToSocket(std::string strdata) { CTcpData data; data.SetData(strdata); if (m_socket.Write(data) != SUCCESS) { m_error = m_socket.GetError(); return false; } return true; } //removes one word from the string in the messages, and compares it to wordtocmp bool CBoblight::ParseWord(CMessage& message, std::string wordtocmp) { string readword; if (!GetWord(message.message, readword) || readword != wordtocmp) return false; return true; } bool CBoblight::ParseLights(CMessage& message) { string word; int nrlights; //first word in the message is "lights", second word is the number of lights if (!ParseWord(message, "lights") || !GetWord(message.message, word) || !StrToInt(word, nrlights) || nrlights < 1) return false; for (int i = 0; i < nrlights; i++) { CLight light; //read some data to the message queue if we have no messages if (m_messagequeue.GetNrMessages() == 0) { if (!ReadDataToQueue()) return false; } message = m_messagequeue.GetMessage(); //first word sent is "light, second one is the name if (!ParseWord(message, "light") || !GetWord(message.message, light.m_name)) { return false; } //third one is "scan" if (!ParseWord(message, "scan")) return false; //now we read the scanrange string scanarea; for (int i = 0; i < 4; i++) { if (!GetWord(message.message, word)) return false; scanarea += word + " "; } ConvertFloatLocale(scanarea); //workaround for locale mismatch (, and .) if (sscanf(scanarea.c_str(), "%f %f %f %f", light.m_vscan, light.m_vscan + 1, light.m_hscan, light.m_hscan + 1) != 4) return false; m_lights.push_back(light); } return true; } const char* CBoblight::GetLightName(int lightnr) { if (lightnr < 0) //negative lights don't exist, so we set it to an invalid number to get the error message lightnr = m_lights.size(); if (CheckLightExists(lightnr)) return m_lights[lightnr].m_name.c_str(); return NULL; } int CBoblight::SetPriority(int priority) { string data = "set priority " + ToString(priority) + "\n"; return WriteDataToSocket(data); } bool CBoblight::CheckLightExists(int lightnr, bool printerror /*= true*/) { if (lightnr >= (int)m_lights.size()) { if (printerror) { m_error = "light " + ToString(lightnr) + " doesn't exist (have " + ToString(m_lights.size()) + " lights)"; } return false; } return true; } void CBoblight::SetScanRange(int width, int height) { for (int i = 0; i < m_lights.size(); i++) { m_lights.SetScanRange(width, height); } } int CBoblight::AddPixel(int lightnr, int* rgb) { if (!CheckLightExists(lightnr)) return 0; if (lightnr < 0) { for (int i = 0; i < m_lights.size(); i++) m_lights[i].AddPixel(rgb); } else { m_lights[lightnr].AddPixel(rgb); } return 1; } void CBoblight::AddPixel(int* rgb, int x, int y) { for (int i = 0; i < m_lights.size(); i++) { if (x >= m_lights[i].m_hscanscaled[0] && x = m_lights[i].m_vscanscaled[0] && y 0.0 && m_lights[i].m_singlechange > 0.0) data += "set light " + m_lights[i].m_name + " singlechange " + ToString(m_lights[i].m_singlechange) + "\n"; } //send a message that we want devices to sync to our input if (sync) data += "sync\n"; //if we want to check if our output is used, send a ping message if (outputused) data += "ping\n"; if (!WriteDataToSocket(data)) return 0; if (outputused) return Ping(outputused, false); else return 1; } int CBoblight::Ping(int* outputused, bool send) { string word; if (send) { if (!WriteDataToSocket("ping\n")) return 0; } if (!ReadDataToQueue()) return 0; CMessage message = m_messagequeue.GetMessage(); if (!GetWord(message.message, word) || word != "ping") { m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; return 0; } //client can set outputused to NULL if (outputused) { if (!GetWord(message.message, word) || !StrToInt(word, *outputused)) { m_error = m_address + ":" + ToString(m_port) + " sent gibberish"; return 0; } } return 1; } int CBoblight::GetNrOptions() { return m_options.size(); } const char* CBoblight::GetOptionDescription(int option) { if (option < 0 || option >= m_options.size()) return NULL; return m_options[option].c_str(); } int CBoblight::SetOption(int lightnr, const char* option) { string error; string data; bool send; if (!CheckLightExists(lightnr)) return 0; if (lightnr < 0) { for (int i = 0; i < m_lights.size(); i++) { error = m_lights[i].SetOption(option, send); if (!error.empty()) { m_error = error; return 0; } if (send) { data += "set light " + m_lights[i].m_name + " " + option + "\n"; } } } else { error = m_lights[lightnr].SetOption(option, send); if (!error.empty()) { m_error = error; return 0; } if (send) { data += "set light " + m_lights[lightnr].m_name + " " + option + "\n"; } } if (!WriteDataToSocket(data)) return 0; return 1; } int CBoblight::GetOption(int lightnr, const char* option, const char** output) { if (lightnr < 0) //negative lights don't exist, so we set it to an invalid number to get the error message lightnr = m_lights.size(); if (!CheckLightExists(lightnr)) return 0; string error = m_lights[lightnr].GetOption(option, m_lastoption); if (!error.empty()) { m_error = error; return 0; } *output = m_lastoption.c_str(); return 1; }