Server/CecClient.cs
author Stephane Lenclud
Sat, 16 Jul 2016 00:24:08 +0200
changeset 202 8784c59c784e
parent 201 6213f42f1983
child 203 ce63ebb51da4
permissions -rw-r--r--
Published v0.9.0.0
HDMI CEC improvements.
     1 /*
     2  * This file is part of the libCEC(R) library.
     3  *
     4  * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited.    All rights reserved.
     5  * libCEC(R) is an original work, containing original code.
     6  *
     7  * libCEC(R) is a trademark of Pulse-Eight Limited.
     8  *
     9  * This program is dual-licensed; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or
    12  * (at your option) any later version.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    22  *
    23  *
    24  * Alternatively, you can license this library under a commercial license,
    25  * please contact Pulse-Eight Licensing for more information.
    26  *
    27  * For more information contact:
    28  * Pulse-Eight Licensing             <license@pulse-eight.com>
    29  *         http://www.pulse-eight.com/
    30  *         http://www.pulse-eight.net/
    31  */
    32 
    33 using System;
    34 using System.Text;
    35 using CecSharp;
    36 using System.Threading;
    37 
    38 namespace Cec
    39 {
    40     class Client : CecCallbackMethods
    41     {
    42         /// <summary>
    43         /// 
    44         /// </summary>
    45         /// <param name="aDeviceName"></param>
    46         /// <param name="aHdmiPort"></param>
    47         public Client(string aDeviceName, byte aHdmiPort, CecLogLevel aLogLevel = CecLogLevel.Warning)
    48         {
    49             Config = new LibCECConfiguration();
    50             Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice;
    51             Config.DeviceName = aDeviceName;
    52             Config.HDMIPort = aHdmiPort;
    53             //Config.ClientVersion = LibCECConfiguration.CurrentVersion;
    54             Config.SetCallbacks(this);
    55             LogLevel = (int)aLogLevel;
    56 
    57             iLib = new LibCecSharp(Config);
    58             iLib.InitVideoStandalone();
    59 
    60             //Console.WriteLine("CEC Parser created - libCEC version " + Lib.VersionToString(Config.ServerVersion));
    61             Console.WriteLine("CEC Parser created - libCEC version " + Config.ServerVersion);
    62         }
    63 
    64 
    65         /// <summary>
    66         /// 
    67         /// </summary>
    68         /// <param name="alert"></param>
    69         /// <param name="data"></param>
    70         /// <returns></returns>
    71         public override int ReceiveAlert(CecAlert alert, CecParameter data)
    72         {
    73             string log = "CEC alert: " + alert.ToString();
    74             if (data != null && data.Type == CecParameterType.ParameterTypeString)
    75             {
    76                 log += " " + data.Data;
    77             }
    78 
    79             Console.WriteLine(log);
    80 
    81             Close();
    82             //Try reconnect
    83             Connect(1000);
    84             return 1;
    85         }
    86 
    87         /// <summary>
    88         /// 
    89         /// </summary>
    90         /// <param name="newVal"></param>
    91         /// <returns></returns>
    92         public override int ReceiveMenuStateChange(CecMenuState newVal)
    93         {
    94             Console.WriteLine("CEC menu state changed to: " + iLib.ToString(newVal));
    95             return 1;
    96         }
    97 
    98         /// <summary>
    99         /// 
   100         /// </summary>
   101         /// <param name="logicalAddress"></param>
   102         /// <param name="activated"></param>
   103         public override void SourceActivated(CecLogicalAddress logicalAddress, bool activated)
   104         {
   105             Console.WriteLine("CEC source activated: " + iLib.ToString(logicalAddress) + "/" + activated.ToString() );
   106             return;
   107         }
   108 
   109         public override int ReceiveCommand(CecCommand command)
   110         {
   111             Console.WriteLine(string.Format("CEC command Src:{0} Dst:{1} Ack: {2} Eom: {3} OpcodeSet: {4} Opcode: {5} Timeout: {6}",
   112                 iLib.ToString(command.Initiator),
   113                 iLib.ToString(command.Destination),
   114                 command.Ack.ToString(),
   115                 command.Eom.ToString(),
   116                 command.OpcodeSet.ToString(),
   117                 iLib.ToString(command.Opcode),
   118                 command.TransmitTimeout.ToString()
   119                 ));
   120             return 1;
   121         }
   122 
   123         public override int ReceiveKeypress(CecKeypress key)
   124         {
   125             Console.WriteLine(string.Format("CEC keypress: {0} Duration:{1} Empty: {2}",
   126                 key.Keycode.ToString(), key.Duration.ToString(), key.Empty.ToString()));
   127             return 1;
   128         }
   129 
   130         public override int ReceiveLogMessage(CecLogMessage message)
   131         {
   132             if (((int)message.Level & LogLevel) == (int)message.Level)
   133             {
   134                 string strLevel = "";
   135                 switch (message.Level)
   136                 {
   137                     case CecLogLevel.Error:
   138                         strLevel = "ERROR: ";
   139                         break;
   140                     case CecLogLevel.Warning:
   141                         strLevel = "WARNING: ";
   142                         break;
   143                     case CecLogLevel.Notice:
   144                         strLevel = "NOTICE: ";
   145                         break;
   146                     case CecLogLevel.Traffic:
   147                         strLevel = "TRAFFIC: ";
   148                         break;
   149                     case CecLogLevel.Debug:
   150                         strLevel = "DEBUG: ";
   151                         break;
   152                     default:
   153                         break;
   154                 }
   155                 string strLog = string.Format("{0} {1} {2}", strLevel, message.Time, message.Message);
   156                 Console.WriteLine(strLog);
   157                 
   158             }
   159             return 1;
   160         }
   161 
   162         /// <summary>
   163         /// 
   164         /// </summary>
   165         /// <param name="timeout"></param>
   166         /// <returns></returns>
   167         public bool Connect(int timeout)
   168         {
   169             Close();         
   170             CecAdapter[] adapters = iLib.FindAdapters(string.Empty);
   171             if (adapters.Length > 0)
   172             {
   173                 Connect(adapters[0].ComPort, timeout);                
   174             }                
   175             else
   176             {
   177                 Console.WriteLine("CEC did not find any adapters");
   178             }
   179 
   180             return iConnected;
   181         }
   182 
   183         public bool Connect(string port, int timeout)
   184         {
   185             Close();
   186             iConnected = iLib.Open(port, timeout);
   187             if (iConnected)
   188             {
   189                 Scan();
   190                 //TestSendKey();
   191             }
   192             return iConnected;
   193         }
   194 
   195         public void Close()
   196         {            
   197             iLib.Close();
   198             iConnected = false;
   199         }
   200 
   201 
   202         public void TestSendKey()
   203         {
   204             //SetupMenu: opens option menu
   205             //RootMenu: opens Android home menu
   206             //ContentsMenu: nop
   207             //FavoriteMenu: nop
   208 
   209             //Philips TopMenu = 16
   210             //Philips PopupMenu = 17
   211 
   212             //bool res = iLib.SendKeypress(CecLogicalAddress.Tv, CecUserControlCode.DisplayInformation, true);
   213             //Thread.Sleep(3000); //Wait few seconds for menu to open
   214                                 //res = iLib.SendKeypress(CecLogicalAddress.Tv, CecUserControlCode.SetupMenu, true);
   215 
   216             for (int i = 0; i < 256; i++)
   217             {
   218                 //Thread.Sleep(100);
   219                 //res = iLib.SendKeyRelease(CecLogicalAddress.Tv, true);
   220                 //Thread.Sleep(100);
   221                 switch ((CecUserControlCode)i)
   222                 {
   223                     case CecUserControlCode.Power:
   224                     case CecUserControlCode.PowerOffFunction:
   225                     case CecUserControlCode.PowerOnFunction:
   226                     case CecUserControlCode.PowerToggleFunction:
   227                     case CecUserControlCode.ElectronicProgramGuide:
   228                     case CecUserControlCode.InputSelect:
   229                     case CecUserControlCode.RootMenu:
   230 
   231                         break;
   232 
   233                     default:
   234                         Console.WriteLine(i.ToString());
   235                         Thread.Sleep(1000);
   236                         iLib.SendKeypress(CecLogicalAddress.Tv, (CecUserControlCode)i, true);
   237                         
   238                         break;
   239 
   240                 }
   241                 
   242                 //
   243             }
   244 
   245 
   246             for (int i=0;i<7;i++)
   247             {
   248                 //Thread.Sleep(100);
   249                 //res = iLib.SendKeyRelease(CecLogicalAddress.Tv, true);
   250                 //Thread.Sleep(100);
   251                 //res = iLib.SendKeypress(CecLogicalAddress.Tv, CecUserControlCode.Down, true);
   252                 //
   253             }
   254 
   255             //res = iLib.SendKeypress(CecLogicalAddress.Tv, CecUserControlCode.Select, true);
   256 
   257             //res = iLib.SendKeypress(CecLogicalAddress.Tv, CecUserControlCode.Select, true);
   258             //res = iLib.SendKeyRelease(CecLogicalAddress.Tv, true);
   259         }
   260 
   261         /// <summary>
   262         /// 
   263         /// </summary>
   264         public void Scan()
   265         {
   266             Console.WriteLine("CEC bus information");
   267             Console.WriteLine("===================");
   268             CecLogicalAddresses addresses = Lib.GetActiveDevices();
   269             for (int iPtr = 0; iPtr < addresses.Addresses.Length; iPtr++)
   270             {
   271                 CecLogicalAddress address = (CecLogicalAddress) iPtr;
   272                 if (!addresses.IsSet(address))
   273                     continue;
   274 
   275                 CecVendorId iVendorId = Lib.GetDeviceVendorId(address);
   276                 bool bActive = Lib.IsActiveDevice(address);
   277                 ushort iPhysicalAddress = Lib.GetDevicePhysicalAddress(address);
   278                 string strAddr = Lib.PhysicalAddressToString(iPhysicalAddress);
   279                 CecVersion iCecVersion = Lib.GetDeviceCecVersion(address);
   280                 CecPowerStatus power = Lib.GetDevicePowerStatus(address);
   281                 string osdName = Lib.GetDeviceOSDName(address);
   282                 string lang = Lib.GetDeviceMenuLanguage(address);
   283 
   284                 Console.WriteLine("device #" + iPtr + ": " + Lib.ToString(address));
   285                 Console.WriteLine("address:       " + strAddr);
   286                 Console.WriteLine("active source: " + (bActive ? "yes" : "no"));
   287                 Console.WriteLine("vendor:        " + Lib.ToString(iVendorId));
   288                 Console.WriteLine("osd string:    " + osdName);
   289                 Console.WriteLine("CEC version:   " + Lib.ToString(iCecVersion));
   290                 Console.WriteLine("power status:  " + Lib.ToString(power));
   291                 if (!string.IsNullOrEmpty(lang))
   292                     Console.WriteLine("language:      " + lang);
   293                 Console.WriteLine("");
   294             }
   295         }
   296 
   297         public void ListAdapters()
   298         {
   299             int iAdapter = 0;
   300             foreach (CecAdapter adapter in iLib.FindAdapters(string.Empty))
   301             {
   302                 Console.WriteLine("Adapter:    " + iAdapter++);
   303                 Console.WriteLine("Path:         " + adapter.Path);
   304                 Console.WriteLine("Com port: " + adapter.ComPort);
   305             }
   306         }
   307 
   308         void ShowConsoleHelp()
   309         {
   310             Console.WriteLine(
   311                 "================================================================================" + Environment.NewLine +
   312                 "Available commands:" + Environment.NewLine +
   313                 Environment.NewLine +
   314                 "[tx] {bytes}                            transfer bytes over the CEC line." + Environment.NewLine +
   315                 "[txn] {bytes}                         transfer bytes but don't wait for transmission ACK." + Environment.NewLine +
   316                 "[on] {address}                        power on the device with the given logical address." + Environment.NewLine +
   317                 "[standby] {address}             put the device with the given address in standby mode." + Environment.NewLine +
   318                 "[la] {logical_address}        change the logical address of the CEC adapter." + Environment.NewLine +
   319                 "[pa] {physical_address}     change the physical address of the CEC adapter." + Environment.NewLine +
   320                 "[osd] {addr} {string}         set OSD message on the specified device." + Environment.NewLine +
   321                 "[ver] {addr}                            get the CEC version of the specified device." + Environment.NewLine +
   322                 "[ven] {addr}                            get the vendor ID of the specified device." + Environment.NewLine +
   323                 "[lang] {addr}                         get the menu language of the specified device." + Environment.NewLine +
   324                 "[pow] {addr}                            get the power status of the specified device." + Environment.NewLine +
   325                 "[poll] {addr}                         poll the specified device." + Environment.NewLine +
   326                 "[scan]                                        scan the CEC bus and display device info" + Environment.NewLine +
   327                 "[mon] {1|0}                             enable or disable CEC bus monitoring." + Environment.NewLine +
   328                 "[log] {1 - 31}                        change the log level. see cectypes.h for values." + Environment.NewLine +
   329                 "[ping]                                        send a ping command to the CEC adapter." + Environment.NewLine +
   330                 "[bl]                                            to let the adapter enter the bootloader, to upgrade" + Environment.NewLine +
   331                 "                                                    the flash rom." + Environment.NewLine +
   332                 "[r]                                             reconnect to the CEC adapter." + Environment.NewLine +
   333                 "[h] or [help]                         show this help." + Environment.NewLine +
   334                 "[q] or [quit]                         to quit the CEC test client and switch off all" + Environment.NewLine +
   335                 "                                                    connected CEC devices." + Environment.NewLine +
   336                 "================================================================================");
   337         }
   338 
   339         public void MainLoop()
   340         {
   341             bool bContinue = true;
   342             string command;
   343             while (bContinue)
   344             {
   345                 Console.WriteLine("waiting for input");
   346 
   347                 command = Console.ReadLine();
   348                 if (command != null && command.Length == 0)
   349                     continue;
   350                 string[] splitCommand = command.Split(' ');
   351                 if (splitCommand[0] == "tx" || splitCommand[0] == "txn")
   352                 {
   353                     CecCommand bytes = new CecCommand();
   354                     for (int iPtr = 1; iPtr < splitCommand.Length; iPtr++)
   355                     {
   356                         bytes.PushBack(byte.Parse(splitCommand[iPtr], System.Globalization.NumberStyles.HexNumber));
   357                     }
   358 
   359                     if (command == "txn")
   360                         bytes.TransmitTimeout = 0;
   361 
   362                     iLib.Transmit(bytes);
   363                 }
   364                 else if (splitCommand[0] == "on")
   365                 {
   366                     if (splitCommand.Length > 1)
   367                         iLib.PowerOnDevices((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   368                     else
   369                         iLib.PowerOnDevices(CecLogicalAddress.Broadcast);
   370                 }
   371                 else if (splitCommand[0] == "standby")
   372                 {
   373                     if (splitCommand.Length > 1)
   374                         iLib.StandbyDevices((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   375                     else
   376                         iLib.StandbyDevices(CecLogicalAddress.Broadcast);
   377                 }
   378                 else if (splitCommand[0] == "poll")
   379                 {
   380                     bool bSent = false;
   381                     if (splitCommand.Length > 1)
   382                         bSent = iLib.PollDevice((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   383                     else
   384                         bSent = iLib.PollDevice(CecLogicalAddress.Broadcast);
   385                     if (bSent)
   386                         Console.WriteLine("POLL message sent");
   387                     else
   388                         Console.WriteLine("POLL message not sent");
   389                 }
   390                 else if (splitCommand[0] == "la")
   391                 {
   392                     if (splitCommand.Length > 1)
   393                         iLib.SetLogicalAddress((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   394                 }
   395                 else if (splitCommand[0] == "pa")
   396                 {
   397                     if (splitCommand.Length > 1)
   398                         iLib.SetPhysicalAddress(ushort.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   399                 }
   400                 else if (splitCommand[0] == "osd")
   401                 {
   402                     if (splitCommand.Length > 2)
   403                     {
   404                         StringBuilder osdString = new StringBuilder();
   405                         for (int iPtr = 1; iPtr < splitCommand.Length; iPtr++)
   406                         {
   407                             osdString.Append(splitCommand[iPtr]);
   408                             if (iPtr != splitCommand.Length - 1)
   409                                 osdString.Append(" ");
   410                         }
   411                         iLib.SetOSDString((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber), CecDisplayControl.DisplayForDefaultTime, osdString.ToString());
   412                     }
   413                 }
   414                 else if (splitCommand[0] == "ping")
   415                 {
   416                     iLib.PingAdapter();
   417                 }
   418                 else if (splitCommand[0] == "mon")
   419                 {
   420                     bool enable = splitCommand.Length > 1 ? splitCommand[1] == "1" : false;
   421                     iLib.SwitchMonitoring(enable);
   422                 }
   423                 else if (splitCommand[0] == "bl")
   424                 {
   425                     iLib.StartBootloader();
   426                 }
   427                 else if (splitCommand[0] == "lang")
   428                 {
   429                     if (splitCommand.Length > 1)
   430                     {
   431                         string language = iLib.GetDeviceMenuLanguage((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   432                         Console.WriteLine("Menu language: " + language);
   433                     }
   434                 }
   435                 else if (splitCommand[0] == "ven")
   436                 {
   437                     if (splitCommand.Length > 1)
   438                     {
   439                         CecVendorId vendor = iLib.GetDeviceVendorId((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   440                         Console.WriteLine("Vendor ID: " + iLib.ToString(vendor));
   441                     }
   442                 }
   443                 else if (splitCommand[0] == "ver")
   444                 {
   445                     if (splitCommand.Length > 1)
   446                     {
   447                         CecVersion version = iLib.GetDeviceCecVersion((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   448                         Console.WriteLine("CEC version: " + iLib.ToString(version));
   449                     }
   450                 }
   451                 else if (splitCommand[0] == "pow")
   452                 {
   453                     if (splitCommand.Length > 1)
   454                     {
   455                         CecPowerStatus power = iLib.GetDevicePowerStatus((CecLogicalAddress)byte.Parse(splitCommand[1], System.Globalization.NumberStyles.HexNumber));
   456                         Console.WriteLine("power status: " + iLib.ToString(power));
   457                     }
   458                 }
   459                 else if (splitCommand[0] == "r")
   460                 {
   461                     Console.WriteLine("closing the connection");
   462                     iLib.Close();
   463 
   464                     Console.WriteLine("opening a new connection");
   465                     Connect(10000);
   466 
   467                     Console.WriteLine("setting active source");
   468                     iLib.SetActiveSource(CecDeviceType.PlaybackDevice);
   469                 }
   470                 else if (splitCommand[0] == "scan")
   471                 {
   472                     StringBuilder output = new StringBuilder();
   473                     output.AppendLine("CEC bus information");
   474                     output.AppendLine("===================");
   475                     CecLogicalAddresses addresses = iLib.GetActiveDevices();
   476                     for (int iPtr = 0; iPtr < addresses.Addresses.Length; iPtr++)
   477                     {
   478                         CecLogicalAddress address = (CecLogicalAddress)iPtr;
   479                         if (!addresses.IsSet(address))
   480                             continue;
   481 
   482                         CecVendorId iVendorId = iLib.GetDeviceVendorId(address);
   483                         bool bActive = iLib.IsActiveDevice(address);
   484                         ushort iPhysicalAddress = iLib.GetDevicePhysicalAddress(address);
   485                         string strAddr = "todo: fixme"; //Lib.PhysicalAddressToString(iPhysicalAddress);
   486                         CecVersion iCecVersion = iLib.GetDeviceCecVersion(address);
   487                         CecPowerStatus power = iLib.GetDevicePowerStatus(address);
   488                         string osdName = iLib.GetDeviceOSDName(address);
   489                         string lang = iLib.GetDeviceMenuLanguage(address);
   490 
   491                         output.AppendLine("device #" + iPtr + ": " + iLib.ToString(address));
   492                         output.AppendLine("address:             " + strAddr);
   493                         output.AppendLine("active source: " + (bActive ? "yes" : "no"));
   494                         output.AppendLine("vendor:                " + iLib.ToString(iVendorId));
   495                         output.AppendLine("osd string:        " + osdName);
   496                         output.AppendLine("CEC version:     " + iLib.ToString(iCecVersion));
   497                         output.AppendLine("power status:    " + iLib.ToString(power));
   498                         if (!string.IsNullOrEmpty(lang))
   499                             output.AppendLine("language:            " + lang);
   500                         output.AppendLine("");
   501                     }
   502                     Console.WriteLine(output.ToString());
   503                 }
   504                 else if (splitCommand[0] == "h" || splitCommand[0] == "help")
   505                     ShowConsoleHelp();
   506                 else if (splitCommand[0] == "q" || splitCommand[0] == "quit")
   507                     bContinue = false;
   508                 else if (splitCommand[0] == "log" && splitCommand.Length > 1)
   509                     LogLevel = int.Parse(splitCommand[1]);                
   510             }
   511         }
   512 
   513         /// TODO: remove that
   514         static void Main(string[] args)
   515         {
   516             Client p = new Client("CEC",2, CecLogLevel.All);
   517             if (p.Connect(10000))
   518             {
   519                 p.MainLoop();
   520             }
   521             else
   522             {
   523                 Console.WriteLine("Could not open a connection to the CEC adapter");
   524             }
   525         }
   526 
   527         /// <summary>
   528         /// Provide direct access to CEC library
   529         /// </summary>
   530         public LibCecSharp Lib
   531         {
   532             get
   533             {
   534                 return iLib;
   535             }
   536         }
   537 
   538         /// <summary>
   539         /// 
   540         /// </summary>
   541         private int LogLevel;
   542         /// <summary>
   543         /// 
   544         /// </summary>
   545         private LibCecSharp iLib;
   546         /// <summary>
   547         /// 
   548         /// </summary>
   549         private LibCECConfiguration Config;
   550 
   551         /// <summary>
   552         /// 
   553         /// </summary>
   554         private bool iConnected;
   555     }
   556 }