LibCecSharp: better handling of callbacks
[deb_libcec.git] / src / LibCecSharp / LibCecSharp.cpp
index 6e4895e8cbf9119acfac0a25e9152869c4e8de71..cd0f6d05d3ae239afc2e8286b9e1ae7694c2e2c8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the libCEC(R) library.
  *
- * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
  * libCEC(R) is an original work, containing original code.
  *
  * libCEC(R) is a trademark of Pulse-Eight Limited.
  *     http://www.pulse-eight.net/
  */
 
-#include "stdafx.h"
-#include <windows.h>
-#include <vcclr.h>
-#include <msclr/marshal.h>
-#include <cec.h>
+#include "CecSharpTypes.h"
 #using <System.dll>
 
 using namespace System;
+using namespace System::Runtime::InteropServices;
 using namespace CEC;
 using namespace msclr::interop;
 
-public enum class CecDeviceType
+namespace CecSharp
 {
-  Tv              = 0,
-  RecordingDevice = 1,
-  Reserved        = 2,
-  Tuner           = 3,
-  PlaybackDevice  = 4,
-  AudioSystem     = 5
-};
-
-public enum class CecLogLevel
-{
-  None    = 0,
-  Error   = 1,
-  Warning = 2,
-  Notice  = 4,
-  Traffic = 8,
-  Debug   = 16,
-  All     = 31
-};
-
-public enum class CecLogicalAddress
-{
-  Unknown          = -1, //not a valid logical address
-  Tv               = 0,
-  RecordingDevice1 = 1,
-  RecordingDevice2 = 2,
-  Tuner1           = 3,
-  PlaybackDevice1  = 4,
-  AudioSystem      = 5,
-  Tuner2           = 6,
-  Tuner3           = 7,
-  PlaybackDevice2  = 8,
-  RecordingDevice3 = 9,
-  Tuner4           = 10,
-  PlaybackDevice3  = 11,
-  Reserved1        = 12,
-  Reserved2        = 13,
-  FreeUse          = 14,
-  Unregistered     = 15,
-  Broadcast        = 15
-};
-
-public enum class CecPowerStatus
-{
-  On                      = 0x00,
-  Standby                 = 0x01,
-  InTransitionStandbyToOn = 0x02,
-  InTransitionOnToStandby = 0x03,
-  Unknown                 = 0x99
-};
-
-public enum class CecVersion
-{
-  Unknown = 0x00,
-  V1_2    = 0x01,
-  V1_2A   = 0x02,
-  V1_3    = 0x03,
-  V1_3A   = 0x04,
-  V1_4    = 0x05
-};
-
-public enum class CecDisplayControl
-{
-  DisplayForDefaultTime = 0x00,
-  DisplayUntilCleared   = 0x40,
-  ClearPreviousMessage  = 0x80,
-  ReservedForFutureUse  = 0xC0
-};
-
-public enum class CecMenuState
-{
-  Activated   = 0,
-  Deactivated = 1
-};
-
-public enum class CecDeckControlMode
-{
-  SkipForwardWind   = 1,
-  SkipReverseRewind = 2,
-  Stop              = 3,
-  Eject             = 4
-};
-
-public enum class CecDeckInfo
-{
-  Play               = 0x11,
-  Record             = 0x12,
-  Reverse            = 0x13,
-  Still              = 0x14,
-  Slow               = 0x15,
-  SlowReverse        = 0x16,
-  FastForward        = 0x17,
-  FastReverse        = 0x18,
-  NoMedia            = 0x19,
-  Stop               = 0x1A,
-  SkipForwardWind    = 0x1B,
-  SkipReverseRewind  = 0x1C,
-  IndexSearchForward = 0x1D,
-  IndexSearchReverse = 0x1E,
-  OtherStatus        = 0x1F
-};
-
-public enum class CecUserControlCode
-{
-  Select                      = 0x00,
-  Up                          = 0x01,
-  Down                        = 0x02,
-  Left                        = 0x03,
-  Right                       = 0x04,
-  RightUp                     = 0x05,
-  RightDown                   = 0x06,
-  LeftUp                      = 0x07,
-  LeftDown                    = 0x08,
-  RootMenu                    = 0x09,
-  SetupMenu                   = 0x0A,
-  ContentsMenu                = 0x0B,
-  FavoriteMenu                = 0x0C,
-  Exit                        = 0x0D,
-  Number0                     = 0x20,
-  Number1                     = 0x21,
-  Number2                     = 0x22,
-  Number3                     = 0x23,
-  Number4                     = 0x24,
-  Number5                     = 0x25,
-  Number6                     = 0x26,
-  Number7                     = 0x27,
-  Number8                     = 0x28,
-  Number9                     = 0x29,
-  Dot                         = 0x2A,
-  Enter                       = 0x2B,
-  Clear                       = 0x2C,
-  NextFavorite                = 0x2F,
-  ChannelUp                   = 0x30,
-  ChannelDown                 = 0x31,
-  PreviousChannel             = 0x32,
-  SoundSelect                 = 0x33,
-  InputSelect                 = 0x34,
-  DisplayInformation          = 0x35,
-  Help                        = 0x36,
-  PageUp                      = 0x37,
-  PageDown                    = 0x38,
-  Power                       = 0x40,
-  VolumeUp                    = 0x41,
-  VolumeDown                  = 0x42,
-  Mute                        = 0x43,
-  Play                        = 0x44,
-  Stop                        = 0x45,
-  Pause                       = 0x46,
-  Record                      = 0x47,
-  Rewind                      = 0x48,
-  FastForward                 = 0x49,
-  Eject                       = 0x4A,
-  Forward                     = 0x4B,
-  Backward                    = 0x4C,
-  StopRecord                  = 0x4D,
-  PauseRecord                 = 0x4E,
-  Angle                       = 0x50,
-  SubPicture                  = 0x51,
-  VideoOnDemand               = 0x52,
-  ElectronicProgramGuide      = 0x53,
-  TimerProgramming            = 0x54,
-  InitialConfiguration        = 0x55,
-  PlayFunction                = 0x60,
-  PausePlayFunction           = 0x61,
-  RecordFunction              = 0x62,
-  PauseRecordFunction         = 0x63,
-  StopFunction                = 0x64,
-  MuteFunction                = 0x65,
-  RestoreVolumeFunction       = 0x66,
-  TuneFunction                = 0x67,
-  SelectMediaFunction         = 0x68,
-  SelectAVInputFunction       = 0x69,
-  SelectAudioInputFunction    = 0x6A,
-  PowerToggleFunction         = 0x6B,
-  PowerOffFunction            = 0x6C,
-  PowerOnFunction             = 0x6D,
-  F1Blue                      = 0x71,
-  F2Red                       = 0X72,
-  F3Green                     = 0x73,
-  F4Yellow                    = 0x74,
-  F5                          = 0x75,
-  Data                        = 0x76,
-  Max                         = 0x76,
-  Unknown
-};
-
-public ref class CecAdapter
-{
-public:
-  CecAdapter(String ^ strPath, String ^ strComPort)
-  {
-    Path = strPath;
-    ComPort = strComPort;
-  }
-
-  property String ^ Path;
-  property String ^ ComPort;
-};
-
-public ref class CecDeviceTypeList
-{
-public:
-  CecDeviceTypeList(void)
-  {
-    Types = gcnew array<CecDeviceType>(5);
-    for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
-      Types[iPtr] = CecDeviceType::Reserved;
-  }
-
-  property array<CecDeviceType> ^ Types;
-};
-
-public ref class CecLogicalAddresses
-{
-public:
-  CecLogicalAddresses(void)
-  {
-    Addresses = gcnew array<CecLogicalAddress>(16);
-    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
-      Addresses[iPtr] = CecLogicalAddress::Unregistered;
-  }
-
-  property array<CecLogicalAddress> ^ Addresses;
-};
-
-public ref class CecDatapacket
-{
-public:
-  CecDatapacket(void)
-  {
-    Data = gcnew array<uint8_t>(100);
-    Size = 0;
-  }
-
-  void PushBack(uint8_t data)
-  {
-    if (Size < 100)
+       public ref class LibCecSharp : public CecCallbackMethods
+       {
+       public:
+         LibCecSharp(LibCECConfiguration ^config)
+               {
+      m_callbacks = config->Callbacks;
+                       CecCallbackMethods::EnableCallbacks(m_callbacks);
+                       if (!InitialiseLibCec(config))
+                               throw gcnew Exception("Could not initialise LibCecSharp");
+               }
+
+               LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes)
+               {
+      m_callbacks = gcnew CecCallbackMethods();
+                       LibCECConfiguration ^config = gcnew LibCECConfiguration();
+                       config->SetCallbacks(this);
+                       config->DeviceName  = strDeviceName;
+                       config->DeviceTypes = deviceTypes;
+                       if (!InitialiseLibCec(config))
+                               throw gcnew Exception("Could not initialise LibCecSharp");
+               }
+          
+               ~LibCecSharp(void)
+               {
+                       Close();
+                       m_libCec = NULL;
+               }
+
+       private:
+               !LibCecSharp(void)
+               {
+                       Close();
+                       m_libCec = NULL;
+               }
+
+               bool InitialiseLibCec(LibCECConfiguration ^config)
+               {
+                       marshal_context ^ context = gcnew marshal_context();
+                       libcec_configuration libCecConfig;
+                       ConvertConfiguration(context, config, libCecConfig);
+
+                       m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig);
+                       config->Update(libCecConfig);
+
+                       delete context;
+                       return m_libCec != NULL;
+               }
+
+         void ConvertConfiguration(marshal_context ^context, LibCECConfiguration ^netConfig, CEC::libcec_configuration &config)
+               {
+                       config.Clear();
+
+                       const char *strDeviceName = context->marshal_as<const char*>(netConfig->DeviceName);
+                       memcpy_s(config.strDeviceName, 13, strDeviceName, 13);
+                       for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+                               config.deviceTypes.types[iPtr] = (cec_device_type)netConfig->DeviceTypes->Types[iPtr];
+
+                       config.bAutodetectAddress   = netConfig->AutodetectAddress ? 1 : 0;
+                       config.iPhysicalAddress     = netConfig->PhysicalAddress;
+                       config.baseDevice           = (cec_logical_address)netConfig->BaseDevice;
+                       config.iHDMIPort            = netConfig->HDMIPort;
+                       config.clientVersion        = (cec_client_version)netConfig->ClientVersion;
+                       config.bGetSettingsFromROM  = netConfig->GetSettingsFromROM ? 1 : 0;
+                       config.bActivateSource      = netConfig->ActivateSource ? 1 : 0;
+                       config.tvVendor             = (cec_vendor_id)netConfig->TvVendor;
+                       config.wakeDevices.Clear();
+                       for (int iPtr = 0; iPtr < 16; iPtr++)
+                       {
+                               if (netConfig->WakeDevices->IsSet((CecLogicalAddress)iPtr))
+                                       config.wakeDevices.Set((cec_logical_address)iPtr);
+                       }
+                       config.powerOffDevices.Clear();
+                       for (int iPtr = 0; iPtr < 16; iPtr++)
+                       {
+                               if (netConfig->PowerOffDevices->IsSet((CecLogicalAddress)iPtr))
+                                       config.powerOffDevices.Set((cec_logical_address)iPtr);
+                       }
+                       config.bPowerOffScreensaver = netConfig->PowerOffScreensaver ? 1 : 0;
+                       config.bPowerOffOnStandby   = netConfig->PowerOffOnStandby ? 1 : 0;
+
+                       if (netConfig->ServerVersion >= CecServerVersion::Version1_5_1)
+                               config.bSendInactiveSource  = netConfig->SendInactiveSource ? 1 : 0;
+
+                       if (netConfig->ServerVersion >= CecServerVersion::Version1_6_0)
+                       {
+                               config.bPowerOffDevicesOnStandby  = netConfig->PowerOffDevicesOnStandby ? 1 : 0;
+                               config.bShutdownOnStandby         = netConfig->ShutdownOnStandby ? 1 : 0;
+                       }
+
+                       if (netConfig->ServerVersion >= CecServerVersion::Version1_6_2)
+                       {
+                               const char *strDeviceLanguage = context->marshal_as<const char*>(netConfig->DeviceLanguage);
+                               memcpy_s(config.strDeviceLanguage, 3, strDeviceLanguage, 3);
+                       }
+
+                       if (netConfig->ServerVersion >= CecServerVersion::Version1_6_3)
+                         config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0;
+
+                       config.callbacks = &g_cecCallbacks;
+               }
+
+       public:
+               array<CecAdapter ^> ^ FindAdapters(String ^ path)
+               {
+                       cec_adapter *devices = new cec_adapter[10];
+
+                       marshal_context ^ context = gcnew marshal_context();
+                       const char* strPathC = path->Length > 0 ? context->marshal_as<const char*>(path) : NULL;
+
+                       uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL);
+
+                       array<CecAdapter ^> ^ adapters = gcnew array<CecAdapter ^>(iDevicesFound);
+                       for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++)
+                               adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm));
+
+                       delete devices;
+                       delete context;
+                       return adapters;
+               }
+
+               bool Open(String ^ strPort, int iTimeoutMs)
+               {
+      CecCallbackMethods::EnableCallbacks(m_callbacks);
+      EnableCallbacks(m_callbacks);
+                       marshal_context ^ context = gcnew marshal_context();
+                       const char* strPortC = context->marshal_as<const char*>(strPort);
+                       bool bReturn = m_libCec->Open(strPortC, iTimeoutMs);
+                       delete context;
+                       return bReturn;
+               }
+
+               void Close(void)
+               {
+                       DisableCallbacks();
+                       m_libCec->Close();
+               }
+
+               virtual void DisableCallbacks(void) override
+               {
+                       // delete the callbacks, since these might already have been destroyed in .NET
+                       CecCallbackMethods::DisableCallbacks();
+                       if (m_libCec)
+                               m_libCec->EnableCallbacks(NULL, NULL);
+               }
+
+               virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override
+               {
+                       if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks))
+                               return m_libCec->EnableCallbacks((void*)GetCallbackPtr(), &g_cecCallbacks);
+
+                       return false;
+               }
+
+               bool PingAdapter(void)
+               {
+                       return m_libCec->PingAdapter();
+               }
+
+               bool StartBootloader(void)
+               {
+                       return m_libCec->StartBootloader();
+               }
+
+               int GetMinLibVersion(void)
+               {
+                       return m_libCec->GetMinLibVersion();
+               }
+
+               int GetLibVersionMajor(void)
+               {
+                       return m_libCec->GetLibVersionMajor();
+               }
+
+               int GetLibVersionMinor(void)
+               {
+                       return m_libCec->GetLibVersionMinor();
+               }
+
+               CecLogMessage ^ GetNextLogMessage(void)
+               {
+                       cec_log_message msg;
+                       if (m_libCec->GetNextLogMessage(&msg))
+                       {
+                               return gcnew CecLogMessage(gcnew String(msg.message), (CecLogLevel)msg.level, msg.time);
+                       }
+
+                       return gcnew CecLogMessage();
+               }
+
+               CecKeypress ^ GetNextKeypress(void)
+               {
+                       cec_keypress key;
+                       if (m_libCec->GetNextKeypress(&key))
+                       {
+                               return gcnew CecKeypress((CecUserControlCode)key.keycode, key.duration);
+                       }
+
+                       return gcnew CecKeypress();
+               }
+
+               CecCommand ^ GetNextCommand(void)
+               {
+                       cec_command command;
+                       if (m_libCec->GetNextCommand(&command))
+                       {
+                               CecCommand ^ retVal = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, (CecOpcode)command.opcode, command.transmit_timeout);
+                               for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
+                                       retVal->Parameters->PushBack(command.parameters[iPtr]);
+                               return retVal;
+                       }
+
+                       return gcnew CecCommand();
+               }
+
+               bool Transmit(CecCommand ^ command)
+               {
+                       cec_command ccommand;
+                       cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode);
+                       ccommand.transmit_timeout = command->TransmitTimeout;
+                       ccommand.eom              = command->Eom;
+                       ccommand.ack              = command->Ack;
+                       for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++)
+                               ccommand.parameters.PushBack(command->Parameters->Data[iPtr]);
+
+                       return m_libCec->Transmit(ccommand);
+               }
+
+               bool SetLogicalAddress(CecLogicalAddress logicalAddress)
+               {
+                       return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress);
+               }
+
+               bool SetPhysicalAddress(uint16_t physicalAddress)
+               {
+                       return m_libCec->SetPhysicalAddress(physicalAddress);
+               }
+
+               bool PowerOnDevices(CecLogicalAddress logicalAddress)
+               {
+                       return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress);
+               }
+
+               bool StandbyDevices(CecLogicalAddress logicalAddress)
+               {
+                       return m_libCec->StandbyDevices((cec_logical_address) logicalAddress);
+               }
+
+               bool PollDevice(CecLogicalAddress logicalAddress)
+               {
+                       return m_libCec->PollDevice((cec_logical_address) logicalAddress);
+               }
+
+               bool SetActiveSource(CecDeviceType type)
+               {
+                       return m_libCec->SetActiveSource((cec_device_type) type);
+               }
+
+               bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate)
+               {
+                       return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate);
+               }
+
+               bool SetDeckInfo(CecDeckInfo info, bool sendUpdate)
+               {
+                       return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate);
+               }
+
+               bool SetInactiveView(void)
+               {
+                       return m_libCec->SetInactiveView();
+               }
+
+               bool SetMenuState(CecMenuState state, bool sendUpdate)
+               {
+                       return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate);
+               }
+
+               bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message)
+               {
+                       marshal_context ^ context = gcnew marshal_context();
+                       const char* strMessageC = context->marshal_as<const char*>(message);
+
+                       bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC);
+
+                       delete context;
+                       return bReturn;
+               }
+
+               bool SwitchMonitoring(bool enable)
+               {
+                       return m_libCec->SwitchMonitoring(enable);
+               }
+
+               CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress)
+               {
+                       return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress);
+               }
+
+               String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress)
+               {
+                       cec_menu_language lang;
+                       if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang))
+                       {
+                               return gcnew String(lang.language);
+                       }
+
+                       return gcnew String("");
+               }
+
+               CecVendorId GetDeviceVendorId(CecLogicalAddress logicalAddress)
+               {
+                       return (CecVendorId)m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress);
+               }
+
+               CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress)
+               {
+                       return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress);
+               }
+
+               void RescanActiveDevices(void)
+               {
+                       m_libCec->RescanActiveDevices();
+               }
+
+               CecLogicalAddresses ^ GetActiveDevices(void)
+               {
+                       CecLogicalAddresses ^ retVal = gcnew CecLogicalAddresses();
+                       unsigned int iDevices = 0;
+
+                       cec_logical_addresses activeDevices = m_libCec->GetActiveDevices();
+
+                       for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+                               if (activeDevices[iPtr])
+                                       retVal->Addresses[iDevices++] = (CecLogicalAddress)iPtr;
+
+                       return retVal;
+               }
+
+               bool IsActiveDevice(CecLogicalAddress logicalAddress)
+               {
+                       return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress);
+               }
+
+               bool IsActiveDeviceType(CecDeviceType type)
+               {
+                       return m_libCec->IsActiveDeviceType((cec_device_type)type);
+               }
+
+               bool SetHDMIPort(CecLogicalAddress address, uint8_t port)
+               {
+                       return m_libCec->SetHDMIPort((cec_logical_address)address, port);
+               }
+
+               uint8_t VolumeUp(bool wait)
+               {
+                       return m_libCec->VolumeUp(wait);
+               }
+
+               uint8_t VolumeDown(bool wait)
+               {
+                       return m_libCec->VolumeDown(wait);
+               }
+
+               uint8_t MuteAudio(bool wait)
+               {
+                       return m_libCec->MuteAudio(wait);
+               }
+
+               bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait)
+               {
+                       return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait);
+               }
+
+               bool SendKeyRelease(CecLogicalAddress destination, bool wait)
+               {
+                       return m_libCec->SendKeyRelease((cec_logical_address)destination, wait);
+               }
+
+               String ^ GetDeviceOSDName(CecLogicalAddress logicalAddress)
+               {
+                       cec_osd_name osd = m_libCec->GetDeviceOSDName((cec_logical_address) logicalAddress);
+                       return gcnew String(osd.name);
+               }
+
+               CecLogicalAddress GetActiveSource()
+               {
+                       return (CecLogicalAddress)m_libCec->GetActiveSource();
+               }
+
+               bool IsActiveSource(CecLogicalAddress logicalAddress)
+               {
+                       return m_libCec->IsActiveSource((cec_logical_address)logicalAddress);
+               }
+
+               uint16_t GetDevicePhysicalAddress(CecLogicalAddress iAddress)
+               {
+                       return m_libCec->GetDevicePhysicalAddress((cec_logical_address)iAddress);
+               }
+
+               bool SetStreamPath(CecLogicalAddress iAddress)
+               {
+                       return m_libCec->SetStreamPath((cec_logical_address)iAddress);
+               }
+
+               bool SetStreamPath(uint16_t iPhysicalAddress)
+               {
+                       return m_libCec->SetStreamPath(iPhysicalAddress);
+               }
+
+               CecLogicalAddresses ^GetLogicalAddresses(void)
+               {
+                       CecLogicalAddresses ^addr = gcnew CecLogicalAddresses();
+                       cec_logical_addresses libAddr = m_libCec->GetLogicalAddresses();
+                       for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+                               addr->Addresses[iPtr] = (CecLogicalAddress)libAddr.addresses[iPtr];
+                       addr->Primary = (CecLogicalAddress)libAddr.primary;
+                       return addr;
+               }
+
+               bool GetCurrentConfiguration(LibCECConfiguration ^configuration)
+               {
+                       libcec_configuration config;
+                       config.Clear();
+
+                       if (m_libCec->GetCurrentConfiguration(&config))
+                       {
+                               configuration->Update(config);
+                               return true;
+                       }
+                       return false;
+               }
+
+    bool CanPersistConfiguration(void)
+               {
+                       return m_libCec->CanPersistConfiguration();
+               }
+
+    bool PersistConfiguration(LibCECConfiguration ^configuration)
+               {
+                       marshal_context ^ context = gcnew marshal_context();
+                       libcec_configuration config;
+                       ConvertConfiguration(context, configuration, config);
+
+                       bool bReturn = m_libCec->PersistConfiguration(&config);
+
+                       delete context;
+                       return bReturn;
+               }
+
+               bool SetConfiguration(LibCECConfiguration ^configuration)
+               {
+                       marshal_context ^ context = gcnew marshal_context();
+                       libcec_configuration config;
+                       ConvertConfiguration(context, configuration, config);
+
+                       bool bReturn = m_libCec->SetConfiguration(&config);
+
+                       delete context;
+                       return bReturn;
+               }
+
+    bool IsLibCECActiveSource()
     {
-      Data[Size] = data;
-      Size++;
+      return m_libCec->IsLibCECActiveSource();
     }
