//#ifdef HAVE_CONFIG_H #include //#endif #include "mc-hid-server.hpp" #include "log/log.hpp" #include #include #include #include #include #include #include using namespace std; const uint8_t BTN_HOME = 7; const uint8_t BTN_CANCEL = 8; const uint8_t BTN_UP = 9; const uint8_t BTN_DOWN = 10; const uint8_t BTN_PLAY = 11; const uint8_t BTN_FWD = 12; const uint8_t BTN_RWD = 16; const uint8_t BTN_OK = 17; // map the buttons to names const std::map BUTTONS = { { BTN_HOME, "BTN_ESCAPE"}, { BTN_CANCEL, "BTN_CANCEL"}, { BTN_UP, "BTN_UP"}, { BTN_DOWN, "BTN_DOWN"}, { BTN_FWD, "BTN_FASTFORWARD"}, { BTN_PLAY, "BTN_PLAYPAUSE"}, { BTN_RWD, "BTN_REWIND"}, { BTN_OK, "BTN_OK"}, }; // define the active state of the const std::map BUTTONS_ACTIVE = { { BTN_HOME, true}, { BTN_CANCEL, false}, { BTN_UP, false}, { BTN_DOWN, false}, { BTN_FWD, false}, { BTN_PLAY, false}, { BTN_RWD, false}, { BTN_OK, false}, }; const std::vector BUTTONS_REGULAR = { BTN_CANCEL, BTN_UP, BTN_DOWN, BTN_FWD, BTN_PLAY, BTN_RWD, BTN_OK, }; const uint8_t LED_RED = 4; const uint8_t LED_GREEN = 5; const uint8_t LED_BLUE = 6; const uint8_t FAN_CTL = 13; const int PULSE_STEPS = 32; static const char *HID_SERVER_NAME = "nl.miqra.MediaCore.Hid"; static const char *HID_SERVER_PATH = "/nl/miqra/MediaCore/Hid"; // signal handler void niam(int sig); HidServer::HidServer(DBus::Connection &connection) : DBus::ObjectAdaptor(connection, HID_SERVER_PATH) { // Initialize button timer btnTimer = new ButtonTimer(70,5000); // 70 ms debounce time, and a Long press takes 5 seconds onShortPressConnection = this->btnTimer->onShortPress.connect( boost::bind( &HidServer::onShortPress, this, _1) ); onLongPressConnection = this->btnTimer->onLongPress.connect( boost::bind( &HidServer::onLongPress, this, _1) ); //onValidatePressConnection = this->btnTimer->onValidatePress.connect( boost::bind( &HidServer::onValidatePress, this, _1) ); // **** Initialize the GPIO Interrupt pin clog << kLogInfo << PACKAGE_STRING << " starting..." << endl; try { // Setup all buttons for pullup and input // Setup home button (which is active-high) clog << kLogInfo << "Connecting to Home button"; this->btHome = new GpioPin(BTN_HOME); clog << kLogInfo << "."; onBtHomeConnection = this->btHome->onChange.connect( boost::bind( &HidServer::onBtChange, this, _1, _2, _3) ); clog << kLogInfo << "."; this->btHome->Listen(GpioEdge::Both, GpioPullup::PullUp, false); clog << kLogInfo << "." << endl; // Setup theo ther butons (which are active-low) clog << kLogInfo << "Connecting to other buttons"; this->btOther = new GpioPins(BUTTONS_REGULAR); clog << kLogInfo << "."; onBtOtherConnection = this->btOther->onChange.connect( boost::bind( &HidServer::onBtChange, this, _1, _2, _3) ); clog << kLogInfo << "."; this->btOther->Listen(GpioEdge::Both, GpioPullup::PullUp, true); clog << kLogInfo << "." << endl; // setup the LED this->rgbLed = new RgbLed(LED_RED,LED_GREEN,LED_BLUE); } catch(const std::exception& x) { clog << kLogCrit << endl << "Fatal error during hardware initialization: " << x.what() << endl << "Quitting now... " << endl; exit(-1); } clog << kLogInfo << "Initialization complete, listening to HID requests." << endl; } HidServer::~HidServer() { ClearColor(); onBtHomeConnection.disconnect(); onBtOtherConnection.disconnect(); onShortPressConnection.disconnect(); onLongPressConnection.disconnect(); onValidatePressConnection.disconnect(); delete this->btnTimer; this->btnTimer = NULL; delete this->btOther; delete this->btHome; delete this->rgbLed; clog << kLogInfo << "Stopping normally" << endl; } void HidServer::SetColor(const uint8_t& r, const uint8_t& g, const uint8_t& b) { clog << kLogDebug << "Got color request: RGB("<< (int)r << "," << (int)g << "," << (int)b << ") - " << endl; this->ThreadStop(); this->rgbLed->SetColor(r,g,b); } void HidServer::PulseColor(const uint8_t& r, const uint8_t& g, const uint8_t& b, const double& interval) { pulseR = r; pulseG = g; pulseB = b; pulseDirUp = true; pulseMin = 0; pulseI = pulseMin; clog << kLogDebug << "Got pulse color request: RGB("<< (int)r << "," << (int)g << "," << (int)b << ")" << endl; // Default PULSE_STEPS is 32, reduce accordingly when interval is below 2 seconds // with 32 pulse steps, this results in min 2.0 / (2*32) = 31 ms per color pulseSteps = PULSE_STEPS; if(interval > 2.0) { pulseSteps = (int32_t)(interval * pulseSteps); } pulseTime = (int32_t)((interval * 1000000) / (2 * pulseSteps)); // Start pulse thread and PWM system ThreadStart(); } // contains the pulse loop (note: faster pulsing does use more cpu) void HidServer::ThreadLoop() { uint8_t myR, myG, myB; int32_t factor = pulseI*100; myR = (pulseR * factor)/(100 * pulseSteps); myG = (pulseG * factor)/(100 * pulseSteps); myB = (pulseB * factor)/(100 * pulseSteps); this->rgbLed->SetColor(myR,myG,myB); if(pulseDirUp) { pulseI++; if(pulseI>= pulseSteps) pulseDirUp = false; } else { pulseI--; if(pulseI <= pulseMin) pulseDirUp = true; } usleep(pulseTime); } void HidServer::ClearColor() { clog << kLogDebug << "Clearing color" << endl; // Stop pulse thread ThreadStop(); // Disable PWM and turn all colors off this->rgbLed->SetColor(0,0,0); } void HidServer::onBtChange(uint8_t gpio, GpioEdge edge, bool level) { if(edge == GpioEdge::Rising){ this->btnTimer->RegisterPress((uint8_t)gpio); clog << kLogDebug << " (Button down : " << getBtnName((uint8_t)gpio) << ")" << endl; ButtonDown(getBtnName(gpio)); } else { this->btnTimer->RegisterRelease((uint8_t)gpio); clog << kLogDebug << " (Button up : " << getBtnName((uint8_t)gpio) << ")" << endl; ButtonUp(getBtnName(gpio)); } } bool HidServer::onValidatePress(uint8_t gpio) { // Check if the key is still pressed before sending out a long press return true; //((bool)gpioRead(gpio)) == BUTTONS_ACTIVE.at(gpio); } void HidServer::onShortPress(uint8_t gpio) { clog << kLogDebug << "SHORT PRESS : " << getBtnName(gpio) << endl; ButtonPress(getBtnName(gpio)); } void HidServer::onLongPress(uint8_t gpio) { clog << kLogDebug << "LONG PRESS : " << getBtnName(gpio) << endl; ButtonLongPress(getBtnName(gpio)); } // Convert gpio into a string for ease of use in e.g. python or other dbus bindings std::string HidServer::getBtnName(uint8_t gpio) { return BUTTONS.at(gpio); } DBus::BusDispatcher dispatcher; void niam(int sig) { dispatcher.leave(); } int main() { signal(SIGTERM, niam); signal(SIGINT, niam); signal(2,niam); DBus::default_dispatcher = &dispatcher; // Initialize clog to be redirected to syslog key "mediacore.hid.server" // Log::Init("mediacore.hid"); DBus::Connection conn = DBus::Connection::SystemBus(); conn.request_name(HID_SERVER_NAME); //gpioCfgClock(10,1,0); //gpioInitialise(); HidServer server(conn); dispatcher.enter(); //gpioTerminate(); return 0; }