From 54cde341e6590c9951bcfeabac9819fb0a3615a3 Mon Sep 17 00:00:00 2001 From: TangoCash Date: Tue, 9 Oct 2018 22:11:01 +0200 Subject: [PATCH] libarmbox: hmdi_cec emit received keys, report power status Origin commit data ------------------ Branch: master Commit: https://github.com/neutrino-images/ni-libstb-hal/commit/4bf182cb85e54698fec27e876994386dbe2a9f9a Author: TangoCash Date: 2018-10-09 (Tue, 09 Oct 2018) ------------------ No further description and justification available within origin commit message! ------------------ This commit was generated by Migit --- libarmbox/hdmi_cec.cpp | 115 +++++++++++++++++++++++++++++++------ libarmbox/hdmi_cec.h | 36 +++++------- libarmbox/hdmi_cec_types.h | 68 ++++++++++++++++++++++ 3 files changed, 180 insertions(+), 39 deletions(-) diff --git a/libarmbox/hdmi_cec.cpp b/libarmbox/hdmi_cec.cpp index cc4db35..a30e115 100644 --- a/libarmbox/hdmi_cec.cpp +++ b/libarmbox/hdmi_cec.cpp @@ -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)); + ((uint64_t)rxmessage.data[2] << 8) + + (uint64_t)rxmessage.data[3]; + 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)); +} diff --git a/libarmbox/hdmi_cec.h b/libarmbox/hdmi_cec.h index 9654e73..65604d7 100644 --- a/libarmbox/hdmi_cec.h +++ b/libarmbox/hdmi_cec.h @@ -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: diff --git a/libarmbox/hdmi_cec_types.h b/libarmbox/hdmi_cec_types.h index f5808af..beb3e4f 100644 --- a/libarmbox/hdmi_cec_types.h +++ b/libarmbox/hdmi_cec_types.h @@ -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; +}