-  }
-
-  property array<uint8_t> ^ Data;
-  property uint8_t          Size;
-};
 
-public ref class CecCommand
-{
-public:
-  CecCommand(CecLogicalAddress iInitiator, CecLogicalAddress iDestination, bool bAck, bool bEom, int8_t iOpcode, int32_t iTransmitTimeout)
-  {
-    Initiator       = iInitiator;
-    Destination     = iDestination;
-    Ack             = bAck;
-    Eom             = bEom;
-    Opcode          = iOpcode;
-    OpcodeSet       = true;
-    TransmitTimeout = iTransmitTimeout;
-    Parameters      = gcnew CecDatapacket;
-    Empty           = false;
-  }
-
-  CecCommand(void)
-  {
-    Initiator       = CecLogicalAddress::Unknown;
-    Destination     = CecLogicalAddress::Unknown;
-    Ack             = false;
-    Eom             = false;
-    Opcode          = 0;
-    OpcodeSet       = false;
-    TransmitTimeout = 0;
-    Parameters      = gcnew CecDatapacket;
-    Empty           = true;
-  }
-
-  void PushBack(uint8_t data)
-  {
-    if (Initiator == CecLogicalAddress::Unknown && Destination == CecLogicalAddress::Unknown)
-    {
-      Initiator   = (CecLogicalAddress) (data >> 4);
-      Destination = (CecLogicalAddress) (data & 0xF);
-    }
-    else if (!OpcodeSet)
-    {
-      OpcodeSet = true;
-      Opcode    = data;
-    }
-    else
+    bool GetDeviceInformation(String ^ port, LibCECConfiguration ^configuration, uint32_t timeoutMs)
     {
-      Parameters->PushBack(data);
-    }
-  }
-
-  property bool               Empty;
-  property CecLogicalAddress  Initiator;
-  property CecLogicalAddress  Destination;
-  property bool               Ack;
-  property bool               Eom;
-  property int8_t             Opcode;
-  property CecDatapacket ^    Parameters;
-  property bool               OpcodeSet;
-  property int32_t            TransmitTimeout;
-};
-
-public ref class CecKeypress
-{
-public:
-  CecKeypress(int iKeycode, unsigned int iDuration)
-  {
-    Keycode  = iKeycode;
-    Duration = iDuration;
-    Empty    = false;
-  }
-
-  CecKeypress(void)
-  {
-    Keycode  = 0;
-    Duration = 0;
-    Empty    = true;
-  }
-
-  property bool         Empty;
-  property int          Keycode;
-  property unsigned int Duration;
-};
-
-public ref class CecLogMessage
-{
-public:
-  CecLogMessage(String ^ strMessage, CecLogLevel iLevel, int64_t iTime)
-  {
-    Message = strMessage;
-    Level   = iLevel;
-    Time    = iTime;
-    Empty   = false;
-  }
-
-  CecLogMessage(void)
-  {
-    Message = "";
-    Level   = CecLogLevel::None;
-    Time    = 0;
-    Empty   = true;
-  }
-
-  property bool        Empty;
-  property String ^    Message;
-  property CecLogLevel Level;
-  property int64_t     Time;
-};
-
-public ref class LibCecSharp
-{
-public:
-   LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes)
-   {
-     marshal_context ^ context = gcnew marshal_context();
-
-     const char* strDeviceNameC = context->marshal_as<const char*>(strDeviceName);
-
-     cec_device_type_list types;
-     for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
-       types.types[iPtr] = (cec_device_type)deviceTypes->Types[iPtr];
-     m_libCec = (ICECAdapter *) CECInit(strDeviceNameC, types);
-     delete context;
-   }
-   
-   ~LibCecSharp(void)
-   {
-     CECDestroy(m_libCec);
-     m_libCec = NULL;
-   }
-
-protected:
-   !LibCecSharp(void)
-   {
-     CECDestroy(m_libCec);
-     m_libCec = NULL;
-   }
-
-public:
-  array<CecAdapter ^> ^ FindAdapters(String ^ path)
-  {
-    cec_adapter *devices = new cec_adapter[10];
-
-    marshal_context ^ context = gcnew marshal_context();
-    const char* strPathC = path->Length > 0 ? context->marshal_as<const char*>(path) : NULL;
-
-    uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL);
-
-    array<CecAdapter ^> ^ adapters = gcnew array<CecAdapter ^>(iDevicesFound);
-    for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++)
-      adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm));
-
-    delete devices;
-    delete context;
-    return adapters;
-  }
-
-  bool Open(String ^ strPort, int iTimeoutMs)
-  {
-    marshal_context ^ context = gcnew marshal_context();
-    const char* strPortC = context->marshal_as<const char*>(strPort);
-    bool bReturn = m_libCec->Open(strPortC, iTimeoutMs);
-    delete context;
-    return bReturn;
-  }
-
-  void Close(void)
-  {
-    m_libCec->Close();
-  }
-
-  bool PingAdapter(void)
-  {
-    return m_libCec->PingAdapter();
-  }
-
-  bool StartBootloader(void)
-  {
-    return m_libCec->StartBootloader();
-  }
-
-  int GetMinLibVersion(void)
-  {
-    return m_libCec->GetMinLibVersion();
-  }
-
-  int GetLibVersionMajor(void)
-  {
-    return m_libCec->GetLibVersionMajor();
-  }
-
-  int GetLibVersionMinor(void)
-  {
-    return m_libCec->GetLibVersionMinor();
-  }
-
-  CecLogMessage ^ GetNextLogMessage(void)
-  {
-    cec_log_message msg;
-    if (m_libCec->GetNextLogMessage(&msg))
-    {
-      return gcnew CecLogMessage(gcnew String(msg.message), (CecLogLevel)msg.level, msg.time);
-    }
+      bool bReturn(false);
+      marshal_context ^ context = gcnew marshal_context();
 
-    return gcnew CecLogMessage();
-  }
-
-  CecKeypress ^ GetNextKeypress(void)
-  {
-    cec_keypress key;
-    if (m_libCec->GetNextKeypress(&key))
-    {
-      return gcnew CecKeypress(key.keycode, key.duration);
-    }
+      libcec_configuration config;
+                       config.Clear();
 
-    return gcnew CecKeypress();
-  }
+      const char* strPortC = port->Length > 0 ? context->marshal_as<const char*>(port) : NULL;
 
