Skip to content

Commit

Permalink
Added CEC
Browse files Browse the repository at this point in the history
  • Loading branch information
procount committed Jan 3, 2017
1 parent 1500f48 commit 6d65e84
Show file tree
Hide file tree
Showing 17 changed files with 1,039 additions and 496 deletions.
537 changes: 47 additions & 490 deletions README.md

Large diffs are not rendered by default.

543 changes: 543 additions & 0 deletions README_PINN.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions README_SUM.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ PINN is a version of the NOOBS Operating System Installer for the Raspberry Pi w

## Change History

### V2.1.1c

- **CEC Support** - Added CEC support to control PINN with a TV remote

### V2.1

- **IoTpHAT support** - Updated to match NOOBS v2.1 for IoTpHAT wifi
Expand Down
4 changes: 4 additions & 0 deletions buildroot/package/recovery/recovery.mk
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ define RECOVERY_INSTALL_TARGET_CMDS
$(INSTALL) -m 0755 package/recovery/unicode-fonts/DejaVuSans-Bold.ttf $(TARGET_DIR)/usr/lib/fonts/DejaVuSans-Bold.ttf
$(INSTALL) -m 0755 package/recovery/unicode-fonts/DroidSansJapanese.ttf $(TARGET_DIR)/usr/lib/fonts/DroidSansJapanese.ttf
$(INSTALL) -m 0755 package/recovery/data/data $(TARGET_DIR)/usr/data
#Copy libs for CEC
#$(INSTALL) -m 0777 package/recovery/libs/libbcm_host.so $(TARGET_DIR)/usr/lib
#$(INSTALL) -m 0777 package/recovery/libs/libdl.so.2 $(TARGET_DIR)/usr/lib
#
$(INSTALL) -m 0644 $(@D)/cmdline.txt $(BINARIES_DIR)/cmdline.txt
mkdir -p $(TARGET_DIR)/keymaps/
$(INSTALL) -m 0755 package/recovery/keymaps/* $(TARGET_DIR)/keymaps/
Expand Down
1 change: 1 addition & 0 deletions buildroot/package/rpi-userland/rpi-userland.mk
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ endif
define RPI_USERLAND_INSTALL_TARGET_CMDS
$(INSTALL) -m 0755 $(STAGING_DIR)/usr/lib/libvchiq_arm.so $(TARGET_DIR)/usr/lib
$(INSTALL) -m 0755 $(STAGING_DIR)/usr/lib/libvcos.so $(TARGET_DIR)/usr/lib
$(INSTALL) -m 0755 $(STAGING_DIR)/usr/lib/libbcm_host.so $(TARGET_DIR)/usr/lib
$(INSTALL) -m 0755 $(STAGING_DIR)/usr/lib/libvchostif.so $(TARGET_DIR)/usr/lib
$(INSTALL) -m 0755 $(STAGING_DIR)/usr/lib/libvcfiled_check.so $(TARGET_DIR)/usr/lib
$(INSTALL) -m 0755 $(STAGING_DIR)/usr/bin/tvservice $(TARGET_DIR)/usr/bin
Expand Down
4 changes: 4 additions & 0 deletions changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,7 @@ Linux Kernel and rpi-firmware updated to match NOOBS v2.0

Updated to match NOOBS v2.1
Now supports the IoTpHAT wifi.

#V2.1.1c Features

Added CEC support
4 changes: 4 additions & 0 deletions history.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ PINN is a version of the NOOBS Operating System Installer for the Raspberry Pi w

## Change History

### V2.1.1c

- **CEC Support** - Added CEC support for controlling PINN with a TV remote

### V2.1

- **IoTpHAT support** - Updated to match NOOBS v2.1 to include IoTpHAT wifi
Expand Down
88 changes: 86 additions & 2 deletions recovery/bootselectiondialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
#include "config.h"
#include "json.h"
#include "util.h"
#include "ceclistener.h"
#include <QDebug>
#include <unistd.h>
#include <QDir>
#include <QMessageBox>

#include <QProcess>
#include <QListWidgetItem>
#include <QPushButton>
Expand All @@ -24,6 +27,16 @@
#include <QScreen>
#include <QWSServer>
#include <QDebug>
#include <QMouseEvent>

#ifdef RASPBERRY_CEC_SUPPORT
extern "C" {
#include <interface/vmcs_host/vc_cecservice.h>
}
#endif


extern CecListener * cec;

BootSelectionDialog::BootSelectionDialog(const QString &defaultPartition, bool dsi=false, QWidget *parent) :
QDialog(parent),
Expand All @@ -36,7 +49,6 @@ BootSelectionDialog::BootSelectionDialog(const QString &defaultPartition, bool d
QRect s = QApplication::desktop()->screenGeometry();
if (s.height() < 500)
resize(s.width()-10, s.height()-100);

QDir dir;
dir.mkdir("/settings");
if (QProcess::execute("mount -o remount,ro /settings") != 0
Expand All @@ -46,6 +58,9 @@ BootSelectionDialog::BootSelectionDialog(const QString &defaultPartition, bool d
return;
}

connect(cec, SIGNAL(keyPress(int)), this, SLOT(onKeyPress(int)));


/* Also mount /dev/mmcblk0p1 as it may contain icons we need */
if (QProcess::execute("mount -t vfat -o ro /dev/mmcblk0p1 /mnt") != 0)
{
Expand Down Expand Up @@ -96,6 +111,7 @@ BootSelectionDialog::BootSelectionDialog(const QString &defaultPartition, bool d

if (partition != 800)
{
cec->clearKeyPressed();
// Start timer
qDebug() << "Starting 10 second timer before booting into partition" << partition;
_timer.setInterval(1000);
Expand Down Expand Up @@ -237,7 +253,8 @@ void BootSelectionDialog::setDisplayMode()

bool BootSelectionDialog::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress || event->type() == QEvent::MouseButtonPress)
qDebug() << event->type();
if (event->type() == QEvent::KeyPress || event->type() == QEvent::MouseButtonPress || event->type() == QEvent::Enter)
{
stopCountdown();
}
Expand All @@ -254,6 +271,8 @@ void BootSelectionDialog::stopCountdown()
void BootSelectionDialog::countdown()
{
setWindowTitle(tr("Previously selected OS will boot in %1 seconds").arg(--_countdown));
if (cec->hasKeyPressed())
stopCountdown();
if (_countdown == 0)
{
_timer.stop();
Expand Down Expand Up @@ -300,3 +319,68 @@ void BootSelectionDialog::updateConfig4dsi(QByteArray partition)
sync();
QProcess::execute("umount "+partstr);
}

/* Key on TV remote pressed */
void BootSelectionDialog::onKeyPress(int cec_code)
{
#ifdef Q_WS_QWS
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
int key=0;
QPoint p = QCursor::pos();
switch (cec_code)
{
/* MOUSE SIMULATION */
case CEC_User_Control_Select:
{
QWidget* widget = dynamic_cast<QWidget*>(QApplication::widgetAt(QCursor::pos()));
QPoint pos = QCursor::pos();
QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress,widget->mapFromGlobal(pos), Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);
QCoreApplication::sendEvent(widget,event);
QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonRelease,widget->mapFromGlobal(pos), Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);
QCoreApplication::sendEvent(widget,event1);
qApp->processEvents();
}
case CEC_User_Control_Left:
p.rx()-=10;
QCursor::setPos(p);
break;
case CEC_User_Control_Right:
p.rx()+=10;
QCursor::setPos(p);
break;
case CEC_User_Control_Up:
p.ry()-=10;
QCursor::setPos(p);
break;
case CEC_User_Control_Down:
p.ry()+=10;
QCursor::setPos(p);
break;
/* ARROW KEY SIMULATION */
case CEC_User_Control_Number0:
key = Qt::Key_Enter;
break;
case CEC_User_Control_Exit:
key = Qt::Key_Escape;
break;
case CEC_User_Control_ChannelUp:
key = Qt::Key_Up;
break;
case CEC_User_Control_ChannelDown:
key = Qt::Key_Down;
break;
default:
break;
}

if (key)
{
// key press
QWSServer::sendKeyEvent(0, key, modifiers, true, false);
// key release
QWSServer::sendKeyEvent(0, key, modifiers, false, false);
}
#else
qDebug() << "onKeyPress" << key;
#endif
}
1 change: 1 addition & 0 deletions recovery/bootselectiondialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class BootSelectionDialog : public QDialog
protected slots:
void countdown();
void bootPartition();
void onKeyPress(int);

private slots:
void on_list_activated(const QModelIndex &index);
Expand Down
123 changes: 123 additions & 0 deletions recovery/ceclistener.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/* 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>
#include <QWSServer>

#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

int CecListener::keyPressed = 0;

CecListener::CecListener(QObject *parent) :
QThread(parent)
{
keyPressed=0;
}

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;
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("PINN");
vc_cec_register_callback(_cec_callback, this);

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, uint32_t, uint32_t)
{
#ifdef RASPBERRY_CEC_SUPPORT
if (CEC_CB_REASON(reason) == VC_CEC_BUTTON_PRESSED)
{
int c = 0;
int cec_buttoncode = CEC_CB_OPERAND1(param1);
keyPressed=1;

emit keyPress(cec_buttoncode);
}
#else
qDebug() << "CEC:" << reason << param1;
#endif
}
59 changes: 59 additions & 0 deletions recovery/ceclistener.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifndef CECLISTENER_H
#define CECLISTENER_H

/* Berryboot -- CEC handling 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 <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <stdint.h>



class CecListener : public QThread
{
Q_OBJECT
public:
explicit CecListener(QObject *parent = 0);
virtual ~CecListener();
static int hasKeyPressed() {return(keyPressed);}
static int clearKeyPressed() {keyPressed=0;}

signals:
void keyPress(int key);
public slots:

protected:
virtual void run();
static void _cec_callback(void *userptr, uint32_t reason, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4);
void cec_callback(uint32_t reason, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4);

QWaitCondition _waitcond;
static int keyPressed;
};

#endif // CECLISTENER_H
2 changes: 1 addition & 1 deletion recovery/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define CONFIG_H

/* Version number displayed in the title bar */
#define VERSION_NUMBER "2.1"
#define VERSION_NUMBER "2.1.1"

/* Color of the background */
// #define BACKGROUND_COLOR Qt::white
Expand Down
Loading

0 comments on commit 6d65e84

Please sign in to comment.