1
0
Fork 0
caffyBoot/BerrybootGUI2.0/ceclistener.cpp

179 lines
5.3 KiB
C++

/* Berryboot -- CEC listener thread
*
* Copyright (c) 2012, Floris Bos
* 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 OWNER 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.
*/
#include "ceclistener.h"
#include <QDebug>
#ifdef RASPBERRY_CEC_SUPPORT
extern "C" {
#include <interface/vmcs_host/vc_cecservice.h>
#include <interface/vchiq_arm/vchiq_if.h>
#include <interface/vmcs_host/vc_tvservice.h>
}
#endif
CecListener::CecListener(QObject *parent) :
QThread(parent)
{
}
CecListener::~CecListener()
{
_waitcond.wakeAll();
if (!wait(2000))
{
qDebug() << "CEC thread did not stop gracefully";
terminate();
}
}
/* Not sure if any of the vchi functions are blocking, but running them in a seperate thread just in case */
void CecListener::run()
{
#ifdef RASPBERRY_CEC_SUPPORT
VCHI_INSTANCE_T vchiq;
VCHI_CONNECTION_T *conn;
uint16_t physaddr;
CEC_AllDevices_T logaddr;
QMutex mutex;
mutex.lock();
qDebug() << "CecListener thread started";
if (vchi_initialise(&vchiq))
{
qDebug() << "Error during vchi_initialise()";
return;
}
if (vchi_connect(NULL, 0, vchiq))
{
qDebug() << "Error connecting to vchi";
return;
}
if (vc_vchi_tv_init(vchiq, &conn, 1))
{
qDebug() << "Error during vc_vchi_tv_init()";
return;
}
TV_GET_STATE_RESP_T tvstate;
vc_tv_get_state(&tvstate);
if (!(tvstate.state & (VC_HDMI_STANDBY | VC_HDMI_HDMI)))
{
qDebug() << "Not in HDMI mode";
return;
}
vc_vchi_cec_init(vchiq, &conn, 1);
vc_cec_set_osd_name("BerryBoot");
vc_cec_register_callback(_cec_callback, this);
vc_tv_register_callback(_tv_callback, this);
vc_cec_get_logical_address(&logaddr);
if (logaddr == 0xF)
{
qDebug() << "CEC not initialized yet. Doing now";
vc_cec_set_passive(false);
vc_cec_alloc_logical_address();
QThread::sleep(1);
vc_cec_get_physical_address(&physaddr);
vc_cec_send_ReportPhysicalAddress(physaddr, CEC_DeviceType_Rec, false);
}
qDebug() << "CecListener done initializing";
/* Wait until we are signaled to quit */
_waitcond.wait(&mutex);
vc_vchi_cec_stop();
#endif
}
/*static*/ void CecListener::_cec_callback(void *userptr, uint32_t reason, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4)
{
static_cast<CecListener *>(userptr)->cec_callback(reason, param1, param2, param3, param4);
}
void CecListener::cec_callback(uint32_t reason, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4)
{
#ifdef RASPBERRY_CEC_SUPPORT
if (CEC_CB_REASON(reason) == VC_CEC_BUTTON_PRESSED)
{
int c = 0;
int cec_buttoncode = CEC_CB_OPERAND1(param1);
qDebug() << "CEC button press code:" << cec_buttoncode;
/* Translate to Qt key value */
switch (cec_buttoncode)
{
case CEC_User_Control_Select:
c = Qt::Key_Enter;
break;
case CEC_User_Control_Up:
c = Qt::Key_Up;
break;
case CEC_User_Control_Down:
c = Qt::Key_Down;
break;
case CEC_User_Control_Left:
c = Qt::Key_Left;
break;
case CEC_User_Control_Right:
c = Qt::Key_Right;
break;
case CEC_User_Control_Exit:
c = Qt::Key_Escape;
break;
case CEC_User_Control_F2Red:
c = Qt::Key_F1;
break;
default:
break;
}
if (c)
emit keyPress(c);
}
else
{
qDebug() << "CEC:" << CEC_CB_REASON(reason) << param1 << param2 << param3 << param4;
}
#else
qDebug() << "CEC:" << reason << param1;
#endif
}
/*static*/ void CecListener::_tv_callback(void *userptr, uint32_t reason, uint32_t param1, uint32_t param2)
{
static_cast<CecListener *>(userptr)->tv_callback(reason, param1, param2);
}
void CecListener::tv_callback(uint32_t reason, uint32_t param1, uint32_t param2)
{
qDebug() << "TV:" << reason << param1 << param2;
}