-  CecCommand ^ GetNextCommand(void)
-  {
-    cec_command command;
-    if (m_libCec->GetNextCommand(&command))
-    {
-      CecCommand ^ retVal = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, command.opcode, command.transmit_timeout);
-      for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
-        retVal->Parameters->PushBack(command.parameters[iPtr]);
-      return retVal;
-    }
+      if (m_libCec->GetDeviceInformation(strPortC, &config, timeoutMs))
+                       {
+                               configuration->Update(config);
+        bReturn = true;
+                       }
 
-    return gcnew CecCommand();
-  }
-
-  bool Transmit(CecCommand ^ command)
-  {
-    cec_command ccommand;
-    cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode);
-    ccommand.transmit_timeout = command->TransmitTimeout;
-    ccommand.eom              = command->Eom;
-    ccommand.ack              = command->Ack;
-    for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++)
-      ccommand.parameters.PushBack(command->Parameters->Data[iPtr]);
-
-    return m_libCec->Transmit(ccommand);
-  }
-
-  bool SetLogicalAddress(CecLogicalAddress logicalAddress)
-  {
-    return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress);
-  }
-
-  bool SetPhysicalAddress(int16_t physicalAddress)
-  {
-    return m_libCec->SetPhysicalAddress(physicalAddress);
-  }
-
-  bool PowerOnDevices(CecLogicalAddress logicalAddress)
-  {
-    return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress);
-  }
-
-  bool StandbyDevices(CecLogicalAddress logicalAddress)
-  {
-    return m_libCec->StandbyDevices((cec_logical_address) logicalAddress);
-  }
-
-  bool PollDevice(CecLogicalAddress logicalAddress)
-  {
-    return m_libCec->PollDevice((cec_logical_address) logicalAddress);
-  }
-
-  bool SetActiveSource(CecDeviceType type)
-  {
-    return m_libCec->SetActiveSource((cec_device_type) type);
-  }
-
-  bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate)
-  {
-    return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate);
-  }
-
-  bool SetDeckInfo(CecDeckInfo info, bool sendUpdate)
-  {
-    return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate);
-  }
-
-  bool SetInactiveView(void)
-  {
-    return m_libCec->SetInactiveView();
-  }
-
-  bool SetMenuState(CecMenuState state, bool sendUpdate)
-  {
-    return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate);
-  }
-
-  bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message)
-  {
-    marshal_context ^ context = gcnew marshal_context();
-    const char* strMessageC = context->marshal_as<const char*>(message);
-
-    bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC);
-
-    delete context;
-    return bReturn;
-  }
-
-  bool SwitchMonitoring(bool enable)
-  {
-    return m_libCec->SwitchMonitoring(enable);
-  }
-
-  CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress)
-  {
-    return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress);
-  }
-
-  String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress)
-  {
-    cec_menu_language lang;
-    if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang))
-    {
-      return gcnew String(lang.language);
+      delete context;
+      return bReturn;
     }
 
