cec: added CEC command that were received by the adapter in a buffer that can be...
authorLars Op den Kamp <lars@opdenkamp.eu>
Thu, 29 Sep 2011 19:53:47 +0000 (21:53 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Thu, 29 Sep 2011 19:56:27 +0000 (21:56 +0200)
include/CECExports.h
include/CECExportsC.h
include/CECExportsCpp.h
include/CECTypes.h
src/lib/CECParser.cpp
src/lib/CECParser.h
src/lib/CECParserC.cpp
src/lib/util/buffer.h
src/testclient/main.cpp

index ad1eb969fb4225c84468edebb8f437f65c0c2812..0aef25c30723e72e5b32fa177a1aeaf86b02e775 100644 (file)
@@ -167,6 +167,72 @@ namespace CEC {
     CECDEVICE_BROADCAST = 15
   } cec_logical_address;
 
+  typedef enum cec_opcode
+  {
+    CEC_OPCODE_ACTIVE_SOURCE = 0x82,
+    CEC_OPCODE_IMAGE_VIEW_ON = 0x04,
+    CEC_OPCODE_TEXT_VIEW_ON = 0x0D,
+    CEC_OPCODE_INACTIVE_SOURCE = 0x9D,
+    CEC_OPCODE_REQUEST_ACTIVE_SOURCE = 0x85,
+    CEC_OPCODE_ROUTING_CHANGE = 0x80,
+    CEC_OPCODE_ROUTING_INFORMATION = 0x81,
+    CEC_OPCODE_SET_STREAM_PATH = 0x86,
+    CEC_OPCODE_STANDBY = 0x36,
+    CEC_OPCODE_RECORD_OFF = 0x0B,
+    CEC_OPCODE_RECORD_ON = 0x09,
+    CEC_OPCODE_RECORD_STATUS = 0x0A,
+    CEC_OPCODE_RECORD_TV_SCREEN = 0x0F,
+    CEC_OPCODE_CLEAR_ANALOGUE_TIMER = 0x33,
+    CEC_OPCODE_CLEAR_DIGITAL_TIMER = 0x99,
+    CEC_OPCODE_CLEAR_EXTERNAL_TIMER = 0xA1,
+    CEC_OPCODE_SET_ANALOGUE_TIMER = 0x34,
+    CEC_OPCODE_SET_DIGITAL_TIMER = 0x97,
+    CEC_OPCODE_SET_EXTERNAL_TIMER = 0xA2,
+    CEC_OPCODE_SET_TIMER_PROGRAM_TITLE = 0x67,
+    CEC_OPCODE_TIMER_CLEARED_STATUS = 0x43,
+    CEC_OPCODE_TIMER_STATUS = 0x35,
+    CEC_OPCODE_CEC_VERSION = 0x9E,
+    CEC_OPCODE_GET_CEC_VERSION = 0x9F,
+    CEC_OPCODE_GIVE_PHYSICAL_ADDRESS = 0x83,
+    CEC_OPCODE_GET_MENU_LANGUAGE = 0x91,
+    CEC_OPCODE_REPORT_PHYSICAL_ADDRESS = 0x84,
+    CEC_OPCODE_SET_MENU_LANGUAGE = 0x32,
+    CEC_OPCODE_DECK_CONTROL = 0x42,
+    CEC_OPCODE_DECK_STATUS = 0x1B,
+    CEC_OPCODE_GIVE_DECK_STATUS = 0x1A,
+    CEC_OPCODE_PLAY = 0x41,
+    CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS = 0x08,
+    CEC_OPCODE_SELECT_ANALOGUE_SERVICE = 0x92,
+    CEC_OPCODE_SELECT_DIGITAL_SERVICE = 0x93,
+    CEC_OPCODE_TUNER_DEVICE_STATUS = 0x07,
+    CEC_OPCODE_TUNER_STEP_DECREMENT = 0x06,
+    CEC_OPCODE_TUNER_STEP_INCREMENT = 0x05,
+    CEC_OPCODE_DEVICE_VENDOR_ID = 0x87,
+    CEC_OPCODE_GIVE_DEVICE_VENDOR_ID = 0x8C,
+    CEC_OPCODE_VENDOR_COMMAND = 0x89,
+    CEC_OPCODE_VENDOR_COMMAND_WITH_ID = 0xA0,
+    CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A,
+    CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP = 0x8B,
+    CEC_OPCODE_SET_OSD_STRING = 0x64,
+    CEC_OPCODE_GIVE_OSD_NAME = 0x46,
+    CEC_OPCODE_SET_OSD_NAME = 0x47,
+    CEC_OPCODE_MENU_REQUEST = 0x8D,
+    CEC_OPCODE_MENU_STATUS = 0x8E,
+    CEC_OPCODE_USER_CONTROL_PRESSED = 0x44,
+    CEC_OPCODE_USER_CONTROL_RELEASE = 0x45,
+    CEC_OPCODE_GIVE_DEVICE_POWER_STATUS = 0x8F,
+    CEC_OPCODE_REPORT_POWER_STATUS = 0x90,
+    CEC_OPCODE_FEATURE_ABORT = 0x00,
+    CEC_OPCODE_ABORT = 0xFF,
+    CEC_OPCODE_GIVE_AUDIO_STATUS = 0x71,
+    CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D,
+    CEC_OPCODE_REPORT_AUDIO_STATUS = 0x7A,
+    CEC_OPCODE_SET_SYSTEM_AUDIO_MODE = 0x72,
+    CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST = 0x70,
+    CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS = 0x7E,
+    CEC_OPCODE_SET_AUDIO_RATE = 0x9A
+  } cec_opcode;
+
   typedef enum cec_log_level
   {
     CEC_LOG_DEBUG = 0,
@@ -193,6 +259,14 @@ namespace CEC {
     std::string comm;
   } cec_device;
 
+  typedef struct cec_command
+  {
+    cec_logical_address source;
+    cec_logical_address destination;
+    cec_opcode          opcode;
+    cec_frame           parameters;
+  } cec_command;
+
   //default physical address 1.0.0.0
   #define CEC_DEFAULT_PHYSICAL_ADDRESS 0x1000
 
index 6fa4dbeebc6115f991a65040a4770d68d56c9bbf..5d278f4c63dcae14b3cc3fe4ebc4b48f84f72a7d 100644 (file)
@@ -145,6 +145,17 @@ extern DECLSPEC bool cec_get_next_keypress(CEC::cec_keypress *key);
 extern DECLSPEC bool cec_get_next_keypress(cec_keypress *key);
 #endif
 
+/*!
+ * @brief Get the next CEC command that was received by the adapter.
+ * @param action The next command.
+ * @return True when a command was passed, false otherwise.
+ */
+#ifdef __cplusplus
+extern DECLSPEC bool cec_get_next_command(CEC::cec_command *command);
+#else
+extern DECLSPEC bool cec_get_next_command(cec_command *command);
+#endif
+
 /*!
  * @brief Transmit a frame on the CEC line.
  * @param data The frame to send.
index ec69a4bb8e946bb7e8c4a2643a901eff6c470fff..fd4ea9fa078c8f99501c93930ffa7d3230c73826 100644 (file)
@@ -91,6 +91,11 @@ namespace CEC
      */
     virtual bool GetNextKeypress(cec_keypress *key) = 0;
 
+    /*!
+     * @see cec_get_next_command
+     */
+    virtual bool GetNextCommand(cec_command *command) = 0;
+
     /*!
      * @see cec_transmit
      */
index 5b8ef2b5f10a8b2ed70b6b009b75315f3a842122..3518d20a61236d41179a699c70526d907146b131 100644 (file)
 #include <string>
 #include "CECExports.h"
 
-typedef enum
-{
-  CEC_OPCODE_ACTIVE_SOURCE = 0x82,
-  CEC_OPCODE_IMAGE_VIEW_ON = 0x04,
-  CEC_OPCODE_TEXT_VIEW_ON = 0x0D,
-  CEC_OPCODE_INACTIVE_SOURCE = 0x9D,
-  CEC_OPCODE_REQUEST_ACTIVE_SOURCE = 0x85,
-  CEC_OPCODE_ROUTING_CHANGE = 0x80,
-  CEC_OPCODE_ROUTING_INFORMATION = 0x81,
-  CEC_OPCODE_SET_STREAM_PATH = 0x86,
-  CEC_OPCODE_STANDBY = 0x36,
-  CEC_OPCODE_RECORD_OFF = 0x0B,
-  CEC_OPCODE_RECORD_ON = 0x09,
-  CEC_OPCODE_RECORD_STATUS = 0x0A,
-  CEC_OPCODE_RECORD_TV_SCREEN = 0x0F,
-  CEC_OPCODE_CLEAR_ANALOGUE_TIMER = 0x33,
-  CEC_OPCODE_CLEAR_DIGITAL_TIMER = 0x99,
-  CEC_OPCODE_CLEAR_EXTERNAL_TIMER = 0xA1,
-  CEC_OPCODE_SET_ANALOGUE_TIMER = 0x34,
-  CEC_OPCODE_SET_DIGITAL_TIMER = 0x97,
-  CEC_OPCODE_SET_EXTERNAL_TIMER = 0xA2,
-  CEC_OPCODE_SET_TIMER_PROGRAM_TITLE = 0x67,
-  CEC_OPCODE_TIMER_CLEARED_STATUS = 0x43,
-  CEC_OPCODE_TIMER_STATUS = 0x35,
-  CEC_OPCODE_CEC_VERSION = 0x9E,
-  CEC_OPCODE_GET_CEC_VERSION = 0x9F,
-  CEC_OPCODE_GIVE_PHYSICAL_ADDRESS = 0x83,
-  CEC_OPCODE_GET_MENU_LANGUAGE = 0x91,
-  CEC_OPCODE_REPORT_PHYSICAL_ADDRESS = 0x84,
-  CEC_OPCODE_SET_MENU_LANGUAGE = 0x32,
-  CEC_OPCODE_DECK_CONTROL = 0x42,
-  CEC_OPCODE_DECK_STATUS = 0x1B,
-  CEC_OPCODE_GIVE_DECK_STATUS = 0x1A,
-  CEC_OPCODE_PLAY = 0x41,
-  CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS = 0x08,
-  CEC_OPCODE_SELECT_ANALOGUE_SERVICE = 0x92,
-  CEC_OPCODE_SELECT_DIGITAL_SERVICE = 0x93,
-  CEC_OPCODE_TUNER_DEVICE_STATUS = 0x07,
-  CEC_OPCODE_TUNER_STEP_DECREMENT = 0x06,
-  CEC_OPCODE_TUNER_STEP_INCREMENT = 0x05,
-  CEC_OPCODE_DEVICE_VENDOR_ID = 0x87,
-  CEC_OPCODE_GIVE_DEVICE_VENDOR_ID = 0x8C,
-  CEC_OPCODE_VENDOR_COMMAND = 0x89,
-  CEC_OPCODE_VENDOR_COMMAND_WITH_ID = 0xA0,
-  CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A,
-  CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP = 0x8B,
-  CEC_OPCODE_SET_OSD_STRING = 0x64,
-  CEC_OPCODE_GIVE_OSD_NAME = 0x46,
-  CEC_OPCODE_SET_OSD_NAME = 0x47,
-  CEC_OPCODE_MENU_REQUEST = 0x8D,
-  CEC_OPCODE_MENU_STATUS = 0x8E,
-  CEC_OPCODE_USER_CONTROL_PRESSED = 0x44,
-  CEC_OPCODE_USER_CONTROL_RELEASE = 0x45,
-  CEC_OPCODE_GIVE_DEVICE_POWER_STATUS = 0x8F,
-  CEC_OPCODE_REPORT_POWER_STATUS = 0x90,
-  CEC_OPCODE_FEATURE_ABORT = 0x00,
-  CEC_OPCODE_ABORT = 0xFF,
-  CEC_OPCODE_GIVE_AUDIO_STATUS = 0x71,
-  CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D,
-  CEC_OPCODE_REPORT_AUDIO_STATUS = 0x7A,
-  CEC_OPCODE_SET_SYSTEM_AUDIO_MODE = 0x72,
-  CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST = 0x70,
-  CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS = 0x7E,
-  CEC_OPCODE_SET_AUDIO_RATE = 0x9A
-} ECecOpcode;
-
 typedef enum
 {
   CEC_ABORT_REASON_UNRECOGNIZED_OPCODE = 0,
index df2ce10c470100b940ee587748c1d501665cec07..97fbcd370b3542831ee2a67d41bade1068be92d0 100644 (file)
@@ -255,9 +255,14 @@ bool CCECParser::GetNextKeypress(cec_keypress *key)
 {
   return m_keyBuffer.Pop(*key);
 }
+
+bool CCECParser::GetNextCommand(cec_command *command)
+{
+  return m_commandBuffer.Pop(*command);
+}
 //@}
 
-void CCECParser::TransmitAbort(cec_logical_address address, ECecOpcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
+void CCECParser::TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
 {
   AddLog(CEC_LOG_DEBUG, "transmitting abort message");
   cec_frame frame;
@@ -692,7 +697,7 @@ void CCECParser::ParseCurrentFrame(void)
     return;
 
   vector<uint8_t> tx;
-  ECecOpcode opCode = (ECecOpcode) m_currentframe[1];
+  cec_opcode opCode = (cec_opcode) m_currentframe[1];
   if (destination == (uint16_t) m_iLogicalAddress)
   {
     switch(opCode)
@@ -732,6 +737,9 @@ void CCECParser::ParseCurrentFrame(void)
       AddKey();
       break;
     default:
+      cec_frame params = m_currentframe;
+      params.erase(params.begin(), params.begin() + 2);
+      AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
       break;
     }
   }
@@ -851,6 +859,17 @@ void CCECParser::AddKey(void)
   }
 }
 
+void CCECParser::AddCommand(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_frame *parameters)
+{
+  cec_command command;
+  command.source       = source;
+  command.destination  = destination;
+  command.opcode       = opcode;
+  if (parameters)
+    command.parameters = *parameters;
+  m_commandBuffer.Push(command);
+}
+
 int CCECParser::GetMinVersion(void)
 {
   return CEC_MIN_VERSION;
index f257fe1c02b967fd8add0760a49dbf812bb5cae8..1eca99c5e7fe3f4af940bea2a417862d0dbfc292 100644 (file)
@@ -62,6 +62,7 @@ namespace CEC
       virtual bool SetInactiveView(void);
       virtual bool GetNextLogMessage(cec_log_message *message);
       virtual bool GetNextKeypress(cec_keypress *key);
+      virtual bool GetNextCommand(cec_command *command);
       virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true, int64_t iTimeout = (int64_t) 5000);
       virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
       virtual bool SetAckMask(uint16_t iMask);
@@ -73,7 +74,7 @@ namespace CEC
       bool Process(void);
     protected:
       virtual bool TransmitFormatted(const cec_frame &data, bool bWaitForAck = true, int64_t iTimeout = (int64_t) 2000);
-      virtual void TransmitAbort(cec_logical_address address, ECecOpcode opcode, ECecAbortReason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
+      virtual void TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
       virtual void ReportCECVersion(cec_logical_address address = CECDEVICE_TV);
       virtual void ReportPowerState(cec_logical_address address = CECDEVICE_TV, bool bOn = true);
       virtual void ReportMenuState(cec_logical_address address = CECDEVICE_TV, bool bActive = true);
@@ -85,6 +86,7 @@ namespace CEC
 
     private:
       void AddKey(void);
+      void AddCommand(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_frame *parameters);
       void AddLog(cec_log_level level, const std::string &strMessage);
       bool WaitForAck(int64_t iTimeout = (int64_t) 1000);
       bool ReadFromDevice(int iTimeout);
@@ -110,6 +112,7 @@ namespace CEC
       CecBuffer<cec_frame>       m_frameBuffer;
       CecBuffer<cec_log_message> m_logBuffer;
       CecBuffer<cec_keypress>    m_keyBuffer;
+      CecBuffer<cec_command>     m_commandBuffer;
       std::string                m_strDeviceName;
       pthread_t                  m_thread;
       CMutex                     m_mutex;
index 4b6a1efa7bb5414f7df00b64016c5c137284ccfb..a4841a0a69b0dec55860b17e65bd3e496338c6d3 100644 (file)
@@ -124,6 +124,13 @@ bool cec_get_next_keypress(cec_keypress *key)
   return false;
 }
 
+bool cec_get_next_command(cec_command *command)
+{
+  if (cec_parser)
+    return cec_parser->GetNextCommand(command);
+  return false;
+}
+
 bool cec_transmit(const CEC::cec_frame &data, bool bWaitForAck /* = true */, int64_t iTimeout /* = 2000 */)
 {
   if (cec_parser)
index 299b019d4113c2920c3ab183f7d560545696502f..4379f8de020e70d3406bdca248a72a422701101c 100644 (file)
@@ -38,29 +38,34 @@ template<typename _BType>
   struct CecBuffer
   {
   public:
-    CecBuffer(void) {}
+    CecBuffer(int iMaxSize = 100) {}
     virtual ~CecBuffer(void) {}
 
-    void Push(_BType entry)
+    bool Push(_BType entry)
     {
-      CLockObject lock(&mutex);
-      buffer.push(entry);
+      CLockObject lock(&m_mutex);
+      if (m_buffer.size() == m_maxSize)
+        return false;
+
+      m_buffer.push(entry);
+      return true;
     }
 
     bool Pop(_BType &entry)
     {
       bool bReturn(false);
-      CLockObject lock(&mutex);
-      if (buffer.size() > 0)
+      CLockObject lock(&m_mutex);
+      if (m_buffer.size() > 0)
       {
-        entry = buffer.front();
-        buffer.pop();
+        entry = m_buffer.front();
+        m_buffer.pop();
         bReturn = true;
       }
       return bReturn;
     }
 
   private:
-    std::queue<_BType> buffer;
-    CMutex             mutex;
+    int                m_maxSize;
+    std::queue<_BType> m_buffer;
+    CMutex             m_mutex;
   };
index d119aef768eda7bb017a192a573e4659e30bfc5a..15a333d0f78f2f9a49ade060e3662ef68fadc0ac 100644 (file)
@@ -100,7 +100,31 @@ void show_help(const char* strExec)
       "parameters:" << endl <<
       "\t-h --help            Shows this help text" << endl <<
       "\t-l --list-devices    List all devices on this system" << endl <<
-      "\t[COM PORT]           The com port to connect to. If no COM port is given, the client tries to connect to the first device that is detected" << endl;
+      "\t[COM PORT]           The com port to connect to. If no COM port is given, the client tries to connect to the first device that is detected" << endl <<
+      endl <<
+      "Type 'h' or 'help' and press enter after starting the client to display all available commands" << endl;
+}
+
+void show_console_help(void)
+{
+  cout << endl <<
+  "================================================================================" << endl <<
+  "Available commands:" << endl <<
+  endl <<
+  "tx {bytes}                transfer bytes over the CEC line." << endl <<
+  "[tx 40 00 FF 11 22 33]    sends bytes 0x40 0x00 0xFF 0x11 0x22 0x33" << endl <<
+  endl <<
+  "am {ackmack}              change the ackmask of the CEC adapter." << endl <<
+  "[am 10]                   ackmask 0x10 (logical address 4)" << endl <<
+  endl <<
+  "la {logical_address}      change the logical address of the CEC adapter." << endl <<
+  "[la 4]                    logical address 4" << endl <<
+  endl <<
+  "[ping]                    send a ping command to the CEC adapter." << endl <<
+  "[bl]                      to let the adapter enter the bootloader, to upgrade the flash rom." << endl <<
+  "[h] or [help]             show this help." << endl <<
+  "[q] or [quit]             to quit the CEC test client and switch off all connected CEC devices." << endl <<
+  "================================================================================" << endl;
 }
 
 int main (int argc, char *argv[])
@@ -224,6 +248,10 @@ int main (int argc, char *argv[])
         {
           parser->StartBootloader();
         }
+        else if (command == "h" || command == "help")
+        {
+          show_console_help();
+        }
         else if (command == "q" || command == "quit")
         {
           bContinue = false;