Merge branch 'master' into release
authorLars Op den Kamp <lars@opdenkamp.eu>
Thu, 29 Sep 2011 23:35:42 +0000 (01:35 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Thu, 29 Sep 2011 23:35:42 +0000 (01:35 +0200)
13 files changed:
.gitignore
configure.ac
debian/changelog
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/lib/util/threads.cpp
src/testclient/main.cpp

index b6443c17c3afd6f00f17db2c76b0ecbe39e4a894..50135e77d4a88790c64d2652c830bcd90f0c00da 100644 (file)
@@ -22,9 +22,9 @@ libcec.exp
 libcec.ilk
 libcec.lib
 libcec.pdb
-testclient.exe
-testclient.ilk
-testclient.pdb
+cec-client.exe
+cec-client.ilk
+cec-client.pdb
 
 project/Debug/
 project/ipch/
index 45b0e49d7adfd3de348a4a3ba3710ddbc806838e..883d414ac3e2172f527dfeea734c62166ae08d09 100644 (file)
@@ -1,4 +1,4 @@
-AC_INIT([libcec], 0:1:0)
+AC_INIT([libcec], 0:2:0)
 AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 
 AC_PROG_CXX
@@ -9,4 +9,4 @@ AC_CHECK_LIB([pthread], [main],, AC_MSG_ERROR("required library 'pthread' is mis
 AC_CHECK_LIB([udev], [main],, AC_MSG_ERROR("required library 'udev' is missing"))
 
 AC_CONFIG_FILES([src/lib/libcec.pc])
-AC_OUTPUT([Makefile src/lib/Makefile src/testclient/Makefile])
\ No newline at end of file
+AC_OUTPUT([Makefile src/lib/Makefile src/testclient/Makefile])
index d54ce14c011c411cab89ed184fca299cff7312ba..76faddc15b900c629ac7392b2f6145fb52c215a3 100644 (file)
@@ -1,3 +1,21 @@
+libcec (0.2-1) unstable; urgency=low
+
+  * added a Close() method to the interface
+  * Added CEC command that were received by the adapter in a buffer that can be
+    read by a client with GetNextCommand()/cec_get_next_command(). added a
+    'help' command to the test client, that displays all available commands
+  * Fixed setting the ackmask. deprecated SetAckMask()/cec_set_ack_mask(). use
+    SetLogicalAddress()/cec_set_logical_address() instead. add 'la' command to
+    the testclient to set the logical address of the cec adapter
+  * Added optional logical and physical address parameters to
+    LoadLibCec()/cec_init() on the interface. fixed wrongly placed namespace
+    close tag in CECExports.h. updated interface documentation. bumped
+    interface version to 2.
+  * fixed hardcoded ackmask in SetAckMast(). set a shorter display name in the
+    test client. the previous one was too long and being rejected
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Fri, 28 Sep 2011 01:33:00 +0200
+
 libcec (0.1-1) unstable; urgency=low
 
   * Initial release v0.1
index 3a72aea13252f468bbd91919eee29c2b5fdeb586..0aef25c30723e72e5b32fa177a1aeaf86b02e775 100644 (file)
@@ -55,8 +55,8 @@
 extern "C" {
 namespace CEC {
 #endif
-  #define CEC_MIN_VERSION      1
-  #define CEC_LIB_VERSION      1
+  #define CEC_MIN_VERSION      2
+  #define CEC_LIB_VERSION      2
   #define CEC_SETTLE_DOWN_TIME 1000
 
   typedef std::vector<uint8_t> cec_frame;
@@ -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,
@@ -192,9 +258,21 @@ namespace CEC {
     std::string path;
     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
 
 #ifdef __cplusplus
+};
+
 #include "CECExportsCpp.h"
 #include "CECExportsC.h"
 };
index 04ce11a61e35e71c0fbbe0fd4c315d3333181ed1..8d91fe26ad9010d964a061c45694a84e28c7eba6 100644 (file)
@@ -39,17 +39,18 @@ extern "C" {
 #endif
 
 /*!
- * @brief Initialise the cec device.
+ * @brief Load the CEC adapter library.
  * @param strDeviceName How to present this device to other devices.
+ * @param iLogicalAddress The logical of this device. PLAYBACKDEVICE1 by default.
+ * @param iPhysicalAddress The physical address of this device. 0x1000 by default.
  * @return True when initialised, false otherwise.
  */
-extern DECLSPEC bool cec_init(const char *strDeviceName);
 
-/*!
- * @brief Close the cec device.
- * @return True when the device was closed, false otherwise.
- */
-extern DECLSPEC bool cec_close(void);
+#ifdef __cplusplus
+extern DECLSPEC bool cec_init(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+#else
+extern DECLSPEC bool cec_init(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+#endif
 
 /*!
  * @brief Open a connection to the CEC adapter.
@@ -59,6 +60,12 @@ extern DECLSPEC bool cec_close(void);
  */
 extern DECLSPEC bool cec_open(const char *strPort, int iTimeout);
 
+/*!
+ * @brief Close the connection to the CEC adapter.
+ * @param iTimeout Timeout in ms
+ */
+extern DECLSPEC bool cec_close(int iTimeout);
+
 /*!
  * @brief Ping the CEC adapter.
  * @return True when the ping was succesful, false otherwise.
@@ -73,6 +80,7 @@ extern DECLSPEC bool cec_start_bootloader(void);
 
 /*!
  * @brief Power off connected CEC capable devices.
+ * @param address The logical address to power off.
  * @return True when the command was sent succesfully, false otherwise.
  */
 #ifdef __cplusplus
@@ -83,6 +91,7 @@ extern DECLSPEC bool cec_power_off_devices(cec_logical_address address = CECDEVI
 
 /*!
  * @brief Power on the connected CEC capable devices.
+ * @param address The logical address to power on.
  * @return True when the command was sent succesfully, false otherwise.
  */
 #ifdef __cplusplus
@@ -93,6 +102,7 @@ extern DECLSPEC bool cec_power_on_devices(cec_logical_address address = CECDEVIC
 
 /*!
  * @brief Put connected CEC capable devices in standby mode.
+ * @brief address The logical address of the device to put in standby.
  * @return True when the command was sent succesfully, false otherwise.
  */
 #ifdef __cplusplus
@@ -102,13 +112,13 @@ extern DECLSPEC bool cec_standby_devices(cec_logical_address address = CECDEVICE
 #endif
 
 /*!
- * @brief Set this device as the active source on connected CEC capable devices.
+ * @brief Broadcast a message that notifies connected CEC capable devices that this device is the active source.
  * @return True when the command was sent succesfully, false otherwise.
  */
 extern DECLSPEC bool cec_set_active_view(void);
 
 /*!
- * @brief Mark this device as inactive on connected CEC capable devices.
+ * @brief Broadcast a message that notifies connected CEC capable devices that this device is no longer the active source.
  * @return True when the command was sent succesfully, false otherwise.
  */
 extern DECLSPEC bool cec_set_inactive_view(void);
@@ -126,7 +136,7 @@ extern DECLSPEC bool cec_get_next_log_message(cec_log_message *message);
 
 /*!
  * @brief Get the next keypress in the queue, if there is one.
- * @param key The next keypress
+ * @param key The next keypress.
  * @return True if a key was passed, false otherwise.
  */
 #ifdef __cplusplus
@@ -136,8 +146,21 @@ extern DECLSPEC bool cec_get_next_keypress(cec_keypress *key);
 #endif
 
 /*!
- * @brief Transmit a frame and wait for ACK.
+ * @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.
+ * @param bWaitForAck Wait for an ACK message for 1 second after this frame has been sent.
+ * @param iTimeout Timeout if the message could not be sent for this amount of ms. Does not influence the timeout of the wait for the ACK message. That timeout is specified by the CEC standard.
  * @return True when the data was sent and acked, false otherwise.
  */
 #ifdef __cplusplus
@@ -147,15 +170,40 @@ extern DECLSPEC bool cec_transmit(const cec_frame &data, bool bWaitForAck = true
 #endif
 
 /*!
- * @brief Set the ack mask for the CEC adapter.
- * @param ackmask The new ack mask.
+ * @brief Set the logical address of the CEC adapter.
+ * @param iLogicalAddress The cec adapter's logical address.
+ * @return True when the logical address was set succesfully, false otherwise.
+ */
+#ifdef __cplusplus
+extern DECLSPEC bool cec_set_logical_address(CEC::cec_logical_address iLogicalAddress);
+#else
+extern DECLSPEC bool cec_set_logical_address(cec_logical_address myAddress, cec_logical_address targetAddress);
+#endif
+
+/*!
+ * @deprecated Use cec_set_logical_address() instead.
+ * @brief Set the ack mask of the CEC adapter.
+ * @param iMask The cec adapter's ack mask.
  * @return True when the ack mask was sent succesfully, false otherwise.
  */
-extern DECLSPEC bool cec_set_ack_mask(uint16_t ackmask);
+extern DECLSPEC bool cec_set_ack_mask(uint16_t iMask);
 
+/*!
+ * @return Get the minimal version of libcec that this version of libcec can interface with.
+ */
 extern DECLSPEC int cec_get_min_version(void);
+
+/*!
+ * @return Get the version of libcec.
+ */
 extern DECLSPEC int cec_get_lib_version(void);
 
+/*!
+ * @brief Try to find all connected CEC adapters. Only implemented on Linux at the moment.
+ * @param deviceList The vector to store device descriptors in.
+ * @param strDevicePath Optional device path. Only adds device descriptors that match the given device path.
+ * @return The number of devices that were found, or -1 when an error occured.
+ */
 #ifdef __cplusplus
 extern DECLSPEC int cec_find_devices(std::vector<CEC::cec_device> &deviceList, const char *strDevicePath = NULL);
 #else
index 195ddf5c2a49a36636b0f5a37649751717f3a220..ac00190571599ea9510396faa83f489b25b79cb4 100644 (file)
@@ -41,6 +41,11 @@ namespace CEC
      */
     virtual bool Open(const char *strPort, int iTimeoutMs = 10000) = 0;
 
+    /*!
+     * @see cec_close
+     */
+    virtual bool Close(int iTimeoutMs = 2000) = 0;
+
     /*!
      * @see cec_find_devices
      */
@@ -91,22 +96,39 @@ namespace CEC
      */
     virtual bool GetNextKeypress(cec_keypress *key) = 0;
 
+    /*!
+     * @see cec_get_next_command
+     */
+    virtual bool GetNextCommand(cec_command *command) = 0;
+
     /*!
      * @see cec_transmit
      */
     virtual bool Transmit(const cec_frame &data, bool bWaitForAck = true, int64_t iTimeout = (int64_t) 5000) = 0;
 
     /*!
-     * @see cec_set_ack_mask
+     * @see cec_set_logical_address
      */
-    virtual bool SetAckMask(cec_logical_address ackmask) = 0;
+    virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress) = 0;
 
+    /*!
+     * @deprecated use SetLogicalAddress() instead
+     */
+    virtual bool SetAckMask(uint16_t iMask) = 0;
+
+    /*!
+     * @see cec_get_min_version
+     */
     virtual int GetMinVersion(void) = 0;
+
+    /*!
+     * @see cec_get_lib_version
+     */
     virtual int GetLibVersion(void) = 0;
   };
 };
 
-extern DECLSPEC void * CECCreate(const char *strDeviceName);
+extern DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
 
 #if !defined(DLL_EXPORT)
 #if defined(_WIN32) || defined(_WIN64)
@@ -114,32 +136,57 @@ extern DECLSPEC void * CECCreate(const char *strDeviceName);
 #include <conio.h>
 
 static HINSTANCE g_libCEC = NULL;
-inline CEC::ICECDevice *LoadLibCec(const char *strName)
+static int g_iLibCECInstanceCount = 0;
+
+/*!
+ * @see cec_init
+ */
+inline CEC::ICECDevice *LoadLibCec(const char *strName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS)
 {
-  typedef void* (__cdecl*_CreateLibCec)(const char *);
+  typedef void* (__cdecl*_CreateLibCec)(const char *, uint8_t, uint8_t);
   _CreateLibCec CreateLibCec;
 
-  g_libCEC = LoadLibrary("libcec.dll");
+  if (!g_libCEC)
+    g_libCEC = LoadLibrary("libcec.dll");
   if (!g_libCEC)
     return NULL;
+
+  ++g_iLibCECInstanceCount;
   CreateLibCec = (_CreateLibCec) (GetProcAddress(g_libCEC, "CECCreate"));
   if (!CreateLibCec)
     return NULL;
-  return static_cast< CEC::ICECDevice* > (CreateLibCec(strName));
+  return static_cast< CEC::ICECDevice* > (CreateLibCec(strName, iLogicalAddress, iPhysicalAddress));
 }
 
+/*!
+ * @brief Unload the given libcec instance.
+ * @param device The instance to unload.
+ */
 inline void UnloadLibCec(CEC::ICECDevice *device)
 {
   delete device;
-  FreeLibrary(g_libCEC);
+
+  if (--g_iLibCECInstanceCount == 0)
+  {
+    FreeLibrary(g_libCEC);
+    g_libCEC = NULL;
+  }
 };
 
 #else
-inline CEC::ICECDevice *LoadLibCec(const char *strName)
+
+/*!
+ * @see cec_init
+ */
+inline CEC::ICECDevice *LoadLibCec(const char *strName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS)
 {
-  return (CEC::ICECDevice*) CECCreate(strName);
+  return (CEC::ICECDevice*) CECCreate(strName, iLogicalAddress, iPhysicalAddress);
 };
 
+/*!
+ * @brief Unload the given libcec instance.
+ * @param device The instance to unload.
+ */
 inline void UnloadLibCec(CEC::ICECDevice *device)
 {
   delete device;
index dcc4c72d63b34b6bf2a421b2fd26fe6cba06cd29..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,
@@ -426,8 +360,6 @@ typedef enum
   MSGCODE_FRAME_ACK = 0x40,
 } ECecMessageCode;
 
-//default physical address 1.0.0.0
-#define CEC_DEFAULT_PHYSICAL_ADDRESS 0x1000
 #define MSGSTART                     0xFF
 #define MSGEND                       0xFE
 #define MSGESC                       0xFD
index 52b271141731842d5471e27189c391c3f9e0235a..dad7a0d038a31340caeed08329afcfd58d6645d3 100644 (file)
@@ -52,13 +52,13 @@ using namespace std;
  * ICECDevice implementation
  */
 //@{
-CCECParser::CCECParser(const char *strDeviceName) :
+CCECParser::CCECParser(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
     m_inbuf(NULL),
     m_iInbufSize(0),
     m_iInbufUsed(0),
     m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
-    m_physicaladdress(CEC_DEFAULT_PHYSICAL_ADDRESS),
-    m_iLogicalAddress(CECDEVICE_PLAYBACKDEVICE1),
+    m_physicaladdress(iPhysicalAddress),
+    m_iLogicalAddress(iLogicalAddress),
     m_strDeviceName(strDeviceName),
     m_bRunning(false)
 {
@@ -67,8 +67,7 @@ CCECParser::CCECParser(const char *strDeviceName) :
 
 CCECParser::~CCECParser(void)
 {
-  m_bRunning = false;
-  pthread_join(m_thread, NULL);
+  Close(0);
   m_serialport->Close();
   delete m_serialport;
 }
@@ -90,7 +89,7 @@ bool CCECParser::Open(const char *strPort, int iTimeoutMs /* = 10000 */)
   m_serialport->Read(buff, sizeof(buff), CEC_SETTLE_DOWN_TIME);
 
   if (bReturn)
-    bReturn = SetAckMask(m_iLogicalAddress);
+    bReturn = SetLogicalAddress(m_iLogicalAddress);
 
   if (!bReturn)
   {
@@ -112,6 +111,24 @@ bool CCECParser::Open(const char *strPort, int iTimeoutMs /* = 10000 */)
   return bReturn;
 }
 
+bool CCECParser::Close(int iTimeoutMs /* = 2000 */)
+{
+  m_bRunning = false;
+  bool bExit(false);
+  if (iTimeoutMs > 0)
+  {
+    bExit = m_exitCondition.Wait(&m_mutex, iTimeoutMs);
+    m_mutex.Unlock();
+  }
+  else
+  {
+    pthread_join(m_thread, NULL);
+    bExit = true;
+  }
+
+  return bExit;
+}
+
 void *CCECParser::ThreadHandler(CCECParser *parser)
 {
   if (parser)
@@ -145,11 +162,15 @@ bool CCECParser::Process(void)
 
   AddLog(CEC_LOG_DEBUG, "reader thread terminated");
   m_bRunning = false;
+  m_exitCondition.Signal();
   return true;
 }
 
 bool CCECParser::Ping(void)
 {
+  if (!m_bRunning)
+    return false;
+
   AddLog(CEC_LOG_DEBUG, "sending ping");
   cec_frame output;
   output.push_back(MSGSTART);
@@ -170,6 +191,9 @@ bool CCECParser::Ping(void)
 
 bool CCECParser::StartBootloader(void)
 {
+  if (!m_bRunning)
+    return false;
+
   AddLog(CEC_LOG_DEBUG, "starting the bootloader");
   cec_frame output;
   output.push_back(MSGSTART);
@@ -193,6 +217,9 @@ uint8_t CCECParser::GetSourceDestination(cec_logical_address destination /* = CE
 
 bool CCECParser::PowerOffDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
 {
+  if (!m_bRunning)
+    return false;
+
   CStdString strLog;
   strLog.Format("powering off devices with logical address %d", (int8_t)address);
   AddLog(CEC_LOG_DEBUG, strLog.c_str());
@@ -204,6 +231,9 @@ bool CCECParser::PowerOffDevices(cec_logical_address address /* = CECDEVICE_BROA
 
 bool CCECParser::PowerOnDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
 {
+  if (!m_bRunning)
+    return false;
+
   CStdString strLog;
   strLog.Format("powering on devices with logical address %d", (int8_t)address);
   AddLog(CEC_LOG_DEBUG, strLog.c_str());
@@ -215,6 +245,9 @@ bool CCECParser::PowerOnDevices(cec_logical_address address /* = CECDEVICE_BROAD
 
 bool CCECParser::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
 {
+  if (!m_bRunning)
+    return false;
+
   CStdString strLog;
   strLog.Format("putting all devices with logical address %d in standby mode", (int8_t)address);
   AddLog(CEC_LOG_DEBUG, strLog.c_str());
@@ -226,6 +259,9 @@ bool CCECParser::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROAD
 
 bool CCECParser::SetActiveView(void)
 {
+  if (!m_bRunning)
+    return false;
+
   AddLog(CEC_LOG_DEBUG, "setting active view");
   cec_frame frame;
   frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
@@ -237,6 +273,9 @@ bool CCECParser::SetActiveView(void)
 
 bool CCECParser::SetInactiveView(void)
 {
+  if (!m_bRunning)
+    return false;
+
   AddLog(CEC_LOG_DEBUG, "setting inactive view");
   cec_frame frame;
   frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
@@ -248,16 +287,21 @@ bool CCECParser::SetInactiveView(void)
 
 bool CCECParser::GetNextLogMessage(cec_log_message *message)
 {
-  return m_logBuffer.Pop(*message);
+  return m_bRunning ? m_logBuffer.Pop(*message) : false;
 }
 
 bool CCECParser::GetNextKeypress(cec_keypress *key)
 {
-  return m_keyBuffer.Pop(*key);
+  return m_bRunning ? m_keyBuffer.Pop(*key) : false;
+}
+
+bool CCECParser::GetNextCommand(cec_command *command)
+{
+  return m_bRunning ? m_commandBuffer.Pop(*command) : false;
 }
 //@}
 
-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;
@@ -512,7 +556,7 @@ bool CCECParser::ReadFromDevice(int iTimeout)
 void CCECParser::ProcessMessages(void)
 {
   cec_frame msg;
-  while (GetMessage(msg))
+  while (m_bRunning && GetMessage(msg))
     ParseMessage(msg);
 }
 
@@ -692,7 +736,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 +776,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;
     }
   }
@@ -753,6 +800,12 @@ void CCECParser::ParseCurrentFrame(void)
           BroadcastActiveSource();
       }
     }
+    else
+    {
+      cec_frame params = m_currentframe;
+      params.erase(params.begin(), params.begin() + 2);
+      AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
+    }
   }
   else
   {
@@ -796,31 +849,34 @@ void CCECParser::CheckKeypressTimeout(int64_t now)
   }
 }
 
-bool CCECParser::SetAckMask(cec_logical_address ackmask)
+bool CCECParser::SetLogicalAddress(cec_logical_address iLogicalAddress)
 {
   CStdString strLog;
-  strLog.Format("setting ackmask to %d", (uint16_t) ackmask);
+  strLog.Format("setting logical address to %d", iLogicalAddress);
   AddLog(CEC_LOG_NOTICE, strLog.c_str());
 
-  //TODO!!
-  uint16_t tackmask = 0x10;
-  AddLog(CEC_LOG_WARNING, "TODO: forcing ackmask to 0x10");
+  m_iLogicalAddress = iLogicalAddress;
+  return SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
+}
+
+bool CCECParser::SetAckMask(uint16_t iMask)
+{
+  CStdString strLog;
+  strLog.Format("setting ackmask to %2x", iMask);
+  AddLog(CEC_LOG_DEBUG, strLog.c_str());
 
   cec_frame output;
-  m_iLogicalAddress = ackmask;
-  output.push_back(MSGSTART);
 
+  output.push_back(MSGSTART);
   PushEscaped(output, MSGCODE_SET_ACK_MASK);
-  PushEscaped(output, tackmask >> 8);
-  PushEscaped(output, (uint8_t) tackmask);
-
+  PushEscaped(output, iMask >> 8);
+  PushEscaped(output, (uint8_t)iMask);
   output.push_back(MSGEND);
 
   if (m_serialport->Write(output) == -1)
   {
-    CStdString strError;
-    strError.Format("error writing to serial port: %s", m_serialport->GetError().c_str());
-    AddLog(CEC_LOG_ERROR, strError);
+    strLog.Format("error writing to serial port: %s", m_serialport->GetError().c_str());
+    AddLog(CEC_LOG_ERROR, strLog);
     return false;
   }
 
@@ -848,6 +904,26 @@ 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;
+  if (m_commandBuffer.Push(command))
+  {
+    CStdString strDebug;
+    strDebug.Format("stored command '%d' in the command buffer. buffer size = %d", opcode, m_commandBuffer.Size());
+    AddLog(CEC_LOG_DEBUG, strDebug);
+  }
+  else
+  {
+    AddLog(CEC_LOG_WARNING, "command buffer is full");
+  }
+}
+
 int CCECParser::GetMinVersion(void)
 {
   return CEC_MIN_VERSION;
@@ -870,7 +946,7 @@ int CCECParser::FindDevices(std::vector<cec_device> &deviceList, const char *str
   return CCECDetect::FindDevices(deviceList, strDevicePath);
 }
 
-DECLSPEC void * CECCreate(const char *strDeviceName)
+DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress /*= CEC::CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
 {
-  return static_cast< void* > (new CCECParser(strDeviceName));
+  return static_cast< void* > (new CCECParser(strDeviceName, iLogicalAddress, iPhysicalAddress));
 }
index 3ad6cf0e3c86cefee7a9ed34eb3548a31208ef35..be958553cb8ea9b22502d5ac44594064521ca199 100644 (file)
@@ -48,10 +48,11 @@ namespace CEC
      * ICECDevice implementation
      */
     //@{
-      CCECParser(const char *strDeviceName);
+      CCECParser(const char *strDeviceName, cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1, int iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
       virtual ~CCECParser(void);
 
       virtual bool Open(const char *strPort, int iTimeout = 10000);
+      virtual bool Close(int iTimeoutMs = 2000);
       virtual int  FindDevices(std::vector<cec_device> &deviceList, const char *strDevicePath = NULL);
       virtual bool Ping(void);
       virtual bool StartBootloader(void);
@@ -62,8 +63,10 @@ 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 SetAckMask(cec_logical_address ackmask);
+      virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress);
+      virtual bool SetAckMask(uint16_t iMask);
       virtual int  GetMinVersion(void);
       virtual int  GetLibVersion(void);
     //@}
@@ -72,7 +75,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);
@@ -84,6 +87,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);
@@ -109,9 +113,11 @@ 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;
+      CCondition                 m_exitCondition;
       bool                       m_bRunning;
   };
 };
index 84d54105b09e343573c77d1ff3d4003838d1bc3b..b21f1c0b461a3d17358983e3dfdda9afd8ec4821 100644 (file)
@@ -41,19 +41,12 @@ using namespace std;
 //@{
 ICECDevice *cec_parser;
 
-bool cec_init(const char *strDeviceName)
+bool cec_init(const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, int iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
 {
-  cec_parser = (ICECDevice *) CECCreate(strDeviceName);
+  cec_parser = (ICECDevice *) CECCreate(strDeviceName, iLogicalAddress, iPhysicalAddress);
   return (cec_parser != NULL);
 }
 
-bool cec_close(void)
-{
-  delete cec_parser;
-  cec_parser = NULL;
-  return true;
-}
-
 bool cec_open(const char *strPort, int iTimeout)
 {
   if (cec_parser)
@@ -61,6 +54,17 @@ bool cec_open(const char *strPort, int iTimeout)
   return false;
 }
 
+bool cec_close(int iTimeout)
+{
+  bool bReturn = false;
+  if (cec_parser)
+    bReturn = cec_parser->Close(iTimeout);
+
+  delete cec_parser;
+  cec_parser = NULL;
+  return bReturn;
+}
+
 bool cec_ping(void)
 {
   if (cec_parser)
@@ -124,6 +128,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)
@@ -131,10 +142,17 @@ bool cec_transmit(const CEC::cec_frame &data, bool bWaitForAck /* = true */, int
   return false;
 }
 
-bool cec_set_ack_mask(uint16_t ackmask)
+bool cec_set_logical_address(cec_logical_address iLogicalAddress)
+{
+  if (cec_parser)
+    return cec_parser->SetLogicalAddress(iLogicalAddress);
+  return false;
+}
+
+bool cec_set_ack_mask(uint16_t iMask)
 {
   if (cec_parser)
-    return cec_parser->SetAckMask((cec_logical_address) ackmask);
+    return cec_parser->SetAckMask(iMask);
   return false;
 }
 
index 299b019d4113c2920c3ab183f7d560545696502f..cafa65574414b5864718038b175d697566572cf9 100644 (file)
@@ -38,29 +38,39 @@ template<typename _BType>
   struct CecBuffer
   {
   public:
-    CecBuffer(void) {}
+    CecBuffer(int iMaxSize = 100)
+    {
+      m_maxSize = iMaxSize;
+    }
     virtual ~CecBuffer(void) {}
 
-    void Push(_BType entry)
+    int Size(void) const { return m_buffer.size(); }
+
+    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 3bfc1bd75e0cbb96f81f1a99a62836ea4f65490d..3e40c2ba0370288cb668662514a91f52b3f10405 100644 (file)
@@ -115,6 +115,8 @@ bool CCondition::Wait(CMutex *mutex, int64_t iTimeout)
     abstime.tv_sec  = now.tv_sec + (time_t)(iTimeout / 1000);
     abstime.tv_nsec = (long)((iTimeout % (unsigned long)1000) * (unsigned long)1000000);
     m_bSignaled     = (pthread_cond_timedwait(&m_cond, &mutex->m_mutex, &abstime) == 0);
+    if (!m_bSignaled)
+      pthread_mutex_unlock(&mutex->m_mutex);
   }
 
   bool bReturn = m_bSignaled;
index 1aa790b250735397904d1fda89d67f0a52d5b493..15a333d0f78f2f9a49ade060e3662ef68fadc0ac 100644 (file)
@@ -42,7 +42,7 @@
 using namespace CEC;
 using namespace std;
 
-#define CEC_TEST_CLIENT_VERSION 1
+#define CEC_TEST_CLIENT_VERSION 2
 
 void flush_log(ICECDevice *cecParser)
 {
@@ -100,12 +100,36 @@ 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[])
 {
-  ICECDevice *parser = LoadLibCec("CEC Test Client");
+  ICECDevice *parser = LoadLibCec("CEC Tester");
   if (!parser && parser->GetMinVersion() > CEC_TEST_CLIENT_VERSION)
   {
     cout << "Unable to create parser. Is libcec.dll present?" << endl;
@@ -203,10 +227,17 @@ int main (int argc, char *argv[])
         {
           string strvalue;
           int    ackmask;
-          vector<uint8_t> bytes;
           if (GetWord(input, strvalue) && HexStrToInt(strvalue, ackmask))
           {
-            parser->SetAckMask((cec_logical_address) ackmask);
+            parser->SetAckMask(ackmask);
+          }
+        }
+        else if (command == "la")
+        {
+          string strvalue;
+          if (GetWord(input, strvalue))
+          {
+            parser->SetLogicalAddress((cec_logical_address) atoi(strvalue.c_str()));
           }
         }
         else if (command == "ping")
@@ -217,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;