HDMI-CEC to USB EG Support for Pulse Eight

Do you have questions about writing plugins or scripts in Python? Meet the coders here.
krambriw
Plugin Developer
Posts: 2570
Joined: Sat Jun 30, 2007 2:51 pm
Location: Stockholm, Sweden
Contact:

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by krambriw » Thu Aug 15, 2013 5:34 am

Reading this, I believe it should be fairly easy for them to provide the necessary documentation provided they have that intention. You only need the so called header file for the dll.

I have made a small test with another dll (this one is actually well documented) exporting the entry points. Since you have VS installed, to make it simple, you can put the following files into a folder together with the dll file:
Image2.gif
Image2.gif (2.73 KiB) Viewed 10142 times
Then, from the command prompt, simple run

Code: Select all


C:\Users\krm\Desktop\DLLtest>dumpbin /exports TelldusCore.dll
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file TelldusCore.dll

File Type: DLL

  Section contains the following exports for tellduscore.dll

    00000000 characteristics
    506976B9 time date stamp Mon Oct 01 12:55:53 2012
        0.00 version
           1 ordinal base
          44 number of functions
          44 number of names

    ordinal hint RVA      name

         11    0 000014F6 tdAddDevice
         16    1 00001307 tdBell
         19    2 000012E9 tdClose
         30    3 00001393 tdConnectTellStickController
         40    4 00001019 tdController
         41    5 000014B0 tdControllerValue
         17    6 000012C6 tdDim
         31    7 00001091 tdDisconnectTellStickController
         35    8 00001271 tdDown
         33    9 000012A8 tdExecute
          2    A 0000152D tdGetDeviceId
          6    B 0000128F tdGetDeviceParameter
         23    C 000013C0 tdGetDeviceType
         18    D 0000147E tdGetErrorString
          5    E 000011C2 tdGetModel
          3    F 00001073 tdGetName
          1   10 0000126C tdGetNumberOfDevices
          4   11 000012F8 tdGetProtocol
         20   12 00001320 tdInit
         22   13 0000145B tdLastSentCommand
         27   14 000011AE tdLastSentValue
         26   15 0000102D tdLearn
         13   16 00001537 tdMethods
         44   17 000013B6 tdRegisterControllerEvent
         32   18 00001078 tdRegisterDeviceChangeEvent
         21   19 000013B1 tdRegisterDeviceEvent
         25   1A 000015B9 tdRegisterRawDeviceEvent
         37   1B 000014C9 tdRegisterSensorEvent
         28   1C 00001104 tdReleaseString
         43   1D 000014FB tdRemoveController
         12   1E 00001596 tdRemoveDevice
         24   1F 00001460 tdSendRawCommand
         38   20 00001195 tdSensor
         39   21 0000101E tdSensorValue
         42   22 000011EF tdSetControllerValue
         10   23 00001528 tdSetDeviceParameter
          9   24 0000116D tdSetModel
          7   25 0000113B tdSetName
          8   26 00001636 tdSetProtocol
         36   27 00001267 tdStop
         15   28 00001145 tdTurnOff
         14   29 00001140 tdTurnOn
         29   2A 00001096 tdUnregisterCallback
         34   2B 00001429 tdUp

  Summary

        1000 .data
        2000 .idata
        5000 .rdata
        2000 .reloc
        1000 .rsrc
       11000 .text

From the results above you can see the name of the methods but unfortunately not the parameters. For those, you need the source, a header file or documentation like in the example below. But what could be so difficult if the company really want interfacing to happen?

Best, Walter

Typical sample from the header file (included when you install the driver and is also available as on-line documentation):

Code: Select all

	TELLSTICK_API int WINAPI tdTurnOn(int intDeviceId);
	TELLSTICK_API int WINAPI tdTurnOff(int intDeviceId);
	TELLSTICK_API int WINAPI tdBell(int intDeviceId);
	TELLSTICK_API int WINAPI tdDim(int intDeviceId, unsigned char level);

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Thu Aug 15, 2013 5:46 pm

Walter,

I'm aware that I can get the names of the functions that are exposed by the DLL. And, I can see in the source code the names/types of the parameters for those functions. However, this does not give me sufficient information. I need to know what those functions do, and how they were intended to be used. I need to know how the values of the parameters change the way the function behaves. I need to know the allowed values.

Next, I need to know the basic flow. Many DLL's require certain properties/attributes to be set before calling certain functions. This information is not explained in their "doxygen style" documentation.

Their source contains functions that are obvious, and others that are not so obvious. For example, they have a function to search for connected Pulse-Eight devices. I assume this function would return information needed for another of their functions, that is obviously used for establishing a connection to the device. They have a function to ask the device what hardware version it is, and another to ask for the firmware version. They have a function that is obviously used to disconnect from the device. Then, they have many, many, many other functions whose purpose is not clear to me.

It's fairly obvious that my program should flow something like this:

