From: Lars Op den Kamp Date: Sun, 13 Nov 2011 19:47:14 +0000 (+0100) Subject: cec: added a C++ CLR wrapper for libCEC, so libCEC can be used by any .NET language... X-Git-Tag: upstream/2.2.0~1^2~44^2~137 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=61f3c2ad37b222442f9f9d81cd9f7694ec2089f5;p=deb_libcec.git cec: added a C++ CLR wrapper for libCEC, so libCEC can be used by any .NET language and ported the basics of cec-client over to C#. --- diff --git a/.gitignore b/.gitignore index e196aa9..2ad44d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .project .cproject +*.manifest aclocal.m4 autom4te.cache @@ -25,18 +26,28 @@ libcec.pdb cec-client.exe cec-client.ilk cec-client.pdb +CecSharpClient.exe +CecSharpClient.pdb +CecSharpClient.vshost.exe +CecSharpClient.vshost.exe.manifest + +LibCecSharp.dll +LibCecSharp.ilk +LibCecSharp.pdb build include/boost -project/boost-1_46_1-xbmc-win32 +project/bin project/Debug/ +project/Release/ project/ipch/ project/libcec.sdf project/libcec.suo -project/libcec.vcxproj.user -project/testclient.vcxproj.user +project/obj +project/Properties +project/*.user src/lib/.deps src/lib/.libs @@ -59,6 +70,7 @@ src/testclient/.libs src/testclient/cec-client src/testclient/*.o +src/CecSharpTester/obj /dpinst-x86.exe /dpinst-amd64.exe diff --git a/README b/README index 6c23712..5ef90e3 100644 --- a/README +++ b/README @@ -22,6 +22,12 @@ Test the device: For developers: * see /include/cec.h for the C++ API and /include/cecc.h for the C version. +* see src/testclient/main.cpp for an example + +For .NET developers: +* build project/libcec.sln first +* add a reference to LibCecSharp.dll +* see src\CecSharpTester\CecSharpClient.cs for an example If you wish to contribute to this project, you must first sign our contributors agreement Please see http://www.pulse-eight.net/contributors for more information \ No newline at end of file diff --git a/project/CecSharpClient.sln b/project/CecSharpClient.sln new file mode 100644 index 0000000..0a4d822 --- /dev/null +++ b/project/CecSharpClient.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CecSharpClient", "..\src\CecSharpTester\CecSharpClient.csproj", "{47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}.Debug|x86.ActiveCfg = Debug|x86 + {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}.Debug|x86.Build.0 = Debug|x86 + {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}.Release|x86.ActiveCfg = Release|x86 + {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/project/LibCecSharp.vcxproj b/project/LibCecSharp.vcxproj new file mode 100644 index 0000000..2ced898 --- /dev/null +++ b/project/LibCecSharp.vcxproj @@ -0,0 +1,101 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7} + v4.0 + ManagedCProj + LibCecSharp + + + + DynamicLibrary + true + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)\..\include;$(IncludePath) + $(ProjectName) + $(SolutionDir)..\ + + + false + $(SolutionDir)\..\include;$(IncludePath) + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + NotUsing + + + true + + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + NotUsing + + + true + + + + + + + + + + + + + + + + + + + + + + + {c04b0fb1-667d-4f1c-bdae-a07cdffaaaa0} + + + + + + \ No newline at end of file diff --git a/project/LibCecSharp.vcxproj.filters b/project/LibCecSharp.vcxproj.filters new file mode 100644 index 0000000..cdfa851 --- /dev/null +++ b/project/LibCecSharp.vcxproj.filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/project/libCEC.nsi b/project/libCEC.nsi index eaf1093..ee6df6e 100644 --- a/project/libCEC.nsi +++ b/project/libCEC.nsi @@ -52,6 +52,7 @@ Section "libCEC" SecLibCEC File "..\COPYING" File "..\libcec.dll" File "..\libcec.lib" + File "..\LibCecSharp.dll" File "..\pthreadVC2.dll" File "..\README" @@ -130,6 +131,7 @@ Section "Uninstall" Delete "$INSTDIR\libcec.dll" Delete "$INSTDIR\libcec.lib" Delete "$INSTDIR\libcec.pdb" + Delete "$INSTDIR\LibCecSharp.dll" Delete "$INSTDIR\pthreadVC2.dll" Delete "$INSTDIR\README" Delete "$INSTDIR\driver\OEM001.inf" diff --git a/project/libcec.sln b/project/libcec.sln index 2255a1b..facfece 100644 --- a/project/libcec.sln +++ b/project/libcec.sln @@ -8,20 +8,59 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testclient", "testclient.vc {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0} = {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibCecSharp", "LibCecSharp.vcxproj", "{1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}" + ProjectSection(ProjectDependencies) = postProject + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0} = {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms Debug|Win32 = Debug|Win32 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms Release|Win32 = Release|Win32 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Win32.ActiveCfg = Debug|Win32 {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|Win32.Build.0 = Debug|Win32 + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|x86.ActiveCfg = Debug|Win32 + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Any CPU.ActiveCfg = Release|Win32 + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Mixed Platforms.Build.0 = Release|Win32 {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Win32.ActiveCfg = Release|Win32 {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|Win32.Build.0 = Release|Win32 + {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|x86.ActiveCfg = Release|Win32 + {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Mixed Platforms.Build.0 = Debug|Win32 {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Win32.ActiveCfg = Debug|Win32 {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|Win32.Build.0 = Debug|Win32 + {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|x86.ActiveCfg = Debug|Win32 + {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Any CPU.ActiveCfg = Release|Win32 + {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Mixed Platforms.Build.0 = Release|Win32 {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Win32.ActiveCfg = Release|Win32 {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|Win32.Build.0 = Release|Win32 + {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|x86.ActiveCfg = Release|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|Win32.Build.0 = Debug|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Debug|x86.ActiveCfg = Debug|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Any CPU.ActiveCfg = Release|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Mixed Platforms.Build.0 = Release|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Win32.ActiveCfg = Release|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|Win32.Build.0 = Release|Win32 + {1AC27FBD-653A-4F5F-ADBC-2A8FD074EEB7}.Release|x86.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/CecSharpTester/AssemblyInfo.cs b/src/CecSharpTester/AssemblyInfo.cs new file mode 100644 index 0000000..058bbb9 --- /dev/null +++ b/src/CecSharpTester/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CecSharpClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Pulse-Eight Ltd.")] +[assembly: AssemblyProduct("CecSharpClient")] +[assembly: AssemblyCopyright("Copyright © Pulse-Eight Ltd. 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fb8d5961-9ba9-4e56-8706-ac150183706f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/CecSharpTester/CecSharpClient.cs b/src/CecSharpTester/CecSharpClient.cs new file mode 100644 index 0000000..0cd6aeb --- /dev/null +++ b/src/CecSharpTester/CecSharpClient.cs @@ -0,0 +1,381 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CecSharpClient +{ + class CecSharpClient + { + public CecSharpClient() + { + CecDeviceTypeList types = new CecDeviceTypeList(); + types.Types[0] = CecDeviceType.PlaybackDevice; + + Lib = new LibCecSharp("CEC Tester", types); + LogLevel = (int) CecLogLevel.All; + + Console.WriteLine("CEC Parser created - libcec version " + Lib.GetLibVersionMajor() + "." + Lib.GetLibVersionMinor()); + } + + void FlushLog() + { + CecLogMessage message = Lib.GetNextLogMessage(); + bool bGotMessage = !message.Empty; + while (bGotMessage) + { + if (((int)message.Level & LogLevel) == (int)message.Level) + { + string strLevel = ""; + switch (message.Level) + { + case CecLogLevel.Error: + strLevel = "ERROR: "; + break; + case CecLogLevel.Warning: + strLevel = "WARNING: "; + break; + case CecLogLevel.Notice: + strLevel = "NOTICE: "; + break; + case CecLogLevel.Traffic: + strLevel = "TRAFFIC: "; + break; + case CecLogLevel.Debug: + strLevel = "DEBUG: "; + break; + default: + break; + } + string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message); + Console.WriteLine(strLog); + } + + message = Lib.GetNextLogMessage(); + bGotMessage = !message.Empty; + } + } + + public bool Connect(int timeout) + { + CecAdapter[] adapters = Lib.FindAdapters(string.Empty); + if (adapters.Length > 0) + return Connect(adapters[0].ComPort, timeout); + else + { + Console.WriteLine("Did not find any CEC adapters"); + return false; + } + } + + public bool Connect(string port, int timeout) + { + return Lib.Open(port, timeout); + } + + public void Close() + { + Lib.Close(); + } + + public void ListDevices() + { + int iAdapter = 0; + foreach (CecAdapter adapter in Lib.FindAdapters(string.Empty)) + { + Console.WriteLine("Adapter: " + iAdapter++); + Console.WriteLine("Path: " + adapter.Path); + Console.WriteLine("Com port: " + adapter.ComPort); + } + } + + void ShowConsoleHelp() + { + Console.WriteLine( + "================================================================================" + System.Environment.NewLine + + "Available commands:" + System.Environment.NewLine + + System.Environment.NewLine + + "tx {bytes} transfer bytes over the CEC line." + System.Environment.NewLine + + "txn {bytes} transfer bytes but don't wait for transmission ACK." + System.Environment.NewLine + + "[tx 40 00 FF 11 22 33] sends bytes 0x40 0x00 0xFF 0x11 0x22 0x33" + System.Environment.NewLine + + System.Environment.NewLine + + "on {address} power on the device with the given logical address." + System.Environment.NewLine + + "[on 5] power on a connected audio system" + System.Environment.NewLine + + System.Environment.NewLine + + "standby {address} put the device with the given address in standby mode." + System.Environment.NewLine + + "[standby 0] powers off the TV" + System.Environment.NewLine + + System.Environment.NewLine + + "la {logical_address} change the logical address of the CEC adapter." + System.Environment.NewLine + + "[la 4] logical address 4" + System.Environment.NewLine + + System.Environment.NewLine + + "pa {physical_address} change the physical address of the CEC adapter." + System.Environment.NewLine + + "[pa 1000] physical address 1.0.0.0" + System.Environment.NewLine + + System.Environment.NewLine + + "osd {addr} {string} set OSD message on the specified device." + System.Environment.NewLine + + "[osd 0 Test Message] displays 'Test Message' on the TV" + System.Environment.NewLine + + System.Environment.NewLine + + "ver {addr} get the CEC version of the specified device." + System.Environment.NewLine + + "[ver 0] get the CEC version of the TV" + System.Environment.NewLine + + System.Environment.NewLine + + "ven {addr} get the vendor ID of the specified device." + System.Environment.NewLine + + "[ven 0] get the vendor ID of the TV" + System.Environment.NewLine + + System.Environment.NewLine + + "lang {addr} get the menu language of the specified device." + System.Environment.NewLine + + "[lang 0] get the menu language of the TV" + System.Environment.NewLine + + System.Environment.NewLine + + "pow {addr} get the power status of the specified device." + System.Environment.NewLine + + "[pow 0] get the power status of the TV" + System.Environment.NewLine + + System.Environment.NewLine + + "poll {addr} poll the specified device." + System.Environment.NewLine + + "[poll 0] sends a poll message to the TV" + System.Environment.NewLine + + System.Environment.NewLine + + "[mon] {1|0} enable or disable CEC bus monitoring." + System.Environment.NewLine + + "[log] {1 - 31} change the log level. see cectypes.h for values." + System.Environment.NewLine + + System.Environment.NewLine + + "[ping] send a ping command to the CEC adapter." + System.Environment.NewLine + + "[bl] to let the adapter enter the bootloader, to upgrade" + System.Environment.NewLine + + " the flash rom." + System.Environment.NewLine + + "[r] reconnect to the CEC adapter." + System.Environment.NewLine + + "[h] or [help] show this help." + System.Environment.NewLine + + "[q] or [quit] to quit the CEC test client and switch off all" + System.Environment.NewLine + + " connected CEC devices." + System.Environment.NewLine + + "================================================================================"); + } + + public void MainLoop() + { + Lib.PowerOnDevices(CecLogicalAddress.Tv); + FlushLog(); + + Lib.SetActiveSource(CecDeviceType.PlaybackDevice); + FlushLog(); + + bool bContinue = true; + string command; + while (bContinue) + { + Console.WriteLine("waiting for input"); + + command = Console.ReadLine(); + if (command.Length == 0) + continue; + string[] splitCommand = command.Split(' '); + if (splitCommand[0] == "tx" || splitCommand[0] == "txn") + { + CecCommand bytes = new CecCommand(); + for (int iPtr = 1; iPtr < splitCommand.Length; iPtr++) + { + bytes.PushBack(byte.Parse(splitCommand[iPtr], System.Globalization.NumberStyles.HexNumber)); + } + + if (command == "txn") + bytes.TransmitTimeout = 0; + + Lib.Transmit(bytes); + } + else if (splitCommand[0] == "on") + { + if (splitCommand.Length > 1) + Lib.PowerOnDevices((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + else + Lib.PowerOnDevices(CecLogicalAddress.Broadcast); + } + else if (splitCommand[0] == "standby") + { + if (splitCommand.Length > 1) + Lib.StandbyDevices((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + else + Lib.StandbyDevices(CecLogicalAddress.Broadcast); + } + else if (splitCommand[0] == "poll") + { + bool bSent = false; + if (splitCommand.Length > 1) + bSent = Lib.PollDevice((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + else + bSent = Lib.PollDevice(CecLogicalAddress.Broadcast); + if (bSent) + Console.WriteLine("POLL message sent"); + else + Console.WriteLine("POLL message not sent"); + } + else if (splitCommand[0] == "la") + { + if (splitCommand.Length > 1) + Lib.SetLogicalAddress((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + } + else if (splitCommand[0] == "pa") + { + if (splitCommand.Length > 1) + Lib.SetPhysicalAddress(short.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + } + else if (splitCommand[0] == "osd") + { + if (splitCommand.Length > 2) + { + StringBuilder osdString = new StringBuilder(); + for (int iPtr = 1; iPtr < splitCommand.Length; iPtr++) + { + osdString.Append(splitCommand[iPtr]); + if (iPtr != splitCommand.Length - 1) + osdString.Append(" "); + } + Lib.SetOSDString((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber), CecDisplayControl.DisplayForDefaultTime, osdString.ToString()); + } + } + else if (splitCommand[0] == "ping") + { + Lib.PingAdapter(); + } + else if (splitCommand[0] == "mon") + { + bool enable = splitCommand.Length > 1 ? splitCommand[1] == "1" : false; + Lib.SwitchMonitoring(enable); + } + else if (splitCommand[0] == "bl") + { + Lib.StartBootloader(); + } + else if (splitCommand[0] == "lang") + { + if (splitCommand.Length > 1) + { + string language = Lib.GetDeviceMenuLanguage((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + Console.WriteLine("Menu language: " + language); + } + } + else if (splitCommand[0] == "ven") + { + if (splitCommand.Length > 1) + { + ulong vendor = Lib.GetDeviceVendorId((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + Console.WriteLine("Vendor ID: " + vendor); + } + } + else if (splitCommand[0] == "ver") + { + if (splitCommand.Length > 1) + { + CecVersion version = Lib.GetDeviceCecVersion((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + switch (version) + { + case CecVersion.V1_2: + Console.WriteLine("CEC version 1.2"); + break; + case CecVersion.V1_2A: + Console.WriteLine("CEC version 1.2a"); + break; + case CecVersion.V1_3: + Console.WriteLine("CEC version 1.3"); + break; + case CecVersion.V1_3A: + Console.WriteLine("CEC version 1.3a"); + break; + case CecVersion.V1_4: + Console.WriteLine("CEC version 1.4"); + break; + default: + Console.WriteLine("unknown CEC version"); + break; + } + } + } + else if (splitCommand[0] == "pow") + { + if (splitCommand.Length > 1) + { + CecPowerStatus power = Lib.GetDevicePowerStatus((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber)); + switch (power) + { + case CecPowerStatus.On: + Console.WriteLine("powered on"); + break; + case CecPowerStatus.InTransitionOnToStandby: + Console.WriteLine("on -> standby"); + break; + case CecPowerStatus.InTransitionStandbyToOn: + Console.WriteLine("standby -> on"); + break; + case CecPowerStatus.Standby: + Console.WriteLine("standby"); + break; + default: + Console.WriteLine("unknown power status"); + break; + } + } + } + else if (splitCommand[0] == "r") + { + Console.WriteLine("closing the connection"); + Lib.Close(); + FlushLog(); + + Console.WriteLine("opening a new connection"); + Connect(10000); + FlushLog(); + + Console.WriteLine("setting active source"); + Lib.SetActiveSource(CecDeviceType.PlaybackDevice); + } + else if (splitCommand[0] == "h" || splitCommand[0] == "help") + ShowConsoleHelp(); + else if (splitCommand[0] == "q" || splitCommand[0] == "quit") + bContinue = false; + else if (splitCommand[0] == "log" && splitCommand.Length > 1) + LogLevel = int.Parse(splitCommand[1]); + + FlushLog(); + } + } + + static void Main(string[] args) + { + CecSharpClient p = new CecSharpClient(); + if (p.Connect(10000)) + { + p.MainLoop(); + } + else + { + Console.WriteLine("Could not open a connection to the CEC adapter"); + } + p.FlushLog(); + } + + private int LogLevel; + private LibCecSharp Lib; + } +} diff --git a/src/CecSharpTester/CecSharpClient.csproj b/src/CecSharpTester/CecSharpClient.csproj new file mode 100644 index 0000000..eff98ef --- /dev/null +++ b/src/CecSharpTester/CecSharpClient.csproj @@ -0,0 +1,61 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {47EF8EFE-5758-4E82-B9BA-F9B002F9C0D4} + Exe + Properties + CecSharpClient + CecSharpClient + v4.0 + Client + 512 + + + x86 + true + full + false + ..\..\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\..\LibCecSharp.dll + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/LibCecSharp/AssemblyInfo.cpp b/src/LibCecSharp/AssemblyInfo.cpp new file mode 100644 index 0000000..459ae9f --- /dev/null +++ b/src/LibCecSharp/AssemblyInfo.cpp @@ -0,0 +1,40 @@ +#include "stdafx.h" + +using namespace System; +using namespace System::Reflection; +using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly:AssemblyTitleAttribute("LibCecSharp")]; +[assembly:AssemblyDescriptionAttribute("")]; +[assembly:AssemblyConfigurationAttribute("")]; +[assembly:AssemblyCompanyAttribute("Pulse-Eight Ltd.")]; +[assembly:AssemblyProductAttribute("LibCecSharp")]; +[assembly:AssemblyCopyrightAttribute("Copyright (c) Pulse-Eight Ltd. 2011")]; +[assembly:AssemblyTrademarkAttribute("")]; +[assembly:AssemblyCultureAttribute("")]; + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the value or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly:AssemblyVersionAttribute("1.0.*")]; + +[assembly:ComVisible(false)]; + +[assembly:CLSCompliantAttribute(true)]; + +[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; diff --git a/src/LibCecSharp/LibCecSharp.cpp b/src/LibCecSharp/LibCecSharp.cpp new file mode 100644 index 0000000..c72e0dd --- /dev/null +++ b/src/LibCecSharp/LibCecSharp.cpp @@ -0,0 +1,528 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 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 + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "stdafx.h" +#include +#include +#include +#include +#using + +using namespace System; +using namespace CEC; +using namespace msclr::interop; + +public enum class CecDeviceType +{ + 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 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(5); + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + Types[iPtr] = CecDeviceType::Reserved; + } + + property array ^ Types; +}; + +public ref class CecDatapacket +{ +public: + CecDatapacket(void) + { + Data = gcnew array(100); + Size = 0; + } + + void PushBack(uint8_t data) + { + if (Size < 100) + { + Data[Size] = data; + Size++; + } + } + + property array ^ 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 + { + 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(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 ^ 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(path) : NULL; + + uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL); + + array ^ adapters = gcnew array(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(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); + } + + return gcnew CecLogMessage(); + } + + CecKeypress ^ GetNextKeypress(void) + { + cec_keypress key; + if (m_libCec->GetNextKeypress(&key)) + { + return gcnew CecKeypress(key.keycode, key.duration); + } + + return gcnew CecKeypress(); + } + + CecCommand ^ GetNextCommand(void) + { + cec_command command; + if (m_libCec->GetNextCommand(&command)) + { + // TODO parameters + return gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, command.opcode, command.transmit_timeout); + } + + 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.push_back(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(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(""); + } + + 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); + } + +private: + ICECAdapter * m_libCec; +}; diff --git a/src/LibCecSharp/LibCecSharp.suo b/src/LibCecSharp/LibCecSharp.suo new file mode 100644 index 0000000..0b75e65 Binary files /dev/null and b/src/LibCecSharp/LibCecSharp.suo differ diff --git a/src/LibCecSharp/Stdafx.cpp b/src/LibCecSharp/Stdafx.cpp new file mode 100644 index 0000000..70d5258 --- /dev/null +++ b/src/LibCecSharp/Stdafx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : source file that includes just the standard includes +// LibCecSharp.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/src/LibCecSharp/Stdafx.h b/src/LibCecSharp/Stdafx.h new file mode 100644 index 0000000..3cc4c24 --- /dev/null +++ b/src/LibCecSharp/Stdafx.h @@ -0,0 +1,7 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#pragma once + + diff --git a/src/LibCecSharp/resource.h b/src/LibCecSharp/resource.h new file mode 100644 index 0000000..d5ac7c4 --- /dev/null +++ b/src/LibCecSharp/resource.h @@ -0,0 +1,3 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by app.rc