mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 23:13:16 +02:00
libarmbox: hmdi_cec emit received keys, report power status
Signed-off-by: Thilo Graf <dbt@novatux.de>
This commit is contained in:
@@ -59,6 +59,7 @@
|
||||
})
|
||||
|
||||
#define CEC_DEVICE "/dev/cec0"
|
||||
#define RC_DEVICE "/dev/input/event1"
|
||||
|
||||
hdmi_cec * hdmi_cec::hdmi_cec_instance = NULL;
|
||||
|
||||
@@ -67,7 +68,7 @@ hdmi_cec * CEC = hdmi_cec::getInstance();
|
||||
|
||||
hdmi_cec::hdmi_cec()
|
||||
{
|
||||
standby_cec_activ = autoview_cec_activ = false;
|
||||
standby_cec_activ = autoview_cec_activ = standby = false;
|
||||
hdmiFd = -1;
|
||||
}
|
||||
|
||||
@@ -246,7 +247,8 @@ void hdmi_cec::GetCECAddressInfo()
|
||||
void hdmi_cec::ReportPhysicalAddress()
|
||||
{
|
||||
struct cec_message txmessage;
|
||||
txmessage.address = 0x0f; /* broadcast */
|
||||
txmessage.initiator = logicalAddress;
|
||||
txmessage.destination = CEC_LOG_ADDR_BROADCAST;
|
||||
txmessage.data[0] = CEC_MSG_REPORT_PHYSICAL_ADDR;
|
||||
txmessage.data[1] = physicalAddress[0];
|
||||
txmessage.data[2] = physicalAddress[1];
|
||||
@@ -264,9 +266,9 @@ void hdmi_cec::SendCECMessage(struct cec_message &txmessage)
|
||||
{
|
||||
sprintf(str+(i*6),"[0x%02X]", txmessage.data[i]);
|
||||
}
|
||||
lt_info("[CEC] send message '%s' (%s)\n", ToString((cec_opcode)txmessage.data[0]), str);
|
||||
lt_info("[CEC] send message 0x%02X >> 0x%02X '%s' (%s)\n", txmessage.initiator, txmessage.destination, ToString((cec_opcode)txmessage.data[0]), str);
|
||||
struct cec_msg msg;
|
||||
cec_msg_init(&msg, logicalAddress, txmessage.address);
|
||||
cec_msg_init(&msg, txmessage.initiator, txmessage.destination);
|
||||
memcpy(&msg.msg[1], txmessage.data, txmessage.length);
|
||||
msg.len = txmessage.length + 1;
|
||||
ioctl(hdmiFd, CEC_TRANSMIT, &msg);
|
||||
@@ -287,9 +289,12 @@ void hdmi_cec::SetCECState(bool state)
|
||||
{
|
||||
struct cec_message message;
|
||||
|
||||
standby = state;
|
||||
|
||||
if ((standby_cec_activ) && state)
|
||||
{
|
||||
message.address = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
message.initiator = logicalAddress;
|
||||
message.destination = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
message.data[0] = CEC_MSG_STANDBY;
|
||||
message.length = 1;
|
||||
SendCECMessage(message);
|
||||
@@ -297,12 +302,22 @@ void hdmi_cec::SetCECState(bool state)
|
||||
|
||||
if ((autoview_cec_activ) && !state)
|
||||
{
|
||||
message.address = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
message.initiator = logicalAddress;
|
||||
message.destination = CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM;
|
||||
message.data[0] = CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS;
|
||||
message.length = 1;
|
||||
SendCECMessage(message);
|
||||
usleep(10000);
|
||||
|
||||
message.initiator = logicalAddress;
|
||||
message.destination = CEC_OP_PRIM_DEVTYPE_TV;
|
||||
message.data[0] = CEC_MSG_IMAGE_VIEW_ON;
|
||||
message.length = 1;
|
||||
SendCECMessage(message);
|
||||
usleep(10000);
|
||||
message.address = 0x0f; /* broadcast */
|
||||
|
||||
message.initiator = logicalAddress;
|
||||
message.destination = CEC_LOG_ADDR_BROADCAST;
|
||||
message.data[0] = CEC_MSG_ACTIVE_SOURCE;
|
||||
message.data[1] = physicalAddress[0];
|
||||
message.data[2] = physicalAddress[1];
|
||||
@@ -469,11 +484,15 @@ void hdmi_cec::Receive()
|
||||
{
|
||||
bool hasdata = false;
|
||||
struct cec_message rxmessage;
|
||||
struct cec_message txmessage;
|
||||
|
||||
struct cec_msg msg;
|
||||
if (::ioctl(hdmiFd, CEC_RECEIVE, &msg) >= 0)
|
||||
{
|
||||
rxmessage.length = msg.len - 1;
|
||||
rxmessage.initiator = cec_msg_initiator(&msg);
|
||||
rxmessage.destination = cec_msg_destination(&msg);
|
||||
rxmessage.opcode = cec_msg_opcode(&msg);
|
||||
memcpy(&rxmessage.data, &msg.msg[1], rxmessage.length);
|
||||
hasdata = true;
|
||||
}
|
||||
@@ -488,29 +507,91 @@ void hdmi_cec::Receive()
|
||||
{
|
||||
sprintf(str+(i*6),"[0x%02X]", rxmessage.data[i]);
|
||||
}
|
||||
lt_info("[CEC] received message '%s' (%s)\n", ToString((cec_opcode)rxmessage.data[0]), str);
|
||||
lt_info("[CEC] received message 0x%02X << 0x%02X '%s' (%s)\n", rxmessage.destination, rxmessage.initiator, ToString((cec_opcode)rxmessage.opcode), str);
|
||||
|
||||
switch (rxmessage.data[0])
|
||||
switch (rxmessage.opcode)
|
||||
{
|
||||
case CEC_MSG_DEVICE_VENDOR_ID:
|
||||
case CEC_OPCODE_DEVICE_VENDOR_ID:
|
||||
case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
|
||||
{
|
||||
uint64_t iVendorId = ((uint64_t)rxmessage.data[1] << 16) +
|
||||
((uint64_t)rxmessage.data[2] << 8) +
|
||||
(uint64_t)rxmessage.data[3];
|
||||
lt_info("[CEC] decoded message '%s' (%s)\n", ToString((cec_opcode)rxmessage.data[0]), ToString((cec_vendor_id)iVendorId));
|
||||
lt_info("[CEC] decoded message '%s' (%s)\n", ToString((cec_opcode)rxmessage.opcode), ToString((cec_vendor_id)iVendorId));
|
||||
break;
|
||||
}
|
||||
case CEC_MSG_USER_CONTROL_PRESSED: /* key pressed */
|
||||
case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
|
||||
{
|
||||
txmessage.destination = rxmessage.initiator;
|
||||
txmessage.initiator = rxmessage.destination;
|
||||
txmessage.data[0] = GetResponseOpcode((cec_opcode)rxmessage.opcode);
|
||||
txmessage.data[1] = standby ? CEC_POWER_STATUS_STANDBY : CEC_POWER_STATUS_ON;
|
||||
txmessage.length = 2;
|
||||
SendCECMessage(txmessage);
|
||||
break;
|
||||
}
|
||||
case CEC_OPCODE_USER_CONTROL_PRESSED: /* key pressed */
|
||||
keypressed = true;
|
||||
pressedkey = rxmessage.data[1];
|
||||
case CEC_MSG_USER_CONTROL_RELEASED: /* key released */
|
||||
case CEC_OPCODE_USER_CONTROL_RELEASE: /* key released */
|
||||
{
|
||||
long code = translateKey(pressedkey);
|
||||
if (keypressed)
|
||||
code |= 0x80000000;
|
||||
lt_info("[CEC] decoded key %s (%ld)\n",ToString((cec_user_control_code)pressedkey), code);
|
||||
handleCode(code,keypressed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hdmi_cec::handleCode(long code, bool keypressed)
|
||||
{
|
||||
int evd = open(RC_DEVICE, O_RDWR);
|
||||
if (evd < 0)
|
||||
{
|
||||
perror("opening " RC_DEVICE " failed");
|
||||
return;
|
||||
}
|
||||
if (keypressed)
|
||||
{
|
||||
if (rc_send(evd, code, KEY_PRESSED) < 0)
|
||||
{
|
||||
perror("writing 'KEY_PRESSED' event failed");
|
||||
close(evd);
|
||||
return;
|
||||
}
|
||||
rc_sync(evd);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rc_send(evd, code, KEY_RELEASED) < 0)
|
||||
{
|
||||
perror("writing 'KEY_RELEASED' event failed");
|
||||
close(evd);
|
||||
return;
|
||||
}
|
||||
rc_sync(evd);
|
||||
}
|
||||
close(evd);
|
||||
}
|
||||
|
||||
int hdmi_cec::rc_send(int fd, unsigned int code, unsigned int value)
|
||||
{
|
||||
struct input_event ev;
|
||||
|
||||
ev.type = EV_KEY;
|
||||
ev.code = code;
|
||||
ev.value = value;
|
||||
return write(fd, &ev, sizeof(ev));
|
||||
}
|
||||
|
||||
void hdmi_cec::rc_sync(int fd)
|
||||
{
|
||||
struct input_event ev;
|
||||
|
||||
gettimeofday(&ev.time, NULL);
|
||||
ev.type = EV_SYN;
|
||||
ev.code = SYN_REPORT;
|
||||
ev.value = 0;
|
||||
write(fd, &ev, sizeof(ev));
|
||||
}
|
||||
|
@@ -22,31 +22,13 @@
|
||||
|
||||
#include "video_lib.h"
|
||||
|
||||
#ifndef KEY_OK
|
||||
#define KEY_OK 0x160
|
||||
#endif
|
||||
|
||||
#ifndef KEY_RED
|
||||
#define KEY_RED 0x18e
|
||||
#endif
|
||||
|
||||
#ifndef KEY_GREEN
|
||||
#define KEY_GREEN 0x18f
|
||||
#endif
|
||||
|
||||
#ifndef KEY_YELLOW
|
||||
#define KEY_YELLOW 0x190
|
||||
#endif
|
||||
|
||||
#ifndef KEY_BLUE
|
||||
#define KEY_BLUE 0x191
|
||||
#endif
|
||||
|
||||
struct cec_message
|
||||
{
|
||||
unsigned char address;
|
||||
unsigned char length;
|
||||
unsigned char initiator;
|
||||
unsigned char destination;
|
||||
unsigned char opcode;
|
||||
unsigned char data[256];
|
||||
unsigned char length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct addressinfo
|
||||
@@ -56,6 +38,12 @@ struct addressinfo
|
||||
unsigned char type;
|
||||
};
|
||||
|
||||
enum {
|
||||
KEY_RELEASED = 0,
|
||||
KEY_PRESSED,
|
||||
KEY_AUTOREPEAT
|
||||
};
|
||||
|
||||
class hdmi_cec : public OpenThreads::Thread
|
||||
{
|
||||
private:
|
||||
@@ -70,6 +58,10 @@ private:
|
||||
unsigned char deviceType, logicalAddress;
|
||||
int hdmiFd;
|
||||
long translateKey(unsigned char code);
|
||||
void handleCode(long code, bool keypressed);
|
||||
int rc_send(int fd, unsigned int code, unsigned int value);
|
||||
void rc_sync(int fd);
|
||||
bool standby;
|
||||
protected:
|
||||
bool running;
|
||||
public:
|
||||
|
@@ -207,6 +207,37 @@ typedef enum cec_opcode
|
||||
CEC_OPCODE_NONE = 0xFD
|
||||
} cec_opcode;
|
||||
|
||||
typedef enum cec_logical_address
|
||||
{
|
||||
CECDEVICE_UNKNOWN = -1, //not a valid logical address
|
||||
CECDEVICE_TV = 0,
|
||||
CECDEVICE_RECORDINGDEVICE1 = 1,
|
||||
CECDEVICE_RECORDINGDEVICE2 = 2,
|
||||
CECDEVICE_TUNER1 = 3,
|
||||
CECDEVICE_PLAYBACKDEVICE1 = 4,
|
||||
CECDEVICE_AUDIOSYSTEM = 5,
|
||||
CECDEVICE_TUNER2 = 6,
|
||||
CECDEVICE_TUNER3 = 7,
|
||||
CECDEVICE_PLAYBACKDEVICE2 = 8,
|
||||
CECDEVICE_RECORDINGDEVICE3 = 9,
|
||||
CECDEVICE_TUNER4 = 10,
|
||||
CECDEVICE_PLAYBACKDEVICE3 = 11,
|
||||
CECDEVICE_RESERVED1 = 12,
|
||||
CECDEVICE_RESERVED2 = 13,
|
||||
CECDEVICE_FREEUSE = 14,
|
||||
CECDEVICE_UNREGISTERED = 15,
|
||||
CECDEVICE_BROADCAST = 15
|
||||
} cec_logical_address;
|
||||
|
||||
typedef enum cec_power_status
|
||||
{
|
||||
CEC_POWER_STATUS_ON = 0x00,
|
||||
CEC_POWER_STATUS_STANDBY = 0x01,
|
||||
CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON = 0x02,
|
||||
CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY = 0x03,
|
||||
CEC_POWER_STATUS_UNKNOWN = 0x99
|
||||
} cec_power_status;
|
||||
|
||||
static const char *ToString(const cec_opcode opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
@@ -598,3 +629,40 @@ static const char *ToString(const cec_user_control_code key)
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static cec_opcode GetResponseOpcode(cec_opcode opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
|
||||
return CEC_OPCODE_ACTIVE_SOURCE;
|
||||
case CEC_OPCODE_GET_CEC_VERSION:
|
||||
return CEC_OPCODE_CEC_VERSION;
|
||||
case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
|
||||
return CEC_OPCODE_REPORT_PHYSICAL_ADDRESS;
|
||||
case CEC_OPCODE_GET_MENU_LANGUAGE:
|
||||
return CEC_OPCODE_SET_MENU_LANGUAGE;
|
||||
case CEC_OPCODE_GIVE_DECK_STATUS:
|
||||
return CEC_OPCODE_DECK_STATUS;
|
||||
case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
|
||||
return CEC_OPCODE_TUNER_DEVICE_STATUS;
|
||||
case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
|
||||
return CEC_OPCODE_DEVICE_VENDOR_ID;
|
||||
case CEC_OPCODE_GIVE_OSD_NAME:
|
||||
return CEC_OPCODE_SET_OSD_NAME;
|
||||
case CEC_OPCODE_MENU_REQUEST:
|
||||
return CEC_OPCODE_MENU_STATUS;
|
||||
case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
|
||||
return CEC_OPCODE_REPORT_POWER_STATUS;
|
||||
case CEC_OPCODE_GIVE_AUDIO_STATUS:
|
||||
return CEC_OPCODE_REPORT_AUDIO_STATUS;
|
||||
case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
|
||||
return CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS;
|
||||
case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
|
||||
return CEC_OPCODE_SET_SYSTEM_AUDIO_MODE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CEC_OPCODE_NONE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user