libarmbox: hmdi_cec emit received keys, report power status

Origin commit data
------------------
Branch: master
Commit: 4bf182cb85
Author: TangoCash <eric@loxat.de>
Date: 2018-10-09 (Tue, 09 Oct 2018)


------------------
No further description and justification available within origin commit message!

------------------
This commit was generated by Migit
This commit is contained in:
TangoCash
2018-10-09 22:11:01 +02:00
committed by max_10
parent 1e4089ddfe
commit 54cde341e6
3 changed files with 180 additions and 39 deletions

View File

@@ -59,6 +59,7 @@
}) })
#define CEC_DEVICE "/dev/cec0" #define CEC_DEVICE "/dev/cec0"
#define RC_DEVICE "/dev/input/event1"
hdmi_cec * hdmi_cec::hdmi_cec_instance = NULL; hdmi_cec * hdmi_cec::hdmi_cec_instance = NULL;
@@ -67,7 +68,7 @@ hdmi_cec * CEC = hdmi_cec::getInstance();
hdmi_cec::hdmi_cec() hdmi_cec::hdmi_cec()
{ {
standby_cec_activ = autoview_cec_activ = false; standby_cec_activ = autoview_cec_activ = standby = false;
hdmiFd = -1; hdmiFd = -1;
} }
@@ -246,7 +247,8 @@ void hdmi_cec::GetCECAddressInfo()
void hdmi_cec::ReportPhysicalAddress() void hdmi_cec::ReportPhysicalAddress()
{ {
struct cec_message txmessage; 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[0] = CEC_MSG_REPORT_PHYSICAL_ADDR;
txmessage.data[1] = physicalAddress[0]; txmessage.data[1] = physicalAddress[0];
txmessage.data[2] = physicalAddress[1]; 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]); 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; 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); memcpy(&msg.msg[1], txmessage.data, txmessage.length);
msg.len = txmessage.length + 1; msg.len = txmessage.length + 1;
ioctl(hdmiFd, CEC_TRANSMIT, &msg); ioctl(hdmiFd, CEC_TRANSMIT, &msg);
@@ -287,9 +289,12 @@ void hdmi_cec::SetCECState(bool state)
{ {
struct cec_message message; struct cec_message message;
standby = state;
if ((standby_cec_activ) && 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.data[0] = CEC_MSG_STANDBY;
message.length = 1; message.length = 1;
SendCECMessage(message); SendCECMessage(message);
@@ -297,12 +302,22 @@ void hdmi_cec::SetCECState(bool state)
if ((autoview_cec_activ) && !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.data[0] = CEC_MSG_IMAGE_VIEW_ON;
message.length = 1; message.length = 1;
SendCECMessage(message); SendCECMessage(message);
usleep(10000); usleep(10000);
message.address = 0x0f; /* broadcast */
message.initiator = logicalAddress;
message.destination = CEC_LOG_ADDR_BROADCAST;
message.data[0] = CEC_MSG_ACTIVE_SOURCE; message.data[0] = CEC_MSG_ACTIVE_SOURCE;
message.data[1] = physicalAddress[0]; message.data[1] = physicalAddress[0];
message.data[2] = physicalAddress[1]; message.data[2] = physicalAddress[1];
@@ -469,11 +484,15 @@ void hdmi_cec::Receive()
{ {
bool hasdata = false; bool hasdata = false;
struct cec_message rxmessage; struct cec_message rxmessage;
struct cec_message txmessage;
struct cec_msg msg; struct cec_msg msg;
if (::ioctl(hdmiFd, CEC_RECEIVE, &msg) >= 0) if (::ioctl(hdmiFd, CEC_RECEIVE, &msg) >= 0)
{ {
rxmessage.length = msg.len - 1; 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); memcpy(&rxmessage.data, &msg.msg[1], rxmessage.length);
hasdata = true; hasdata = true;
} }
@@ -488,29 +507,91 @@ void hdmi_cec::Receive()
{ {
sprintf(str+(i*6),"[0x%02X]", rxmessage.data[i]); 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 iVendorId = ((uint64_t)rxmessage.data[1] << 16) +
((uint64_t)rxmessage.data[2] << 8) + ((uint64_t)rxmessage.data[2] << 8) +
(uint64_t)rxmessage.data[3]; (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; 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; keypressed = true;
pressedkey = rxmessage.data[1]; pressedkey = rxmessage.data[1];
case CEC_MSG_USER_CONTROL_RELEASED: /* key released */ case CEC_OPCODE_USER_CONTROL_RELEASE: /* key released */
{ {
long code = translateKey(pressedkey); long code = translateKey(pressedkey);
if (keypressed)
code |= 0x80000000;
lt_info("[CEC] decoded key %s (%ld)\n",ToString((cec_user_control_code)pressedkey), code); lt_info("[CEC] decoded key %s (%ld)\n",ToString((cec_user_control_code)pressedkey), code);
handleCode(code,keypressed);
break; 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));
}

View File

@@ -22,31 +22,13 @@
#include "video_lib.h" #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 struct cec_message
{ {
unsigned char address; unsigned char initiator;
unsigned char length; unsigned char destination;
unsigned char opcode;
unsigned char data[256]; unsigned char data[256];
unsigned char length;
} __attribute__((packed)); } __attribute__((packed));
struct addressinfo struct addressinfo
@@ -56,6 +38,12 @@ struct addressinfo
unsigned char type; unsigned char type;
}; };
enum {
KEY_RELEASED = 0,
KEY_PRESSED,
KEY_AUTOREPEAT
};
class hdmi_cec : public OpenThreads::Thread class hdmi_cec : public OpenThreads::Thread
{ {
private: private:
@@ -70,6 +58,10 @@ private:
unsigned char deviceType, logicalAddress; unsigned char deviceType, logicalAddress;
int hdmiFd; int hdmiFd;
long translateKey(unsigned char code); 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: protected:
bool running; bool running;
public: public:

View File

@@ -207,6 +207,37 @@ typedef enum cec_opcode
CEC_OPCODE_NONE = 0xFD CEC_OPCODE_NONE = 0xFD
} cec_opcode; } 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) static const char *ToString(const cec_opcode opcode)
{ {
switch (opcode) switch (opcode)
@@ -598,3 +629,40 @@ static const char *ToString(const cec_user_control_code key)
return "unknown"; 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;
}