LibCecSharp: better handling of callbacks
[deb_libcec.git] / src / LibCecSharp / CecSharpTypes.h
1 #pragma once
2 /*
3 * This file is part of the libCEC(R) library.
4 *
5 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
6 * libCEC(R) is an original work, containing original code.
7 *
8 * libCEC(R) is a trademark of Pulse-Eight Limited.
9 *
10 * This program is dual-licensed; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 *
24 *
25 * Alternatively, you can license this library under a commercial license,
26 * please contact Pulse-Eight Licensing for more information.
27 *
28 * For more information contact:
29 * Pulse-Eight Licensing <license@pulse-eight.com>
30 * http://www.pulse-eight.com/
31 * http://www.pulse-eight.net/
32 */
33
34 #include "../lib/platform/threads/mutex.h"
35 #include <vcclr.h>
36 #include <msclr/marshal.h>
37 #include "../../include/cec.h"
38 #include <vector>
39
40 #using <System.dll>
41
42 namespace CecSharp
43 {
44 public enum class CecDeviceType
45 {
46 Tv = 0,
47 RecordingDevice = 1,
48 Reserved = 2,
49 Tuner = 3,
50 PlaybackDevice = 4,
51 AudioSystem = 5
52 };
53
54 public enum class CecLogLevel
55 {
56 None = 0,
57 Error = 1,
58 Warning = 2,
59 Notice = 4,
60 Traffic = 8,
61 Debug = 16,
62 All = 31
63 };
64
65 public enum class CecLogicalAddress
66 {
67 Unknown = -1, //not a valid logical address
68 Tv = 0,
69 RecordingDevice1 = 1,
70 RecordingDevice2 = 2,
71 Tuner1 = 3,
72 PlaybackDevice1 = 4,
73 AudioSystem = 5,
74 Tuner2 = 6,
75 Tuner3 = 7,
76 PlaybackDevice2 = 8,
77 RecordingDevice3 = 9,
78 Tuner4 = 10,
79 PlaybackDevice3 = 11,
80 Reserved1 = 12,
81 Reserved2 = 13,
82 FreeUse = 14,
83 Unregistered = 15,
84 Broadcast = 15
85 };
86
87 public enum class CecAlert
88 {
89 ServiceDevice = 1
90 };
91
92 public enum class CecParameterType
93 {
94 ParameterTypeString = 1
95 };
96
97 public ref class CecParameter
98 {
99 public:
100 CecParameter(CecParameterType type, System::String ^ strData)
101 {
102 Type = type;
103 Data = strData;
104 }
105
106 property CecParameterType Type;
107 property System::String ^ Data;
108 };
109
110 public enum class CecPowerStatus
111 {
112 On = 0x00,
113 Standby = 0x01,
114 InTransitionStandbyToOn = 0x02,
115 InTransitionOnToStandby = 0x03,
116 Unknown = 0x99
117 };
118
119 public enum class CecVersion
120 {
121 Unknown = 0x00,
122 V1_2 = 0x01,
123 V1_2A = 0x02,
124 V1_3 = 0x03,
125 V1_3A = 0x04,
126 V1_4 = 0x05
127 };
128
129 public enum class CecDisplayControl
130 {
131 DisplayForDefaultTime = 0x00,
132 DisplayUntilCleared = 0x40,
133 ClearPreviousMessage = 0x80,
134 ReservedForFutureUse = 0xC0
135 };
136
137 public enum class CecMenuState
138 {
139 Activated = 0,
140 Deactivated = 1
141 };
142
143 public enum class CecDeckControlMode
144 {
145 SkipForwardWind = 1,
146 SkipReverseRewind = 2,
147 Stop = 3,
148 Eject = 4
149 };
150
151 public enum class CecDeckInfo
152 {
153 Play = 0x11,
154 Record = 0x12,
155 Reverse = 0x13,
156 Still = 0x14,
157 Slow = 0x15,
158 SlowReverse = 0x16,
159 FastForward = 0x17,
160 FastReverse = 0x18,
161 NoMedia = 0x19,
162 Stop = 0x1A,
163 SkipForwardWind = 0x1B,
164 SkipReverseRewind = 0x1C,
165 IndexSearchForward = 0x1D,
166 IndexSearchReverse = 0x1E,
167 OtherStatus = 0x1F
168 };
169
170 public enum class CecUserControlCode
171 {
172 Select = 0x00,
173 Up = 0x01,
174 Down = 0x02,
175 Left = 0x03,
176 Right = 0x04,
177 RightUp = 0x05,
178 RightDown = 0x06,
179 LeftUp = 0x07,
180 LeftDown = 0x08,
181 RootMenu = 0x09,
182 SetupMenu = 0x0A,
183 ContentsMenu = 0x0B,
184 FavoriteMenu = 0x0C,
185 Exit = 0x0D,
186 Number0 = 0x20,
187 Number1 = 0x21,
188 Number2 = 0x22,
189 Number3 = 0x23,
190 Number4 = 0x24,
191 Number5 = 0x25,
192 Number6 = 0x26,
193 Number7 = 0x27,
194 Number8 = 0x28,
195 Number9 = 0x29,
196 Dot = 0x2A,
197 Enter = 0x2B,
198 Clear = 0x2C,
199 NextFavorite = 0x2F,
200 ChannelUp = 0x30,
201 ChannelDown = 0x31,
202 PreviousChannel = 0x32,
203 SoundSelect = 0x33,
204 InputSelect = 0x34,
205 DisplayInformation = 0x35,
206 Help = 0x36,
207 PageUp = 0x37,
208 PageDown = 0x38,
209 Power = 0x40,
210 VolumeUp = 0x41,
211 VolumeDown = 0x42,
212 Mute = 0x43,
213 Play = 0x44,
214 Stop = 0x45,
215 Pause = 0x46,
216 Record = 0x47,
217 Rewind = 0x48,
218 FastForward = 0x49,
219 Eject = 0x4A,
220 Forward = 0x4B,
221 Backward = 0x4C,
222 StopRecord = 0x4D,
223 PauseRecord = 0x4E,
224 Angle = 0x50,
225 SubPicture = 0x51,
226 VideoOnDemand = 0x52,
227 ElectronicProgramGuide = 0x53,
228 TimerProgramming = 0x54,
229 InitialConfiguration = 0x55,
230 PlayFunction = 0x60,
231 PausePlayFunction = 0x61,
232 RecordFunction = 0x62,
233 PauseRecordFunction = 0x63,
234 StopFunction = 0x64,
235 MuteFunction = 0x65,
236 RestoreVolumeFunction = 0x66,
237 TuneFunction = 0x67,
238 SelectMediaFunction = 0x68,
239 SelectAVInputFunction = 0x69,
240 SelectAudioInputFunction = 0x6A,
241 PowerToggleFunction = 0x6B,
242 PowerOffFunction = 0x6C,
243 PowerOnFunction = 0x6D,
244 F1Blue = 0x71,
245 F2Red = 0X72,
246 F3Green = 0x73,
247 F4Yellow = 0x74,
248 F5 = 0x75,
249 Data = 0x76,
250 Max = 0x76,
251 SamsungReturn = 0x91,
252 Unknown
253 };
254
255 public enum class CecVendorId
256 {
257 Samsung = 0x00F0,
258 LG = 0xE091,
259 Panasonic = 0x8045,
260 Pioneer = 0xE036,
261 Onkyo = 0x09B0,
262 Yamaha = 0xA0DE,
263 Philips = 0x903E,
264 Sony = 0x080046,
265 Unknown = 0
266 };
267
268 public enum class CecAudioStatus
269 {
270 MuteStatusMask = 0x80,
271 VolumeStatusMask = 0x7F,
272 VolumeMin = 0x00,
273 VolumeMax = 0x64,
274 VolumeStatusUnknown = 0x7F
275 };
276
277 public enum class CecOpcode
278 {
279 ActiveSource = 0x82,
280 ImageViewOn = 0x04,
281 TextViewOn = 0x0D,
282 InactiveSource = 0x9D,
283 RequestActiveSource = 0x85,
284 RoutingChange = 0x80,
285 RoutingInformation = 0x81,
286 SetStreamPath = 0x86,
287 Standby = 0x36,
288 RecordOff = 0x0B,
289 RecordOn = 0x09,
290 RecordStatus = 0x0A,
291 RecordTvScreen = 0x0F,
292 ClearAnalogueTimer = 0x33,
293 ClearDigitalTimer = 0x99,
294 ClearExternalTimer = 0xA1,
295 SetAnalogueTimer = 0x34,
296 SetDigitalTimer = 0x97,
297 SetExternalTimer = 0xA2,
298 SetTimerProgramTitle = 0x67,
299 TimerClearedStatus = 0x43,
300 TimerStatus = 0x35,
301 CecVersion = 0x9E,
302 GetCecVersion = 0x9F,
303 GivePhysicalAddress = 0x83,
304 GetMenuLanguage = 0x91,
305 ReportPhysicalAddress = 0x84,
306 SetMenuLanguage = 0x32,
307 DeckControl = 0x42,
308 DeckStatus = 0x1B,
309 GiveDeckStatus = 0x1A,
310 Play = 0x41,
311 GiveTunerDeviceStatus = 0x08,
312 SelectAnalogueService = 0x92,
313 SelectDigtalService = 0x93,
314 TunerDeviceStatus = 0x07,
315 TunerStepDecrement = 0x06,
316 TunerStepIncrement = 0x05,
317 DeviceVendorId = 0x87,
318 GiveDeviceVendorId = 0x8C,
319 VendorCommand = 0x89,
320 VendorCommandWithId = 0xA0,
321 VendorRemoteButtonDown = 0x8A,
322 VendorRemoteButtonUp = 0x8B,
323 SetOsdString = 0x64,
324 GiveOsdName = 0x46,
325 SetOsdName = 0x47,
326 MenuRequest = 0x8D,
327 MenuStatus = 0x8E,
328 UserControlPressed = 0x44,
329 UserControlRelease = 0x45,
330 GiveDevicePowerStatus = 0x8F,
331 ReportPowerStatus = 0x90,
332 FeatureAbort = 0x00,
333 Abort = 0xFF,
334 GiveAudioStatus = 0x71,
335 GiveSystemAudioMode = 0x7D,
336 ReportAudioStatus = 0x7A,
337 SetSystemAudioMode = 0x72,
338 SystemAudioModeRequest = 0x70,
339 SystemAudioModeStatus = 0x7E,
340 SetAudioRate = 0x9A,
341 /* when this opcode is set, no opcode will be sent to the device. this is one of the reserved numbers */
342 None = 0xFD
343 };
344
345 public enum class CecSystemAudioStatus
346 {
347 Off = 0,
348 On = 1
349 };
350
351 public enum class CecClientVersion
352 {
353 VersionPre1_5 = 0,
354 Version1_5_0 = 0x1500,
355 Version1_5_1 = 0x1501,
356 Version1_5_2 = 0x1502,
357 Version1_5_3 = 0x1503,
358 Version1_6_0 = 0x1600,
359 Version1_6_1 = 0x1601,
360 Version1_6_2 = 0x1602,
361 Version1_6_3 = 0x1603,
362 Version1_7_0 = 0x1700,
363 Version1_7_1 = 0x1701
364 };
365
366 public enum class CecServerVersion
367 {
368 VersionPre1_5 = 0,
369 Version1_5_0 = 0x1500,
370 Version1_5_1 = 0x1501,
371 Version1_5_2 = 0x1502,
372 Version1_5_3 = 0x1503,
373 Version1_6_0 = 0x1600,
374 Version1_6_1 = 0x1601,
375 Version1_6_2 = 0x1602,
376 Version1_6_3 = 0x1603,
377 Version1_7_0 = 0x1700,
378 Version1_7_1 = 0x1701
379 };
380
381 public ref class CecAdapter
382 {
383 public:
384 CecAdapter(System::String ^ strPath, System::String ^ strComPort)
385 {
386 Path = strPath;
387 ComPort = strComPort;
388 }
389
390 property System::String ^ Path;
391 property System::String ^ ComPort;
392 };
393
394 public ref class CecDeviceTypeList
395 {
396 public:
397 CecDeviceTypeList(void)
398 {
399 Types = gcnew array<CecDeviceType>(5);
400 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
401 Types[iPtr] = CecDeviceType::Reserved;
402 }
403
404 property array<CecDeviceType> ^ Types;
405 };
406
407 public ref class CecLogicalAddresses
408 {
409 public:
410 CecLogicalAddresses(void)
411 {
412 Addresses = gcnew array<CecLogicalAddress>(16);
413 Clear();
414 }
415
416 void Clear(void)
417 {
418 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
419 Addresses[iPtr] = CecLogicalAddress::Unknown;
420 }
421
422 bool IsSet(CecLogicalAddress iAddress)
423 {
424 return Addresses[(unsigned int)iAddress] != CecLogicalAddress::Unknown;
425 }
426
427 void Set(CecLogicalAddress iAddress)
428 {
429 Addresses[(unsigned int)iAddress] = iAddress;
430 }
431
432 property CecLogicalAddress Primary;
433 property array<CecLogicalAddress> ^ Addresses;
434 };
435
436 public ref class CecDatapacket
437 {
438 public:
439 CecDatapacket(void)
440 {
441 Data = gcnew array<uint8_t>(100);
442 Size = 0;
443 }
444
445 void PushBack(uint8_t data)
446 {
447 if (Size < 100)
448 {
449 Data[Size] = data;
450 Size++;
451 }
452 }
453
454 property array<uint8_t> ^ Data;
455 property uint8_t Size;
456 };
457
458 public ref class CecCommand
459 {
460 public:
461 CecCommand(CecLogicalAddress iInitiator, CecLogicalAddress iDestination, bool bAck, bool bEom, CecOpcode iOpcode, int32_t iTransmitTimeout)
462 {
463 Initiator = iInitiator;
464 Destination = iDestination;
465 Ack = bAck;
466 Eom = bEom;
467 Opcode = iOpcode;
468 OpcodeSet = true;
469 TransmitTimeout = iTransmitTimeout;
470 Parameters = gcnew CecDatapacket;
471 Empty = false;
472 }
473
474 CecCommand(void)
475 {
476 Initiator = CecLogicalAddress::Unknown;
477 Destination = CecLogicalAddress::Unknown;
478 Ack = false;
479 Eom = false;
480 Opcode = CecOpcode::None;
481 OpcodeSet = false;
482 TransmitTimeout = 0;
483 Parameters = gcnew CecDatapacket;
484 Empty = true;
485 }
486
487 void PushBack(uint8_t data)
488 {
489 if (Initiator == CecLogicalAddress::Unknown && Destination == CecLogicalAddress::Unknown)
490 {
491 Initiator = (CecLogicalAddress) (data >> 4);
492 Destination = (CecLogicalAddress) (data & 0xF);
493 }
494 else if (!OpcodeSet)
495 {
496 OpcodeSet = true;
497 Opcode = (CecOpcode)data;
498 }
499 else
500 {
501 Parameters->PushBack(data);
502 }
503 }
504
505 property bool Empty;
506 property CecLogicalAddress Initiator;
507 property CecLogicalAddress Destination;
508 property bool Ack;
509 property bool Eom;
510 property CecOpcode Opcode;
511 property CecDatapacket ^ Parameters;
512 property bool OpcodeSet;
513 property int32_t TransmitTimeout;
514 };
515
516 public ref class CecKeypress
517 {
518 public:
519 CecKeypress(CecUserControlCode iKeycode, unsigned int iDuration)
520 {
521 Keycode = iKeycode;
522 Duration = iDuration;
523 Empty = false;
524 }
525
526 CecKeypress(void)
527 {
528 Keycode = CecUserControlCode::Unknown;
529 Duration = 0;
530 Empty = true;
531 }
532
533 property bool Empty;
534 property CecUserControlCode Keycode;
535 property unsigned int Duration;
536 };
537
538 public ref class CecLogMessage
539 {
540 public:
541 CecLogMessage(System::String ^ strMessage, CecLogLevel iLevel, int64_t iTime)
542 {
543 Message = strMessage;
544 Level = iLevel;
545 Time = iTime;
546 Empty = false;
547 }
548
549 CecLogMessage(void)
550 {
551 Message = "";
552 Level = CecLogLevel::None;
553 Time = 0;
554 Empty = true;
555 }
556
557 property bool Empty;
558 property System::String ^Message;
559 property CecLogLevel Level;
560 property int64_t Time;
561 };
562
563 ref class CecCallbackMethods; //forward
564 public ref class LibCECConfiguration
565 {
566 public:
567 LibCECConfiguration(void)
568 {
569 DeviceName = "";
570 DeviceTypes = gcnew CecDeviceTypeList();
571 AutodetectAddress = true;
572 PhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
573 BaseDevice = (CecLogicalAddress)CEC_DEFAULT_BASE_DEVICE;
574 HDMIPort = CEC_DEFAULT_HDMI_PORT;
575 ClientVersion = CecClientVersion::VersionPre1_5;
576 ServerVersion = CecServerVersion::VersionPre1_5;
577 TvVendor = CecVendorId::Unknown;
578
579 GetSettingsFromROM = false;
580 UseTVMenuLanguage = CEC_DEFAULT_SETTING_USE_TV_MENU_LANGUAGE == 1;
581 ActivateSource = CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1;
582
583 WakeDevices = gcnew CecLogicalAddresses();
584 if (CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1)
585 WakeDevices->Set(CecLogicalAddress::Tv);
586
587 PowerOffDevices = gcnew CecLogicalAddresses();
588 if (CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN == 1)
589 PowerOffDevices->Set(CecLogicalAddress::Broadcast);
590
591 PowerOffScreensaver = CEC_DEFAULT_SETTING_POWER_OFF_SCREENSAVER == 1;
592 PowerOffOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY == 1;
593
594 SendInactiveSource = CEC_DEFAULT_SETTING_SEND_INACTIVE_SOURCE == 1;
595 LogicalAddresses = gcnew CecLogicalAddresses();
596 FirmwareVersion = 1;
597 PowerOffDevicesOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_DEVICES_STANDBY == 1;
598 ShutdownOnStandby = CEC_DEFAULT_SETTING_SHUTDOWN_ON_STANDBY == 1;
599 DeviceLanguage = "";
600 }
601
602 void SetCallbacks(CecCallbackMethods ^callbacks)
603 {
604 Callbacks = callbacks;
605 }
606
607 void Update(const CEC::libcec_configuration &config)
608 {
609 DeviceName = gcnew System::String(config.strDeviceName);
610
611 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
612 DeviceTypes->Types[iPtr] = (CecDeviceType)config.deviceTypes.types[iPtr];
613
614 AutodetectAddress = config.bAutodetectAddress == 1;
615 PhysicalAddress = config.iPhysicalAddress;
616 BaseDevice = (CecLogicalAddress)config.baseDevice;
617 HDMIPort = config.iHDMIPort;
618 ClientVersion = (CecClientVersion)config.clientVersion;
619 ServerVersion = (CecServerVersion)config.serverVersion;
620 TvVendor = (CecVendorId)config.tvVendor;
621
622 // player specific settings
623 GetSettingsFromROM = config.bGetSettingsFromROM == 1;
624 UseTVMenuLanguage = config.bUseTVMenuLanguage == 1;
625 ActivateSource = config.bActivateSource == 1;
626
627 WakeDevices->Clear();
628 for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
629 if (config.wakeDevices[iPtr])
630 WakeDevices->Set((CecLogicalAddress)iPtr);
631
632 PowerOffDevices->Clear();
633 for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
634 if (config.powerOffDevices[iPtr])
635 PowerOffDevices->Set((CecLogicalAddress)iPtr);
636
637 PowerOffScreensaver = config.bPowerOffScreensaver == 1;
638 PowerOffOnStandby = config.bPowerOffOnStandby == 1;
639
640 if (ServerVersion >= CecServerVersion::Version1_5_1)
641 SendInactiveSource = config.bSendInactiveSource == 1;
642
643 if (ServerVersion >= CecServerVersion::Version1_5_3)
644 {
645 LogicalAddresses->Clear();
646 for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
647 if (config.logicalAddresses[iPtr])
648 LogicalAddresses->Set((CecLogicalAddress)iPtr);
649 }
650
651 if (ServerVersion >= CecServerVersion::Version1_6_0)
652 {
653 FirmwareVersion = config.iFirmwareVersion;
654 PowerOffDevicesOnStandby = config.bPowerOffDevicesOnStandby == 1;
655 ShutdownOnStandby = config.bShutdownOnStandby == 1;
656 }
657
658 if (ServerVersion >= CecServerVersion::Version1_6_2)
659 DeviceLanguage = gcnew System::String(config.strDeviceLanguage);
660
661 if (ServerVersion >= CecServerVersion::Version1_6_3)
662 MonitorOnlyClient = config.bMonitorOnly == 1;
663 }
664
665 property System::String ^ DeviceName;
666 property CecDeviceTypeList ^ DeviceTypes;
667 property bool AutodetectAddress;
668 property uint16_t PhysicalAddress;
669 property CecLogicalAddress BaseDevice;
670 property uint8_t HDMIPort;
671 property CecClientVersion ClientVersion;
672 property CecServerVersion ServerVersion;
673 property CecVendorId TvVendor;
674
675 // player specific settings
676 property bool GetSettingsFromROM;
677 property bool UseTVMenuLanguage;
678 property bool ActivateSource;
679 property CecLogicalAddresses ^WakeDevices;
680 property CecLogicalAddresses ^PowerOffDevices;
681 property bool PowerOffScreensaver;
682 property bool PowerOffOnStandby;
683 property bool SendInactiveSource;
684 property CecLogicalAddresses ^LogicalAddresses;
685 property uint16_t FirmwareVersion;
686 property bool PowerOffDevicesOnStandby;
687 property bool ShutdownOnStandby;
688 property bool MonitorOnlyClient;
689 property System::String ^ DeviceLanguage;
690 property CecCallbackMethods ^ Callbacks;
691 };
692
693 // the callback methods are called by unmanaged code, so we need some delegates for this
694 #pragma unmanaged
695 // unmanaged callback methods
696 typedef int (__stdcall *LOGCB) (const CEC::cec_log_message &message);
697 typedef int (__stdcall *KEYCB) (const CEC::cec_keypress &key);
698 typedef int (__stdcall *COMMANDCB)(const CEC::cec_command &command);
699 typedef int (__stdcall *CONFIGCB) (const CEC::libcec_configuration &config);
700 typedef int (__stdcall *ALERTCB) (const CEC::libcec_alert, const CEC::libcec_parameter &data);
701 typedef int (__stdcall *MENUCB) (const CEC::cec_menu_state newVal);
702 typedef void (__stdcall *ACTICB) (const CEC::cec_logical_address logicalAddress, const uint8_t bActivated);
703
704 typedef struct
705 {
706 LOGCB logCB;
707 KEYCB keyCB;
708 COMMANDCB commandCB;
709 CONFIGCB configCB;
710 ALERTCB alertCB;
711 MENUCB menuCB;
712 ACTICB sourceActivatedCB;
713 } UnmanagedCecCallbacks;
714
715 static PLATFORM::CMutex g_callbackMutex;
716 static std::vector<UnmanagedCecCallbacks> g_unmanagedCallbacks;
717 static CEC::ICECCallbacks g_cecCallbacks;
718
719 int CecLogMessageCB(void *cbParam, const CEC::cec_log_message &message)
720 {
721 if (cbParam)
722 {
723 size_t iPtr = (size_t)cbParam;
724 PLATFORM::CLockObject lock(g_callbackMutex);
725 if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
726 return g_unmanagedCallbacks[iPtr].logCB(message);
727 }
728 return 0;
729 }
730
731 int CecKeyPressCB(void *cbParam, const CEC::cec_keypress &key)
732 {
733 if (cbParam)
734 {
735 size_t iPtr = (size_t)cbParam;
736 PLATFORM::CLockObject lock(g_callbackMutex);
737 if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
738 return g_unmanagedCallbacks[iPtr].keyCB(key);
739 }
740 return 0;
741 }
742
743 int CecCommandCB(void *cbParam, const CEC::cec_command &command)
744 {
745 if (cbParam)
746 {
747 size_t iPtr = (size_t)cbParam;
748 PLATFORM::CLockObject lock(g_callbackMutex);
749 if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
750 return g_unmanagedCallbacks[iPtr].commandCB(command);
751 }
752 return 0;
753 }
754
755 int CecConfigCB(void *cbParam, const CEC::libcec_configuration &config)
756 {
757 if (cbParam)
758 {
759 size_t iPtr = (size_t)cbParam;
760 PLATFORM::CLockObject lock(g_callbackMutex);
761 if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
762 return g_unmanagedCallbacks[iPtr].configCB(config);
763 }
764 return 0;
765 }
766
767 int CecAlertCB(void *cbParam, const CEC::libcec_alert alert, const CEC::libcec_parameter &data)
768 {
769 if (cbParam)
770 {
771 size_t iPtr = (size_t)cbParam;
772 PLATFORM::CLockObject lock(g_callbackMutex);
773 if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
774 return g_unmanagedCallbacks[iPtr].alertCB(alert, data);
775 }
776 return 0;
777 }
778
779 int CecMenuCB(void *cbParam, const CEC::cec_menu_state newVal)
780 {
781 if (cbParam)
782 {
783 size_t iPtr = (size_t)cbParam;
784 PLATFORM::CLockObject lock(g_callbackMutex);
785 if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
786 return g_unmanagedCallbacks[iPtr].menuCB(newVal);
787 }
788 return 0;
789 }
790
791 void CecSourceActivatedCB(void *cbParam, const CEC::cec_logical_address logicalAddress, const uint8_t bActivated)
792 {
793 if (cbParam)
794 {
795 size_t iPtr = (size_t)cbParam;
796 PLATFORM::CLockObject lock(g_callbackMutex);
797 if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
798 g_unmanagedCallbacks[iPtr].sourceActivatedCB(logicalAddress, bActivated);
799 }
800 }
801
802 #pragma managed
803 // delegates for the unmanaged callback methods
804 public delegate int CecLogMessageManagedDelegate(const CEC::cec_log_message &);
805 public delegate int CecKeyPressManagedDelegate(const CEC::cec_keypress &);
806 public delegate int CecCommandManagedDelegate(const CEC::cec_command &);
807 public delegate int CecConfigManagedDelegate(const CEC::libcec_configuration &);
808 public delegate int CecAlertManagedDelegate(const CEC::libcec_alert, const CEC::libcec_parameter &);
809 public delegate int CecMenuManagedDelegate(const CEC::cec_menu_state newVal);
810 public delegate void CecSourceActivatedManagedDelegate(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated);
811
812 void AssignCallbacks()
813 {
814 g_cecCallbacks.CBCecLogMessage = CecLogMessageCB;
815 g_cecCallbacks.CBCecKeyPress = CecKeyPressCB;
816 g_cecCallbacks.CBCecCommand = CecCommandCB;
817 g_cecCallbacks.CBCecConfigurationChanged = CecConfigCB;
818 g_cecCallbacks.CBCecAlert = CecAlertCB;
819 g_cecCallbacks.CBCecMenuStateChanged = CecMenuCB;
820 g_cecCallbacks.CBCecSourceActivated = CecSourceActivatedCB;
821 }
822
823 // callback method interface
824 public ref class CecCallbackMethods
825 {
826 public:
827 CecCallbackMethods(void)
828 {
829 m_iCallbackPtr = -1;
830 AssignCallbacks();
831 m_bHasCallbacks = false;
832 m_bDelegatesCreated = false;
833 }
834
835 ~CecCallbackMethods(void)
836 {
837 DestroyDelegates();
838 }
839
840 size_t GetCallbackPtr(void)
841 {
842 PLATFORM::CLockObject lock(g_callbackMutex);
843 return m_iCallbackPtr;
844 }
845
846 protected:
847 !CecCallbackMethods(void)
848 {
849 DestroyDelegates();
850 }
851
852 public:
853 virtual void DisableCallbacks(void)
854 {
855 DestroyDelegates();
856 }
857
858 virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks)
859 {
860 CreateDelegates();
861 if (!m_bHasCallbacks)
862 {
863 m_bHasCallbacks = true;
864 m_callbacks = callbacks;
865 return true;
866 }
867
868 return false;
869 }
870
871 virtual int ReceiveLogMessage(CecLogMessage ^ message)
872 {
873 return 0;
874 }
875
876 virtual int ReceiveKeypress(CecKeypress ^ key)
877 {
878 return 0;
879 }
880
881 virtual int ReceiveCommand(CecCommand ^ command)
882 {
883 return 0;
884 }
885
886 virtual int ConfigurationChanged(LibCECConfiguration ^ config)
887 {
888 return 0;
889 }
890
891 virtual int ReceiveAlert(CecAlert alert, CecParameter ^ data)
892 {
893 return 0;
894 }
895
896 virtual int ReceiveMenuStateChange(CecMenuState newVal)
897 {
898 return 0;
899 }
900
901 virtual void SourceActivated(CecLogicalAddress logicalAddress, bool bActivated)
902 {
903 }
904
905 protected:
906 // managed callback methods
907 int CecLogMessageManaged(const CEC::cec_log_message &message)
908 {
909 int iReturn(0);
910 if (m_bHasCallbacks)
911 iReturn = m_callbacks->ReceiveLogMessage(gcnew CecLogMessage(gcnew System::String(message.message), (CecLogLevel)message.level, message.time));
912 return iReturn;
913 }
914
915 int CecKeyPressManaged(const CEC::cec_keypress &key)
916 {
917 int iReturn(0);
918 if (m_bHasCallbacks)
919 iReturn = m_callbacks->ReceiveKeypress(gcnew CecKeypress((CecUserControlCode)key.keycode, key.duration));
920 return iReturn;
921 }
922
923 int CecCommandManaged(const CEC::cec_command &command)
924 {
925 int iReturn(0);
926 if (m_bHasCallbacks)
927 {
928 CecCommand ^ newCommand = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, (CecOpcode)command.opcode, command.transmit_timeout);
929 for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
930 newCommand->Parameters->PushBack(command.parameters[iPtr]);
931 iReturn = m_callbacks->ReceiveCommand(newCommand);
932 }
933 return iReturn;
934 }
935
936 int CecConfigManaged(const CEC::libcec_configuration &config)
937 {
938 int iReturn(0);
939 if (m_bHasCallbacks)
940 {
941 LibCECConfiguration ^netConfig = gcnew LibCECConfiguration();
942 netConfig->Update(config);
943 iReturn = m_callbacks->ConfigurationChanged(netConfig);
944 }
945 return iReturn;
946 }
947
948 int CecAlertManaged(const CEC::libcec_alert alert, const CEC::libcec_parameter &data)
949 {
950 int iReturn(0);
951 if (m_bHasCallbacks)
952 {
953 CecParameterType newType = (CecParameterType)data.paramType;
954 if (newType == CecParameterType::ParameterTypeString)
955 {
956 System::String ^ newData = gcnew System::String((const char *)data.paramData, 0, 128);
957 CecParameter ^ newParam = gcnew CecParameter(newType, newData);
958 iReturn = m_callbacks->ReceiveAlert((CecAlert)alert, newParam);
959 }
960 }
961 return iReturn;
962 }
963
964 int CecMenuManaged(const CEC::cec_menu_state newVal)
965 {
966 int iReturn(0);
967 if (m_bHasCallbacks)
968 {
969 iReturn = m_callbacks->ReceiveMenuStateChange((CecMenuState)newVal);
970 }
971 return iReturn;
972 }
973
974 void CecSourceActivatedManaged(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated)
975 {
976 if (m_bHasCallbacks)
977 m_callbacks->SourceActivated((CecLogicalAddress)logicalAddress, bActivated == 1);
978 }
979
980 void DestroyDelegates()
981 {
982 m_bHasCallbacks = false;
983 if (m_bDelegatesCreated)
984 {
985 m_bDelegatesCreated = false;
986 m_logMessageGCHandle.Free();
987 m_keypressGCHandle.Free();
988 m_commandGCHandle.Free();
989 m_alertGCHandle.Free();
990 m_menuGCHandle.Free();
991 m_sourceActivatedGCHandle.Free();
992 }
993 }
994
995 void CreateDelegates()
996 {
997 DestroyDelegates();
998
999 if (!m_bDelegatesCreated)
1000 {
1001 msclr::interop::marshal_context ^ context = gcnew msclr::interop::marshal_context();
1002
1003 // create the delegate method for the log message callback
1004 m_logMessageDelegate = gcnew CecLogMessageManagedDelegate(this, &CecCallbackMethods::CecLogMessageManaged);
1005 m_logMessageGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_logMessageDelegate);
1006 m_logMessageCallback = static_cast<LOGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer());
1007
1008 // create the delegate method for the keypress callback
1009 m_keypressDelegate = gcnew CecKeyPressManagedDelegate(this, &CecCallbackMethods::CecKeyPressManaged);
1010 m_keypressGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_keypressDelegate);
1011 m_keypressCallback = static_cast<KEYCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer());
1012
1013 // create the delegate method for the command callback
1014 m_commandDelegate = gcnew CecCommandManagedDelegate(this, &CecCallbackMethods::CecCommandManaged);
1015 m_commandGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_commandDelegate);
1016 m_commandCallback = static_cast<COMMANDCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer());
1017
1018 // create the delegate method for the configuration change callback
1019 m_configDelegate = gcnew CecConfigManagedDelegate(this, &CecCallbackMethods::CecConfigManaged);
1020 m_configGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_configDelegate);
1021 m_configCallback = static_cast<CONFIGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer());
1022
1023 // create the delegate method for the alert callback
1024 m_alertDelegate = gcnew CecAlertManagedDelegate(this, &CecCallbackMethods::CecAlertManaged);
1025 m_alertGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_alertDelegate);
1026 m_alertCallback = static_cast<ALERTCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_alertDelegate).ToPointer());
1027
1028 // create the delegate method for the menu callback
1029 m_menuDelegate = gcnew CecMenuManagedDelegate(this, &CecCallbackMethods::CecMenuManaged);
1030 m_menuGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_menuDelegate);
1031 m_menuCallback = static_cast<MENUCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_menuDelegate).ToPointer());
1032
1033 // create the delegate method for the source activated callback
1034 m_sourceActivatedDelegate = gcnew CecSourceActivatedManagedDelegate(this, &CecCallbackMethods::CecSourceActivatedManaged);
1035 m_sourceActivatedGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_sourceActivatedDelegate);
1036 m_sourceActivatedCallback = static_cast<ACTICB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_sourceActivatedDelegate).ToPointer());
1037
1038 delete context;
1039
1040 UnmanagedCecCallbacks unmanagedCallbacks;
1041 unmanagedCallbacks.logCB = m_logMessageCallback;
1042 unmanagedCallbacks.keyCB = m_keypressCallback;
1043 unmanagedCallbacks.commandCB = m_commandCallback;
1044 unmanagedCallbacks.configCB = m_configCallback;
1045 unmanagedCallbacks.alertCB = m_alertCallback;
1046 unmanagedCallbacks.menuCB = m_menuCallback;
1047 unmanagedCallbacks.sourceActivatedCB = m_sourceActivatedCallback;
1048
1049 PLATFORM::CLockObject lock(g_callbackMutex);
1050 g_unmanagedCallbacks.push_back(unmanagedCallbacks);
1051 m_iCallbackPtr = g_unmanagedCallbacks.size() - 1;
1052 m_bDelegatesCreated = true;
1053 }
1054 }
1055
1056 CecLogMessageManagedDelegate ^ m_logMessageDelegate;
1057 static System::Runtime::InteropServices::GCHandle m_logMessageGCHandle;
1058 LOGCB m_logMessageCallback;
1059
1060 CecKeyPressManagedDelegate ^ m_keypressDelegate;
1061 static System::Runtime::InteropServices::GCHandle m_keypressGCHandle;
1062 KEYCB m_keypressCallback;
1063
1064 CecCommandManagedDelegate ^ m_commandDelegate;
1065 static System::Runtime::InteropServices::GCHandle m_commandGCHandle;
1066 COMMANDCB m_commandCallback;
1067
1068 CecConfigManagedDelegate ^ m_configDelegate;
1069 static System::Runtime::InteropServices::GCHandle m_configGCHandle;
1070 CONFIGCB m_configCallback;
1071
1072 CecAlertManagedDelegate ^ m_alertDelegate;
1073 static System::Runtime::InteropServices::GCHandle m_alertGCHandle;
1074 ALERTCB m_alertCallback;
1075
1076 CecMenuManagedDelegate ^ m_menuDelegate;
1077 static System::Runtime::InteropServices::GCHandle m_menuGCHandle;
1078 MENUCB m_menuCallback;
1079
1080 CecSourceActivatedManagedDelegate ^ m_sourceActivatedDelegate;
1081 static System::Runtime::InteropServices::GCHandle m_sourceActivatedGCHandle;
1082 ACTICB m_sourceActivatedCallback;
1083
1084 CecCallbackMethods ^ m_callbacks;
1085 bool m_bHasCallbacks;
1086 bool m_bDelegatesCreated;
1087 size_t m_iCallbackPtr;
1088 };
1089 }