-    return gcnew String("");
-  }
-
-  uint64_t GetDeviceVendorId(CecLogicalAddress logicalAddress)
-  {
-    return m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress);
-  }
-
-  CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress)
-  {
-    return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress);
-  }
-
-  CecLogicalAddresses ^ GetActiveDevices(void)
-  {
-    CecLogicalAddresses ^ retVal = gcnew CecLogicalAddresses();
-    unsigned int iDevices = 0;
-
-    cec_logical_addresses activeDevices = m_libCec->GetActiveDevices();
-
-    for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
-      if (activeDevices[iPtr])
-        retVal->Addresses[iDevices++] = (CecLogicalAddress)iPtr;
-
-    return retVal;
-  }
-
-  bool IsActiveDevice(CecLogicalAddress logicalAddress)
-  {
-    return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress);
-  }
-
-  bool IsActiveDeviceType(CecDeviceType type)
-  {
-    return m_libCec->IsActiveDeviceType((cec_device_type)type);
-  }
-
-  bool SetHDMIPort(uint8_t port)
-  {
-    return m_libCec->SetHDMIPort(port);
-  }
-
-  uint8_t VolumeUp(bool wait)
-  {
-    return m_libCec->VolumeUp(wait);
-  }
-
-  uint8_t VolumeDown(bool wait)
-  {
-    return m_libCec->VolumeDown(wait);
-  }
-
-  uint8_t MuteAudio(bool wait)
-  {
-    return m_libCec->MuteAudio(wait);
-  }
-
-  bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait)
-  {
-    return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait);
-  }
-
-  bool SendKeyRelease(CecLogicalAddress destination, bool wait)
-  {
-    return m_libCec->SendKeyRelease((cec_logical_address)destination, wait);
-  }
-
-  String ^ GetOSDName(CecLogicalAddress logicalAddress)
-  {
-    cec_osd_name osd = m_libCec->GetOSDName((cec_logical_address) logicalAddress);
-    return gcnew String(osd.name);
-  }
-
-private:
-   ICECAdapter *m_libCec;
-};
+               String ^ ToString(CecLogicalAddress iAddress)
+               {
+                       const char *retVal = m_libCec->ToString((cec_logical_address)iAddress);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecVendorId iVendorId)
+               {
+                       const char *retVal = m_libCec->ToString((cec_vendor_id)iVendorId);
+                       return gcnew String(retVal);
+               }
+         
+               String ^ ToString(CecVersion iVersion)
+               {
+                       const char *retVal = m_libCec->ToString((cec_version)iVersion);
+                       return gcnew String(retVal);
+               }
+         
+               String ^ ToString(CecPowerStatus iState)
+               {
+                       const char *retVal = m_libCec->ToString((cec_power_status)iState);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecMenuState iState)
+               {
+                       const char *retVal = m_libCec->ToString((cec_menu_state)iState);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecDeckControlMode iMode)
+               {
+                       const char *retVal = m_libCec->ToString((cec_deck_control_mode)iMode);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecDeckInfo status)
+               {
+                       const char *retVal = m_libCec->ToString((cec_deck_info)status);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecOpcode opcode)
+               {
+                       const char *retVal = m_libCec->ToString((cec_opcode)opcode);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecSystemAudioStatus mode)
+               {
+                       const char *retVal = m_libCec->ToString((cec_system_audio_status)mode);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecAudioStatus status)
+               {
+                       const char *retVal = m_libCec->ToString((cec_audio_status)status);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecClientVersion version)
+               {
+                       const char *retVal = m_libCec->ToString((cec_client_version)version);
+                       return gcnew String(retVal);
+               }
+
+               String ^ ToString(CecServerVersion version)
+               {
+                       const char *retVal = m_libCec->ToString((cec_server_version)version);
+                       return gcnew String(retVal);
+               }
+
+       private:
+               ICECAdapter *        m_libCec;
+    CecCallbackMethods ^ m_callbacks;
+       };
+}