1) Register itself as an EG plugin, and all the other stuff shown in the Plugin Developer Documentation (which was very informative, by the way).
2) Search for Pulse-Eight devices.
3) Connect to a Pulse-Eight device.
4) Gather hardware/firmware information (this may not be necessary).
5) Start a new thread that listens to the device so that communications on the CEC bus will trigger events. This is where the trouble begins. I don't see a function that is obviously used for listening to the CEC bus. And, even if I did, I need more information on how to implement it.
6) Write some actions that send commands to the device. I can see one function that obviously allows me to send data on the CEC bus. It seems that it would allow me to do something similar to the way the RCAware plugin communicates. However, I was lead to believe (by one of the Pulse-Eight devs) that their DLL should handle the intricacies of the CEC message format. So, I assume that there must be other functions that make things simpler for me... instead of having to write my program to communicate directly with the CEC bus. It is not clear which of the many functions are the correct ones to use.
7) Disconnect from the device, unload the DLL, etc, when the EG plugin is stopped or removed.

I agree with you that it seems like Pulse-Eight should be able to provide some documentation on their DLL, especially since they have said that they encourage others to write software around their library.

As I've stated before, I don't know C++ nor Visual Studio. Honestly, VS looks more complicated than learning C++.

I'll spend more time on this soon. Hopefully, I can get more information from Pulse-Eight... but I don't have high hopes in that regard.

I may dive into the source code to figure it out. I really don't want to go that direction, but I may.

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Thu Aug 15, 2013 6:20 pm

From the README file in the Github libCEC directory:
We provide a C, C++ and .NET CLR interface to the adapter.

C++ developers:
* the API can be found in /include/cec.h
* an example implementation can be found in /src/testclient/main.cpp

C developers:
* the API can be found in /include/cecc.h

.NET developers:
* add a reference to LibCecSharp.dll
* an example can be found in \src\CecSharpTester\CecSharpClient.cs
OK, so I look in the header file, as Walter recommends. Here is what I see:

Code: Select all

#pragma once
/*
 * This file is part of the libCEC(R) library.
 *
 * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.  All rights reserved.
 * libCEC(R) is an original work, containing original code.
 *
 * libCEC(R) is a trademark of Pulse-Eight Limited.
 *
 * This program is dual-licensed; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *
 * Alternatively, you can license this library under a commercial license,
 * please contact Pulse-Eight Licensing for more information.
 *
 * For more information contact:
 * Pulse-Eight Licensing       <license@pulse-eight.com>
 *     http://www.pulse-eight.com/
 *     http://www.pulse-eight.net/
 */


#ifndef CECEXPORTS_H_
#define CECEXPORTS_H_


#include "cectypes.h"


#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_CURRENT


namespace CEC
{
  /*!
   * To create a new libCEC instance, call CECInitialise() and pass the
   * configuration as argument. Then call Open() to open a connection to the
   * adapter. Close() closes the connection and CECDestroy() cleans up the
   * libCEC instance.
   *
   * libCEC can send commands to other devices on the CEC bus via the methods
   * on this interface, and all commands that libCEC received are sent back
   * to the application via callback methods. The callback methods can be
   * found in cectypes.h, ICECCallbacks.
   */
  class ICECAdapter
  {
  public:
    virtual ~ICECAdapter() {};
    /*! @name Adapter methods */
    //@{


    /*!
     * @brief Open a connection to the CEC adapter.
     * @param strPort The path to the port.
     * @param iTimeoutMs Connection timeout in ms.
     * @return True when connected, false otherwise.
     */
    virtual bool Open(const char *strPort, uint32_t iTimeoutMs = 10000) = 0;


    /*!
     * @brief Close the connection to the CEC adapter.
     */
    virtual void Close(void) = 0;


    /*!
     * @deprecated Use DetectAdapters() instead
     * @brief Try to find all connected CEC adapters.
     * @param deviceList The vector to store device descriptors in.
     * @param iBufSize The size of the deviceList buffer.
     * @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.
     */
    virtual int8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL) = 0;


    /*!
     * @brief Sends a ping command to the adapter, to check if it's responding.
     * @return True when the ping was succesful, false otherwise.
     */
    virtual bool PingAdapter(void) = 0;


    /*!
     * @brief Start the bootloader of the CEC adapter. Closes the connection when successful.
     * @return True when the command was sent successfully, false otherwise.
     */
    virtual bool StartBootloader(void) = 0;
    //@}


    /*!
     * @brief Transmit a raw CEC command over the CEC line.
     * @param data The command to send.
     * @return True when the data was sent and acked, false otherwise.
     */
    virtual bool Transmit(const cec_command &data) = 0;


    /*!
     * @brief Change the logical address on the CEC bus of the CEC adapter. libCEC automatically assigns a logical address, and this method is only available for debugging purposes.
     * @param iLogicalAddress The CEC adapter's new logical address.
     * @return True when the logical address was set successfully, false otherwise.
     */
    virtual bool SetLogicalAddress(cec_logical_address iLogicalAddress = CECDEVICE_PLAYBACKDEVICE1) = 0;


