7f0667a84066d92245f91ba1827c7aa263aabcdc
[deb_libcec.git] / LibCecSharp.cpp
1 /*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011-2012 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 #include "CecSharpTypes.h"
34 #using <System.dll>
35
36 using namespace System;
37 using namespace System::Runtime::InteropServices;
38 using namespace CEC;
39 using namespace msclr::interop;
40
41 namespace CecSharp
42 {
43 public ref class LibCecSharp : public CecCallbackMethods
44 {
45 public:
46 LibCecSharp(LibCECConfiguration ^config)
47 {
48 m_callbacks = config->Callbacks;
49 CecCallbackMethods::EnableCallbacks(m_callbacks);
50 if (!InitialiseLibCec(config))
51 throw gcnew Exception("Could not initialise LibCecSharp");
52 }
53
54 LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes)
55 {
56 m_callbacks = gcnew CecCallbackMethods();
57 LibCECConfiguration ^config = gcnew LibCECConfiguration();
58 config->SetCallbacks(this);
59 config->DeviceName = strDeviceName;
60 config->DeviceTypes = deviceTypes;
61 if (!InitialiseLibCec(config))
62 throw gcnew Exception("Could not initialise LibCecSharp");
63 }
64
65 ~LibCecSharp(void)
66 {
67 Close();
68 m_libCec = NULL;
69 }
70
71 private:
72 !LibCecSharp(void)
73 {
74 Close();
75 m_libCec = NULL;
76 }
77
78 bool InitialiseLibCec(LibCECConfiguration ^config)
79 {
80 marshal_context ^ context = gcnew marshal_context();
81 libcec_configuration libCecConfig;
82 ConvertConfiguration(context, config, libCecConfig);
83
84 m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig);
85
86 delete context;
87 return m_libCec != NULL;
88 }
89
90 void ConvertConfiguration(marshal_context ^context, LibCECConfiguration ^netConfig, CEC::libcec_configuration &config)
91 {
92 config.Clear();
93
94 const char *strDeviceName = context->marshal_as<const char*>(netConfig->DeviceName);
95 memcpy_s(config.strDeviceName, 13, strDeviceName, 13);
96 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
97 config.deviceTypes.types[iPtr] = (cec_device_type)netConfig->DeviceTypes->Types[iPtr];
98
99 config.bAutodetectAddress = netConfig->AutodetectAddress ? 1 : 0;
100 config.iPhysicalAddress = netConfig->PhysicalAddress;
101 config.baseDevice = (cec_logical_address)netConfig->BaseDevice;
102 config.iHDMIPort = netConfig->HDMIPort;
103 config.clientVersion = (cec_client_version)netConfig->ClientVersion;
104 config.bGetSettingsFromROM = netConfig->GetSettingsFromROM ? 1 : 0;
105 config.bActivateSource = netConfig->ActivateSource ? 1 : 0;
106 config.tvVendor = (cec_vendor_id)netConfig->TvVendor;
107 config.wakeDevices.Clear();
108 for (int iPtr = 0; iPtr < 16; iPtr++)
109 {
110 if (netConfig->WakeDevices->IsSet((CecLogicalAddress)iPtr))
111 config.wakeDevices.Set((cec_logical_address)iPtr);
112 }
113 config.powerOffDevices.Clear();
114 for (int iPtr = 0; iPtr < 16; iPtr++)
115 {
116 if (netConfig->PowerOffDevices->IsSet((CecLogicalAddress)iPtr))
117 config.powerOffDevices.Set((cec_logical_address)iPtr);
118 }
119 config.bPowerOffScreensaver = netConfig->PowerOffScreensaver ? 1 : 0;
120 config.bPowerOffOnStandby = netConfig->PowerOffOnStandby ? 1 : 0;
121
122 if (netConfig->ServerVersion >= CecServerVersion::Version1_5_1)
123 config.bSendInactiveSource = netConfig->SendInactiveSource ? 1 : 0;
124
125 if (netConfig->ServerVersion >= CecServerVersion::Version1_6_0)
126 {
127 config.bPowerOffDevicesOnStandby = netConfig->PowerOffDevicesOnStandby ? 1 : 0;
128 config.bShutdownOnStandby = netConfig->ShutdownOnStandby ? 1 : 0;
129 }
130
131 if (netConfig->ServerVersion >= CecServerVersion::Version1_6_2)
132 {
133 const char *strDeviceLanguage = context->marshal_as<const char*>(netConfig->DeviceLanguage);
134 memcpy_s(config.strDeviceLanguage, 3, strDeviceLanguage, 3);
135 }
136
137 if (netConfig->ServerVersion >= CecServerVersion::Version1_6_3)
138 {
139 config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0;
140 }
141
142 config.callbacks = &g_cecCallbacks;
143 }
144
145 public:
146 array<CecAdapter ^> ^ FindAdapters(String ^ path)
147 {
148 cec_adapter *devices = new cec_adapter[10];
149
150 marshal_context ^ context = gcnew marshal_context();
151 const char* strPathC = path->Length > 0 ? context->marshal_as<const char*>(path) : NULL;
152
153 uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL);
154
155 array<CecAdapter ^> ^ adapters = gcnew array<CecAdapter ^>(iDevicesFound);
156 for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++)
157 adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm));
158
159 delete devices;
160 delete context;
161 return adapters;
162 }
163
164 bool Open(String ^ strPort, int iTimeoutMs)
165 {
166 CecCallbackMethods::EnableCallbacks(m_callbacks);
167 EnableCallbacks(m_callbacks);
168 marshal_context ^ context = gcnew marshal_context();
169 const char* strPortC = context->marshal_as<const char*>(strPort);
170 bool bReturn = m_libCec->Open(strPortC, iTimeoutMs);
171 delete context;
172 return bReturn;
173 }
174
175 void Close(void)
176 {
177 DisableCallbacks();
178 m_libCec->Close();
179 }
180
181 virtual void DisableCallbacks(void) override
182 {
183 // delete the callbacks, since these might already have been destroyed in .NET
184 CecCallbackMethods::DisableCallbacks();
185 if (m_libCec)
186 m_libCec->EnableCallbacks(NULL, NULL);
187 }
188
189 virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override
190 {
191 if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks))
192 return m_libCec->EnableCallbacks(NULL, &g_cecCallbacks);
193
194 return false;
195 }
196
197 bool PingAdapter(void)
198 {
199 return m_libCec->PingAdapter();
200 }
201
202 bool StartBootloader(void)
203 {
204 return m_libCec->StartBootloader();
205 }
206
207 int GetMinLibVersion(void)
208 {
209 return m_libCec->GetMinLibVersion();
210 }
211
212 int GetLibVersionMajor(void)
213 {
214 return m_libCec->GetLibVersionMajor();
215 }
216
217 int GetLibVersionMinor(void)
218 {
219 return m_libCec->GetLibVersionMinor();
220 }
221
222 CecLogMessage ^ GetNextLogMessage(void)
223 {
224 cec_log_message msg;
225 if (m_libCec->GetNextLogMessage(&msg))
226 {
227 return gcnew CecLogMessage(gcnew String(msg.message), (CecLogLevel)msg.level, msg.time);
228 }
229
230 return gcnew CecLogMessage();
231 }
232
233 CecKeypress ^ GetNextKeypress(void)
234 {
235 cec_keypress key;
236 if (m_libCec->GetNextKeypress(&key))
237 {
238 return gcnew CecKeypress((CecUserControlCode)key.keycode, key.duration);
239 }
240
241 return gcnew CecKeypress();
242 }
243
244 CecCommand ^ GetNextCommand(void)
245 {
246 cec_command command;
247 if (m_libCec->GetNextCommand(&command))
248 {
249 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);
250 for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
251 retVal->Parameters->PushBack(command.parameters[iPtr]);
252 return retVal;
253 }
254
255 return gcnew CecCommand();
256 }
257
258 bool Transmit(CecCommand ^ command)
259 {
260 cec_command ccommand;
261 cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode);
262 ccommand.transmit_timeout = command->TransmitTimeout;
263 ccommand.eom = command->Eom;
264 ccommand.ack = command->Ack;
265 for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++)
266 ccommand.parameters.PushBack(command->Parameters->Data[iPtr]);
267
268 return m_libCec->Transmit(ccommand);
269 }
270
271 bool SetLogicalAddress(CecLogicalAddress logicalAddress)
272 {
273 return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress);
274 }
275
276 bool SetPhysicalAddress(uint16_t physicalAddress)
277 {
278 return m_libCec->SetPhysicalAddress(physicalAddress);
279 }
280
281 bool PowerOnDevices(CecLogicalAddress logicalAddress)
282 {
283 return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress);
284 }
285
286 bool StandbyDevices(CecLogicalAddress logicalAddress)
287 {
288 return m_libCec->StandbyDevices((cec_logical_address) logicalAddress);
289 }
290
291 bool PollDevice(CecLogicalAddress logicalAddress)
292 {
293 return m_libCec->PollDevice((cec_logical_address) logicalAddress);
294 }
295
296 bool SetActiveSource(CecDeviceType type)
297 {
298 return m_libCec->SetActiveSource((cec_device_type) type);
299 }
300
301 bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate)
302 {
303 return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate);
304 }
305
306 bool SetDeckInfo(CecDeckInfo info, bool sendUpdate)
307 {
308 return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate);
309 }
310
311 bool SetInactiveView(void)
312 {
313 return m_libCec->SetInactiveView();
314 }
315
316 bool SetMenuState(CecMenuState state, bool sendUpdate)
317 {
318 return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate);
319 }
320
321 bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message)
322 {
323 marshal_context ^ context = gcnew marshal_context();
324 const char* strMessageC = context->marshal_as<const char*>(message);
325
326 bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC);
327
328 delete context;
329 return bReturn;
330 }
331
332 bool SwitchMonitoring(bool enable)
333 {
334 return m_libCec->SwitchMonitoring(enable);
335 }
336
337 CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress)
338 {
339 return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress);
340 }
341
342 String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress)
343 {
344 cec_menu_language lang;
345 if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang))
346 {
347 return gcnew String(lang.language);
348 }
349
350 return gcnew String("");
351 }
352
353 CecVendorId GetDeviceVendorId(CecLogicalAddress logicalAddress)
354 {
355 return (CecVendorId)m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress);
356 }
357
358 CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress)
359 {
360 return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress);
361 }
362
363 void RescanActiveDevices(void)
364 {
365 m_libCec->RescanActiveDevices();
366 }
367
368 CecLogicalAddresses ^ GetActiveDevices(void)
369 {
370 CecLogicalAddresses ^ retVal = gcnew CecLogicalAddresses();
371 unsigned int iDevices = 0;
372
373 cec_logical_addresses activeDevices = m_libCec->GetActiveDevices();
374
375 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
376 if (activeDevices[iPtr])
377 retVal->Addresses[iDevices++] = (CecLogicalAddress)iPtr;
378
379 return retVal;
380 }
381
382 bool IsActiveDevice(CecLogicalAddress logicalAddress)
383 {
384 return m_libCec->IsActiveDevice((cec_logical_address)logicalAddress);
385 }
386
387 bool IsActiveDeviceType(CecDeviceType type)
388 {
389 return m_libCec->IsActiveDeviceType((cec_device_type)type);
390 }
391
392 bool SetHDMIPort(CecLogicalAddress address, uint8_t port)
393 {
394 return m_libCec->SetHDMIPort((cec_logical_address)address, port);
395 }
396
397 uint8_t VolumeUp(bool wait)
398 {
399 return m_libCec->VolumeUp(wait);
400 }
401
402 uint8_t VolumeDown(bool wait)
403 {
404 return m_libCec->VolumeDown(wait);
405 }
406
407 uint8_t MuteAudio(bool wait)
408 {
409 return m_libCec->MuteAudio(wait);
410 }
411
412 bool SendKeypress(CecLogicalAddress destination, CecUserControlCode key, bool wait)
413 {
414 return m_libCec->SendKeypress((cec_logical_address)destination, (cec_user_control_code)key, wait);
415 }
416
417 bool SendKeyRelease(CecLogicalAddress destination, bool wait)
418 {
419 return m_libCec->SendKeyRelease((cec_logical_address)destination, wait);
420 }
421
422 String ^ GetDeviceOSDName(CecLogicalAddress logicalAddress)
423 {
424 cec_osd_name osd = m_libCec->GetDeviceOSDName((cec_logical_address) logicalAddress);
425 return gcnew String(osd.name);
426 }
427
428 CecLogicalAddress GetActiveSource()
429 {
430 return (CecLogicalAddress)m_libCec->GetActiveSource();
431 }
432
433 bool IsActiveSource(CecLogicalAddress logicalAddress)
434 {
435 return m_libCec->IsActiveSource((cec_logical_address)logicalAddress);
436 }
437
438 uint16_t GetDevicePhysicalAddress(CecLogicalAddress iAddress)
439 {
440 return m_libCec->GetDevicePhysicalAddress((cec_logical_address)iAddress);
441 }
442
443 bool SetStreamPath(CecLogicalAddress iAddress)
444 {
445 return m_libCec->SetStreamPath((cec_logical_address)iAddress);
446 }
447
448 bool SetStreamPath(uint16_t iPhysicalAddress)
449 {
450 return m_libCec->SetStreamPath(iPhysicalAddress);
451 }
452
453 CecLogicalAddresses ^GetLogicalAddresses(void)
454 {
455 CecLogicalAddresses ^addr = gcnew CecLogicalAddresses();
456 cec_logical_addresses libAddr = m_libCec->GetLogicalAddresses();
457 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
458 addr->Addresses[iPtr] = (CecLogicalAddress)libAddr.addresses[iPtr];
459 addr->Primary = (CecLogicalAddress)libAddr.primary;
460 return addr;
461 }
462
463 bool GetCurrentConfiguration(LibCECConfiguration ^configuration)
464 {
465 libcec_configuration config;
466 config.Clear();
467
468 if (m_libCec->GetCurrentConfiguration(&config))
469 {
470 configuration->Update(config);
471 return true;
472 }
473 return false;
474 }
475
476 bool CanPersistConfiguration(void)
477 {
478 return m_libCec->CanPersistConfiguration();
479 }
480
481 bool PersistConfiguration(LibCECConfiguration ^configuration)
482 {
483 marshal_context ^ context = gcnew marshal_context();
484 libcec_configuration config;
485 ConvertConfiguration(context, configuration, config);
486
487 bool bReturn = m_libCec->PersistConfiguration(&config);
488
489 delete context;
490 return bReturn;
491 }
492
493 bool SetConfiguration(LibCECConfiguration ^configuration)
494 {
495 marshal_context ^ context = gcnew marshal_context();
496 libcec_configuration config;
497 ConvertConfiguration(context, configuration, config);
498
499 bool bReturn = m_libCec->SetConfiguration(&config);
500
501 delete context;
502 return bReturn;
503 }
504
505 bool IsLibCECActiveSource()
506 {
507 return m_libCec->IsLibCECActiveSource();
508 }
509
510 bool GetDeviceInformation(String ^ port, LibCECConfiguration ^configuration, uint32_t timeoutMs)
511 {
512 bool bReturn(false);
513 marshal_context ^ context = gcnew marshal_context();
514
515 libcec_configuration config;
516 config.Clear();
517
518 const char* strPortC = port->Length > 0 ? context->marshal_as<const char*>(port) : NULL;
519
520 if (m_libCec->GetDeviceInformation(strPortC, &config, timeoutMs))
521 {
522 configuration->Update(config);
523 bReturn = true;
524 }
525
526 delete context;
527 return bReturn;
528 }
529
530 String ^ ToString(CecLogicalAddress iAddress)
531 {
532 const char *retVal = m_libCec->ToString((cec_logical_address)iAddress);
533 return gcnew String(retVal);
534 }
535
536 String ^ ToString(CecVendorId iVendorId)
537 {
538 const char *retVal = m_libCec->ToString((cec_vendor_id)iVendorId);
539 return gcnew String(retVal);
540 }
541
542 String ^ ToString(CecVersion iVersion)
543 {
544 const char *retVal = m_libCec->ToString((cec_version)iVersion);
545 return gcnew String(retVal);
546 }
547
548 String ^ ToString(CecPowerStatus iState)
549 {
550 const char *retVal = m_libCec->ToString((cec_power_status)iState);
551 return gcnew String(retVal);
552 }
553
554 String ^ ToString(CecMenuState iState)
555 {
556 const char *retVal = m_libCec->ToString((cec_menu_state)iState);
557 return gcnew String(retVal);
558 }
559
560 String ^ ToString(CecDeckControlMode iMode)
561 {
562 const char *retVal = m_libCec->ToString((cec_deck_control_mode)iMode);
563 return gcnew String(retVal);
564 }
565
566 String ^ ToString(CecDeckInfo status)
567 {
568 const char *retVal = m_libCec->ToString((cec_deck_info)status);
569 return gcnew String(retVal);
570 }
571
572 String ^ ToString(CecOpcode opcode)
573 {
574 const char *retVal = m_libCec->ToString((cec_opcode)opcode);
575 return gcnew String(retVal);
576 }
577
578 String ^ ToString(CecSystemAudioStatus mode)
579 {
580 const char *retVal = m_libCec->ToString((cec_system_audio_status)mode);
581 return gcnew String(retVal);
582 }
583
584 String ^ ToString(CecAudioStatus status)
585 {
586 const char *retVal = m_libCec->ToString((cec_audio_status)status);
587 return gcnew String(retVal);
588 }
589
590 String ^ ToString(CecClientVersion version)
591 {
592 const char *retVal = m_libCec->ToString((cec_client_version)version);
593 return gcnew String(retVal);
594 }
595
596 String ^ ToString(CecServerVersion version)
597 {
598 const char *retVal = m_libCec->ToString((cec_server_version)version);
599 return gcnew String(retVal);
600 }
601
602 private:
603 ICECAdapter * m_libCec;
604 CecCallbackMethods ^ m_callbacks;
605 };
606 }