    /*!
     * @brief Change the physical address (HDMI port) of the CEC adapter. libCEC will try to autodetect the physical address when connecting. If it did, it's set in libcec_configuration.
     * @param iPhysicalAddress The CEC adapter's new physical address.
     * @brief True when the physical address was set successfully, false otherwise.
     */
    virtual bool SetPhysicalAddress(uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS) = 0;


    /*!
     * @brief Power on the given CEC capable devices. If CECDEVICE_BROADCAST is used, then wakeDevice in libcec_configuration will be used.
     * @param address The logical address to power on.
     * @return True when the command was sent succesfully, false otherwise.
     */
    virtual bool PowerOnDevices(cec_logical_address address = CECDEVICE_TV) = 0;


    /*!
     * @brief Put the given CEC capable devices in standby mode. If CECDEVICE_BROADCAST is used, then standbyDevices in libcec_configuration will be used.
     * @brief address The logical address of the device to put in standby.
     * @return True when the command was sent succesfully, false otherwise.
     */
    virtual bool StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST) = 0;


    /*!
     * @brief Change the active source to a device type handled by libCEC. Use CEC_DEVICE_TYPE_RESERVED to make the default type used by libCEC active.
     * @param type The new active source. Leave empty to use the primary type
     * @return True when the command was sent succesfully, false otherwise.
     */
    virtual bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED) = 0;


    /*!
     * @brief Change the deck control mode, if this adapter is registered as playback or recording device.
     * @param mode The new control mode.
     * @param bSendUpdate True to send the new status over the CEC line.
     * @return True if set, false otherwise.
     */
    virtual bool SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true) = 0;


    /*!
     * @brief Change the deck info, if this adapter is a playback or recording device.
     * @param info The new deck info.
     * @param bSendUpdate True to send the new status over the CEC line.
     * @return True if set, false otherwise.
     */
    virtual bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true) = 0;


    /*!
     * @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.
     */
    virtual bool SetInactiveView(void) = 0;


    /*!
     * @brief Change the menu state. This value is already changed by libCEC automatically if a device is (de)activated.
     * @param state The new state.
     * @param bSendUpdate True to send the new status over the CEC line.
     * @return True if set, false otherwise.
     */
    virtual bool SetMenuState(cec_menu_state state, bool bSendUpdate = true) = 0;


    /*!
     * @brief Display a message on the device with the given logical address. Not supported by most TVs.
     * @param iLogicalAddress The logical address of the device to display the message on.
     * @param duration The duration of the message
     * @param strMessage The message to display.
     * @return True when the command was sent, false otherwise.
     */
    virtual bool SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage) = 0;


    /*!
     * @brief Enable or disable monitoring mode, for debugging purposes. If monitoring mode is enabled, libCEC won't respond to any command, but only log incoming data.
     * @param bEnable True to enable, false to disable.
     * @return True when switched successfully, false otherwise.
     */
    virtual bool SwitchMonitoring(bool bEnable) = 0;


    /*!
     * @brief Get the CEC version of the device with the given logical address
     * @param iLogicalAddress The logical address of the device to get the CEC version for.
     * @return The version or CEC_VERSION_UNKNOWN when the version couldn't be fetched.
     */
    virtual cec_version GetDeviceCecVersion(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @brief Get the menu language of the device with the given logical address
     * @param iLogicalAddress The logical address of the device to get the menu language for.
     * @param language The requested menu language.
     * @return True when fetched succesfully, false otherwise.
     */
    virtual bool GetDeviceMenuLanguage(cec_logical_address iLogicalAddress, cec_menu_language *language) = 0;


    /*!
     * @brief Get the vendor ID of the device with the given logical address.
     * @param iLogicalAddress The logical address of the device to get the vendor ID for.
     * @return The vendor ID or 0 if it wasn't found.
     */
    virtual uint64_t GetDeviceVendorId(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @brief Get the power status of the device with the given logical address.
     * @param iLogicalAddress The logical address of the device to get the power status for.
     * @return The power status or CEC_POWER_STATUS_UNKNOWN if it wasn't found.
     */
    virtual cec_power_status GetDevicePowerStatus(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @brief Sends a POLL message to a device, to check if it's present and responding.
     * @param iLogicalAddress The device to send the message to.
     * @return True if the POLL was acked, false otherwise.
     */
    virtual bool PollDevice(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @return The logical addresses of the devices that are active on the bus, including those handled by libCEC.
     */
    virtual cec_logical_addresses GetActiveDevices(void) = 0;


    /*!
     * @brief Check whether a device is active on the bus.
     * @param iLogicalAddress The address to check.
     * @return True when active, false otherwise.
     */
    virtual bool IsActiveDevice(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @brief Check whether a device of the given type is active on the bus.
     * @param type The type to check.
     * @return True when active, false otherwise.
     */
    virtual bool IsActiveDeviceType(cec_device_type type) = 0;


    /*!
     * @brief Sends a volume up keypress to an audiosystem if it's present.
     * @param bSendRelease Send a key release after the keypress.
     * @return The new audio status.
     */
    virtual uint8_t VolumeUp(bool bSendRelease = true) = 0;


    /*!
     * @brief Sends a volume down keypress to an audiosystem if it's present.
     * @param bSendRelease Send a key release after the keypress.
     * @return The new audio status.
     */
    virtual uint8_t VolumeDown(bool bSendRelease = true) = 0;


    /*!
     * @deprecated Use AudioToggleMute() instead
     * @brief Sends a mute keypress to an audiosystem if it's present.
     * @param bSendRelease Send a key release after the keypress.
     * @return The new audio status.
     */
    virtual uint8_t MuteAudio(bool bSendRelease = true) = 0;


    /*!
     * @brief Send a keypress to a device on the CEC bus.
     * @param iDestination The logical address of the device to send the message to.
     * @param key The key to send.
     * @param bWait True to wait for a response, false otherwise.
     * @return True when the keypress was acked, false otherwise.
     */
    virtual bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = false) = 0;


    /*!
     * @brief Send a key release to a device on the CEC bus.
     * @param iDestination The logical address of the device to send the message to.
     * @param bWait True to wait for a response, false otherwise.
     * @return True when the key release was acked, false otherwise.
     */
    virtual bool SendKeyRelease(cec_logical_address iDestination, bool bWait = false) = 0;


    /*!
     * @brief Get the OSD name of a device on the CEC bus.
     * @param iLogicalAddress The device to get the OSD name for.
     * @return The OSD name.
     */
    virtual cec_osd_name GetDeviceOSDName(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @brief Get the logical address of the device that is currently the active source on the CEC bus.
     * @return The active source or CECDEVICE_UNKNOWN when unknown.
     */
    virtual cec_logical_address GetActiveSource(void) = 0;


    /*!
     * @brief Check whether a device is currently the active source on the CEC bus.
     * @param iLogicalAddress The logical address of the device to check.
     * @return True when it is the active source, false otherwise.
     */
    virtual bool IsActiveSource(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @brief Sets the stream path to the device on the given logical address.
     * @param iLogicalAddress The address to activate.
     * @return True when the command was sent, false otherwise.
     */
    virtual bool SetStreamPath(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @brief Sets the stream path to the device on the given physical address.
     * @param iPhysicalAddress The address to activate.
     * @return True when the command was sent, false otherwise.
     */
    virtual bool SetStreamPath(uint16_t iPhysicalAddress) = 0;


    /*!
     * @return The list of logical addresses that libCEC is controlling
     */
    virtual cec_logical_addresses GetLogicalAddresses(void) = 0;


    /*!
     * @brief Get libCEC's current configuration.
     * @param configuration The configuration.
     * @return True when the configuration was updated, false otherwise.
     */
    virtual bool GetCurrentConfiguration(libcec_configuration *configuration) = 0;


    /*!
     * @brief Change libCEC's configuration.
     * @param configuration The new configuration.
     * @return True when the configuration was changed successfully, false otherwise.
     */
    virtual bool SetConfiguration(const libcec_configuration *configuration) = 0;


    /*!
     * @return True when this CEC adapter can persist the user configuration, false otherwise.
     */
    virtual bool CanPersistConfiguration(void) = 0;


    /*!
     * @brief Persist the given configuration in adapter (if supported)
     * @brief configuration The configuration to store.
     * @return True when the configuration was persisted, false otherwise.
     */
    virtual bool PersistConfiguration(libcec_configuration *configuration) = 0;


    /*!
     * @brief Tell libCEC to poll for active devices on the bus.
     */
    virtual void RescanActiveDevices(void) = 0;


    /*!
     * @return true when libCEC is the active source on the bus, false otherwise.
     */
    virtual bool IsLibCECActiveSource(void) = 0;


    /*!
     * @brief Get information about the given CEC adapter.
     * @param strPort The port to which the device is connected
     * @param config The device configuration
     * @param iTimeoutMs The timeout in milliseconds
     * @return True when the device was found, false otherwise
     */
    virtual bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = 10000) = 0;


    /*!
     * @brief Set and enable the callback methods. If this method is not called, the GetNext...() methods will have to be used.
     * @param cbParam Parameter to pass to callback methods.
     * @param callbacks The callbacks to set.
     * @return True when enabled, false otherwise.
     */
    virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) = 0;


    /*!
     * @brief Changes the active HDMI port.
     * @param iBaseDevice The device to which this libCEC is connected.
     * @param iPort The new port number.
     * @return True when changed, false otherwise.
     */
    virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort) = 0;


    /*!
     * @brief Get the physical address of the device with the given logical address.
     * @param iLogicalAddress The logical address of the device to get the physical address for.
     * @return The physical address or 0 if it wasn't found.
     */
    virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iLogicalAddress) = 0;


    /*!
     * @return A string with information about how libCEC was compiled.
     */
    virtual const char *GetLibInfo(void) = 0;


    /*!
     * @brief Calling this method will initialise the host on which libCEC is running.
     * Calling this method will initialise the host on which libCEC is running. On the RPi, it calls
     * bcm_host_init(), which may only be called once per process, and is called by any process using
     * the video api on that system. So only call this method if libCEC is used in an application that
     * does not already initialise the video api.
     *
     * Should be called as first call to libCEC, directly after CECInitialise() and before using Open()
     */
    virtual void InitVideoStandalone(void) = 0;


    /*!
     * @return The (virtual) USB vendor id
     */
    virtual uint16_t GetAdapterVendorId(void) const = 0;


    /*!
     * @return The (virtual) USB product id
     */
    virtual uint16_t GetAdapterProductId(void) const = 0;


    virtual const char *ToString(const cec_menu_state state) = 0;
    virtual const char *ToString(const cec_version version) = 0;
    virtual const char *ToString(const cec_power_status status) = 0;
    virtual const char *ToString(const cec_logical_address address) = 0;
    virtual const char *ToString(const cec_deck_control_mode mode) = 0;
    virtual const char *ToString(const cec_deck_info status) = 0;
    virtual const char *ToString(const cec_opcode opcode) = 0;
    virtual const char *ToString(const cec_system_audio_status mode) = 0;
    virtual const char *ToString(const cec_audio_status status) = 0;
    virtual const char *ToString(const cec_vendor_id vendor) = 0;
    virtual const char *ToString(const cec_client_version version) = 0;
    virtual const char *ToString(const cec_server_version version) = 0;
    virtual const char *ToString(const cec_user_control_code key) = 0;
    virtual const char *ToString(const cec_adapter_type type) = 0;


    /*!
     * @brief Toggle the mute status of the AVR (if present)
     * @return The new audio status.
     */
    virtual uint8_t AudioToggleMute(void) = 0;


    /*!
     * @brief Mute the AVR (if present)
     * @return The new audio status.
     */
    virtual uint8_t AudioMute(void) = 0;


    /*!
     * @brief Mute the AVR (if connected)
     * @return The new audio status.
     */
    virtual uint8_t AudioUnmute(void) = 0;


    /*!
     * @brief Get the current audio status (if an AVR is connected)
     * @return The current audio status, or cec_audio_status if unknown.
     */
    virtual uint8_t AudioStatus(void) = 0;


    /*!
     * @brief Try to find all connected CEC adapters.
     * @param deviceList The vector to store device descriptors in.
     * @param iBufSize The size of the deviceList buffer.
     * @param strDevicePath Optional device path. Only adds device descriptors that match the given device path.
     * @param bQuickScan True to do a "quick scan", which will not open a connection to the adapter. Firmware version information and the exact device type will be missing
     * @return The number of devices that were found, or -1 when an error occured.
     */
    virtual int8_t DetectAdapters(cec_adapter_descriptor *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL, bool bQuickScan = false) = 0;


  };
};


/*!
 * @brief Unload the CEC adapter library.
 */
extern "C" DECLSPEC void CECDestroy(CEC::ICECAdapter *instance);


/*!
 * @brief Load the CEC adapter library.
 * @param configuration The configuration to pass to libCEC
 * @return An instance of ICECAdapter or NULL on error.
 */
extern "C" DECLSPEC void * CECInitialise(CEC::libcec_configuration *configuration);


/*!
 * @brief Try to connect to the adapter and send the "start bootloader" command, without initialising libCEC and going through all checks
 * @return True when the command was send, false otherwise.
 */
extern "C" DECLSPEC bool CECStartBootloader(void);


#endif /* CECEXPORTS_H_ */

Now, as you can see, the comments sound very helpful. They tell you which functions to call to initialize the device and open communications with it. It tells you to "pass the configuration as argument" to the CECInitialise function, but they don't tell you what the valid values are, or what they mean.

Dig down a little more into the header file, and you'll find the CECInitialise function. One would hope to find comments there that describe the valid values. One would be disappointed to find that there are none.

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Thu Aug 15, 2013 7:45 pm

I've been studying the header file more, and I've looked at the cectypes.h file too. I see now, that the parameter that gets passed to the CECInitialise function is defined as shown below:

Code: Select all

struct libcec_configuration
{
  uint32_t              clientVersion;        /*!< the version of the client that is connecting */
  char                  strDeviceName[13];    /*!< the device name to use on the CEC bus */
  cec_device_type_list  deviceTypes;          /*!< the device type(s) to use on the CEC bus for libCEC */
  uint8_t               bAutodetectAddress;   /*!< (read only) set to 1 by libCEC when the physical address was autodetected */
  uint16_t              iPhysicalAddress;     /*!< the physical address of the CEC adapter */
  cec_logical_address   baseDevice;           /*!< the logical address of the device to which the adapter is connected. only used when iPhysicalAddress = 0 or when the adapter doesn't support autodetection */
  uint8_t               iHDMIPort;            /*!< the HDMI port to which the adapter is connected. only used when iPhysicalAddress = 0 or when the adapter doesn't support autodetection */
  uint64_t              tvVendor;             /*!< override the vendor ID of the TV. leave this untouched to autodetect */
  cec_logical_addresses wakeDevices;          /*!< list of devices to wake when initialising libCEC or when calling PowerOnDevices() without any parameter. */
  cec_logical_addresses powerOffDevices;      /*!< list of devices to power off when calling StandbyDevices() without any parameter. */


  uint32_t              serverVersion;        /*!< the version number of the server. read-only */


  // player specific settings
  uint8_t               bGetSettingsFromROM;  /*!< true to get the settings from the ROM (if set, and a v2 ROM is present), false to use these settings. */
  uint8_t               bUseTVMenuLanguage;   /*!< use the menu language of the TV in the player application */
  uint8_t               bActivateSource;      /*!< make libCEC the active source on the bus when starting the player application */
  uint8_t               bPowerOffScreensaver; /*!< put devices in standby mode when activating the screensaver */
  uint8_t               bPowerOnScreensaver;  /*!< wake devices when deactivating the screensaver */
  uint8_t               bPowerOffOnStandby;   /*!< put this PC in standby mode when the TV is switched off. only used when bShutdownOnStandby = 0  */
  uint8_t               bSendInactiveSource;  /*!< send an 'inactive source' message when stopping the player. added in 1.5.1 */


  void *                callbackParam;        /*!< the object to pass along with a call of the callback methods. NULL to ignore */
  ICECCallbacks *       callbacks;            /*!< the callback methods to use. set this to NULL when not using callbacks */


  cec_logical_addresses logicalAddresses;     /*!< (read-only) the current logical addresses. added in 1.5.3 */
  uint16_t              iFirmwareVersion;     /*!< (read-only) the firmware version of the adapter. added in 1.6.0 */
  uint8_t               bPowerOffDevicesOnStandby; /*!< put devices in standby when the PC/player is put in standby. added in 1.6.0 */
  uint8_t               bShutdownOnStandby;   /*!< shutdown this PC when the TV is switched off. only used when bPowerOffOnStandby = 0. added in 1.6.0 */
  char                  strDeviceLanguage[3]; /*!< the menu language used by the client. 3 character ISO 639-2 country code. see http://http://www.loc.gov/standards/iso639-2/ added in 1.6.2 */
  uint32_t              iFirmwareBuildDate;   /*!< (read-only) the build date of the firmware, in seconds since epoch. if not available, this value will be set to 0. added in 1.6.2 */
  uint8_t               bMonitorOnly;         /*!< won't allocate a CCECClient when starting the connection when set (same as monitor mode). added in 1.6.3 */
  cec_version           cecVersion;           /*!< CEC spec version to use by libCEC. defaults to v1.4. added in 1.8.0 */
  cec_adapter_type      adapterType;          /*!< type of the CEC adapter that we're connected to. added in 1.8.2 */
  uint8_t               iDoubleTapTimeoutMs;  /*!< prevent double taps withing this timeout. defaults to 200ms. added in 2.0.0 */
  cec_user_control_code comboKey;             /*!< key code that initiates combo keys. defaults to CEC_USER_CONTROL_CODE_F1_BLUE. CEC_USER_CONTROL_CODE_UNKNOWN to disable. added in 2.0.5 */
  uint32_t              iComboKeyTimeoutMs;   /*!< timeout until the combo key is sent as normal keypress */


#ifdef __cplusplus
   libcec_configuration(void) { Clear(); }
  ~libcec_configuration(void) { Clear(); }


  bool operator==(const libcec_configuration &other) const
  {
    return (     clientVersion             == other.clientVersion &&
        !strncmp(strDeviceName,               other.strDeviceName, 13) &&
                  deviceTypes               == other.deviceTypes &&
                  bAutodetectAddress        == other.bAutodetectAddress &&
                  iPhysicalAddress          == other.iPhysicalAddress &&
                  baseDevice                == other.baseDevice &&
                  iHDMIPort                 == other.iHDMIPort &&
                  tvVendor                  == other.tvVendor &&
                  wakeDevices               == other.wakeDevices &&
                  powerOffDevices           == other.powerOffDevices &&
                  serverVersion             == other.serverVersion &&
                  bGetSettingsFromROM       == other.bGetSettingsFromROM &&
                  bUseTVMenuLanguage        == other.bUseTVMenuLanguage &&
                  bActivateSource           == other.bActivateSource &&
                  bPowerOffScreensaver      == other.bPowerOffScreensaver &&
                  bPowerOffOnStandby        == other.bPowerOffOnStandby &&
                  bSendInactiveSource       == other.bSendInactiveSource &&
                  logicalAddresses          == other.logicalAddresses &&
                  iFirmwareVersion          == other.iFirmwareVersion &&
                  bPowerOffDevicesOnStandby == other.bPowerOffDevicesOnStandby &&
                  bShutdownOnStandby        == other.bShutdownOnStandby &&
        !strncmp(strDeviceLanguage,           other.strDeviceLanguage, 3) &&
                  iFirmwareBuildDate        == other.iFirmwareBuildDate &&
                  bMonitorOnly              == other.bMonitorOnly &&
                  cecVersion                == other.cecVersion &&
                  adapterType               == other.adapterType &&
                  iDoubleTapTimeoutMs       == other.iDoubleTapTimeoutMs &&
                  (other.clientVersion <= CEC_CLIENT_VERSION_2_0_4 || comboKey            == other.comboKey) &&
                  (other.clientVersion <= CEC_CLIENT_VERSION_2_0_4 || iComboKeyTimeoutMs  == other.iComboKeyTimeoutMs) &&
                  (other.clientVersion <  CEC_CLIENT_VERSION_2_1_0 || bPowerOnScreensaver == other.bPowerOnScreensaver));
  }
This gives me a better idea of what libCEC requires for this parameter, but I'm not sure how that would be formatted in Python. I'd appreciate an example of how to pass a parameter that is essentially an array of various other parameters, each having its own type.

krambriw
Plugin Developer
Posts: 2570
Joined: Sat Jun 30, 2007 2:51 pm
Location: Stockholm, Sweden
Contact:

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by krambriw » Thu Aug 15, 2013 8:05 pm

You are right and I think you are on the right track. I think I mentioned earlier, have a look at my TellStickDuo plugin code. There you can see how I define the device methods, error codes etc..

Then you have to import the ctypes you will use when calling the dll like in this sample:

Code: Select all

from ctypes import(
	windll, WINFUNCTYPE, POINTER, string_at,
	wstring_at, c_char_p, c_int, c_ubyte, c_void_p	
)
Then load the library and initialize the device (like this sample for the TellStickDuo usb device)

Code: Select all

        print "Loading library"
        try:
            self.dll = windll.LoadLibrary("TelldusCore.dll")
        except: 
            raise eg.Exception(self.text.init_exception_txt)

        self.dll.tdInit()
I do not know if you expect to receive events also, in that case it might that you have to register callback functions as well (also this is done in my plugin).

Try to make it very simple to start with, maybe just a python script that initiates the device, maybe does something more. Then extend it when you got it working. Once this is working for you, it will be easy to make a first plugin, then build further, adding more and more..

I do not have a Pulse Eight (and currently no need for it) but we can for sure discuss the sw

Best, Walter

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Thu Aug 15, 2013 8:35 pm

Thank you Walter. As always, I appreciate your thoughtful advice and patience.

I intend to do exactly as you say. I wanted to first create a plugin that will initialize/connect to the device. Then, once that is successful, I will try a simple function such as asking the device for it's firmware version, logical address, or something similarly simple.

Once I am successful at this, I will move on to attempting to turn my TV on/off.

I do plan to receive events as well. I understand that this requires starting a new thread in the plugin. The developer documentation (and the simple tutorial for creating my first plugin) on the EG website is very helpful in this regard.

I'll look at your TellStickDuo plugin and I'll be back with questions. Does the TellStickDuo plugin have a parameter like the one I listed above? It would be wonderful if it does.

After reading more of Pulse-Eight's comments, I see that a good starting place is their "tester" applications. I've begun to read the source of those to get more information about the properties/attributes that must be set prior to calling the functions, and also to get the order in which the functions need to be called for a successful implementation.

I hope to have some progress by the end of this weekend.

Thank you again for your help, patience, and insight. It is very much appreciated.

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Thu Aug 15, 2013 8:45 pm

One more question:

Pulse-Eight supplies both a C++ library, and a C# library. In their README (quoted again below for convenience), they say that C and .NET developers should use their C# library. Python is neither C nor .NET. Do you think it would be easier to use their C# library in Python than it would be to use their C++ library? It seems to me, that it shouldn't matter. When loading a compiled DLL, all one needs to do is call the functions in the library with the appropriate parameters. But I thought I should ask before I get too far down the wrong road.
We provide a C, C++ and .NET CLR interface to the adapter.

C++ developers:
* the API can be found in /include/cec.h
* an example implementation can be found in /src/testclient/main.cpp

C developers:
* the API can be found in /include/cecc.h

.NET developers:
* add a reference to LibCecSharp.dll
* an example can be found in \src\CecSharpTester\CecSharpClient.cs

krambriw
Plugin Developer
Posts: 2570
Joined: Sat Jun 30, 2007 2:51 pm
Location: Stockholm, Sweden
Contact:

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by krambriw » Fri Aug 16, 2013 4:17 am

I have used C++ dll's

I think C++ will be fine but if it is simpler to interface using the .NET, it might be worth investigating, maybe there is an *easier* way

http://stackoverflow.com/questions/1168 ... python-net

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Fri Aug 16, 2013 8:50 pm

I can certainly read the C# code easier than I can read the C++ code!

I'll make my decision tonight or tomorrow, and start coding Saturday afternoon.

Ganapoes
Posts: 6
Joined: Mon Dec 05, 2011 7:51 am
Contact:

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by Ganapoes » Sat Aug 17, 2013 2:48 am

I'm buying one of these devices just to play with it.

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Sat Aug 17, 2013 9:35 pm

After some analysis, the two DLL's (C++ and C#) seem to have the same functions. Purely based on the ease of reading the C# source, I'm moving forward with the C# DLL.

So far, I have a basic shell of a plugin that works. Now, I need to load the DLL and try to use it to connect to the device, and execute a simple function to communicate with the CEC bus (e.g. "turn on the TV").

I'm using the C# "tester" application's source as a guide.

<rant>
It sure would be nice if Pulse-Eight would provide some actual documentation for their DLL and software!
</rant>

User avatar
Livin
Experienced User
Posts: 792
Joined: Wed Oct 08, 2008 4:56 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by Livin » Sat Aug 17, 2013 10:12 pm

barnabas1969
Did you try to contact Chri21 on teh P.E. forums? He wrote a CEC-Tray app many people are using. I suspect he can help
setup... XBMC, W7MC for DVR & Live OTA TV, JRMC for multi-zone audio, EG, MiCasaVerde Vera3, USB-UIRT IR receiver, Harmony remote, 5.2 home theater system

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Sat Aug 17, 2013 10:27 pm

@Livin: No, I haven't. His program is closed-source, as far as I can tell. Besides, even if he shared his source with me, that wouldn't help me integrate it into EventGhost.

The Pulse-Eight (P8) tray application has some bugs... especially when dealing with standby/resume. But the biggest failure on the part of P8 is the lack of configuration options (well... their lack of documentation might rank even higher). It appears, based on Chri21's description (on his webpage) of the software, that the only configurable buttons are the RGBY keys. If I can make this thing work in EventGhost, anyone will be able to do anything with this device!

No single piece of software can fit every need... except EventGhost.

For example, the P8 developers didn't think it was necessary to turn on the TV when the PC resumes from standby! Obviously, you wouldn't want your TV to turn on when the PC resumes for scheduled tasks (like scheduled TV recordings and Windows and/or Media Center updates... or, in the case of those who have extenders for Media Center... you don't want the TV which is connected to the PC to turn on when the PC wakes due to a WOL packet when one of your extenders turns on).

EG provides solutions to all of those problems! Via events and macros (and a little creative thinking), EG can solve the whole problem... if only the P8 device could be controlled from EG!

So... instead of being locked-in to a closed-source developer's idea of what your system should do... wouldn't you rather be able to CHOOSE what your system does when X happens?

I think that's the whole purpose of EG. EG is the most versatile software I've ever encountered. The possibilities are endless.

barnabas1969
Experienced User
Posts: 133
Joined: Sat Feb 04, 2012 1:42 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by barnabas1969 » Sat Aug 17, 2013 10:33 pm

Oh, and I suppose that I should mention that the C# "tester" app works fine. I've seen several posts on the P8 forums where people are asking for the commands that it supports (it's the command-line program).

Simply running the program and typing "h" at the prompt lists all the possible commands. This was easily evident when reviewing the source code for the program. I was able to successfully use the "tester" app to turn my TV on/off, change inputs, etc.

So, I believe that the "tester" app is a good place to begin, so that I can understand the flow of interaction with the device.

Now, I need to get back to coding. I'm stuck at loading the DLL right now. I used Walter's example in a previous post to load the DLL, and it failed. I suspect that there is more to it than what Walter posted, so I'm going to look at his TellStickDuo plugin to find the answers. If I am not successful at loading the DLL after reading the code for his plugin, I'll post back here for more help.

User avatar
Livin
Experienced User
Posts: 792
Joined: Wed Oct 08, 2008 4:56 am

Re: HDMI-CEC to USB EG Support for Pulse Eight

Post by Livin » Sat Aug 17, 2013 10:42 pm

barnabas1969 wrote:@Livin: No, I haven't. His program is closed-source, as far as I can tell. Besides, even if he shared his source with me, that wouldn't help me integrate it into EventGhost.

The Pulse-Eight (P8) tray application has some bugs... especially when dealing with standby/resume. But the biggest failure on the part of P8 is the lack of configuration options (well... their lack of documentation might rank even higher). It appears, based on Chri21's description (on his webpage) of the software, that the only configurable buttons are the RGBY keys. If I can make this thing work in EventGhost, anyone will be able to do anything with this device!

No single piece of software can fit every need... except EventGhost.

For example, the P8 developers didn't think it was necessary to turn on the TV when the PC resumes from standby! Obviously, you wouldn't want your TV to turn on when the PC resumes for scheduled tasks (like scheduled TV recordings and Windows and/or Media Center updates... or, in the case of those who have extenders for Media Center... you don't want the TV which is connected to the PC to turn on when the PC wakes due to a WOL packet when one of your extenders turns on).

EG provides solutions to all of those problems! Via events and macros (and a little creative thinking), EG can solve the whole problem... if only the P8 device could be controlled from EG!

So... instead of being locked-in to a closed-source developer's idea of what your system should do... wouldn't you rather be able to CHOOSE what your system does when X happens?

I think that's the whole purpose of EG. EG is the most versatile software I've ever encountered. The possibilities are endless.
I did not think he'd give you source code... but he might help you if you have questions about the API, functions, etc.
setup... XBMC, W7MC for DVR & Live OTA TV, JRMC for multi-zone audio, EG, MiCasaVerde Vera3, USB-UIRT IR receiver, Harmony remote, 5.2 home theater system

Post Reply