cec: added a C++ CLR wrapper for libCEC, so libCEC can be used by any .NET language...
[deb_libcec.git] / src / LibCecSharp / LibCecSharp.cpp
1 /*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011 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 "stdafx.h"
34 #include <windows.h>
35 #include <vcclr.h>
36 #include <msclr/marshal.h>
37 #include <cec.h>
38 #using <System.dll>
39
40 using namespace System;
41 using namespace CEC;
42 using namespace msclr::interop;
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 CecPowerStatus
88 {
89 On = 0x00,
90 Standby = 0x01,
91 InTransitionStandbyToOn = 0x02,
92 InTransitionOnToStandby = 0x03,
93 Unknown = 0x99
94 };
95
96 public enum class CecVersion
97 {
98 Unknown = 0x00,
99 V1_2 = 0x01,
100 V1_2A = 0x02,
101 V1_3 = 0x03,
102 V1_3A = 0x04,
103 V1_4 = 0x05
104 };
105
106 public enum class CecDisplayControl
107 {
108 DisplayForDefaultTime = 0x00,
109 DisplayUntilCleared = 0x40,
110 ClearPreviousMessage = 0x80,
111 ReservedForFutureUse = 0xC0
112 };
113
114 public enum class CecMenuState
115 {
116 Activated = 0,
117 Deactivated = 1
118 };
119
120 public enum class CecDeckControlMode
121 {
122 SkipForwardWind = 1,
123 SkipReverseRewind = 2,
124 Stop = 3,
125 Eject = 4
126 };
127
128 public enum class CecDeckInfo
129 {
130 Play = 0x11,
131 Record = 0x12,
132 Reverse = 0x13,
133 Still = 0x14,
134 Slow = 0x15,
135 SlowReverse = 0x16,
136 FastForward = 0x17,
137 FastReverse = 0x18,
138 NoMedia = 0x19,
139 Stop = 0x1A,
140 SkipForwardWind = 0x1B,
141 SkipReverseRewind = 0x1C,
142 IndexSearchForward = 0x1D,
143 IndexSearchReverse = 0x1E,
144 OtherStatus = 0x1F
145 };
146
147 public ref class CecAdapter
148 {
149 public:
150 CecAdapter(String ^ strPath, String ^ strComPort)
151 {
152 Path = strPath;
153 ComPort = strComPort;
154 }
155
156 property String ^ Path;
157 property String ^ ComPort;
158 };
159
160 public ref class CecDeviceTypeList
161 {
162 public:
163 CecDeviceTypeList(void)
164 {
165 Types = gcnew array<CecDeviceType>(5);
166 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
167 Types[iPtr] = CecDeviceType::Reserved;
168 }
169
170 property array<CecDeviceType> ^ Types;
171 };
172
173 public ref class CecDatapacket
174 {
175 public:
176 CecDatapacket(void)
177 {
178 Data = gcnew array<uint8_t>(100);
179 Size = 0;
180 }
181
182 void PushBack(uint8_t data)
183 {
184 if (Size < 100)
185 {
186 Data[Size] = data;
187 Size++;
188 }
189 }
190
191 property array<uint8_t> ^ Data;
192 property uint8_t Size;
193 };
194
195 public ref class CecCommand
196 {
197 public:
198 CecCommand(CecLogicalAddress iInitiator, CecLogicalAddress iDestination, bool bAck, bool bEom, int8_t iOpcode, int32_t iTransmitTimeout)
199 {
200 Initiator = iInitiator;
201 Destination = iDestination;
202 Ack = bAck;
203 Eom = bEom;
204 Opcode = iOpcode;
205 OpcodeSet = true;
206 TransmitTimeout = iTransmitTimeout;
207 Parameters = gcnew CecDatapacket;
208 Empty = false;
209 }
210
211 CecCommand(void)
212 {
213 Initiator = CecLogicalAddress::Unknown;
214 Destination = CecLogicalAddress::Unknown;
215 Ack = false;
216 Eom = false;
217 Opcode = 0;
218 OpcodeSet = false;
219 TransmitTimeout = 0;
220 Parameters = gcnew CecDatapacket;
221 Empty = true;
222 }
223
224 void PushBack(uint8_t data)
225 {
226 if (Initiator == CecLogicalAddress::Unknown && Destination == CecLogicalAddress::Unknown)
227 {
228 Initiator = (CecLogicalAddress) (data >> 4);
229 Destination = (CecLogicalAddress) (data & 0xF);
230 }
231 else if (!OpcodeSet)
232 {
233 OpcodeSet = true;
234 Opcode = data;
235 }
236 else
237 {
238 Parameters->PushBack(data);
239 }
240 }
241
242 property bool Empty;
243 property CecLogicalAddress Initiator;
244 property CecLogicalAddress Destination;
245 property bool Ack;
246 property bool Eom;
247 property int8_t Opcode;
248 property CecDatapacket ^ Parameters;
249 property bool OpcodeSet;
250 property int32_t TransmitTimeout;
251 };
252
253 public ref class CecKeypress
254 {
255 public:
256 CecKeypress(int iKeycode, unsigned int iDuration)
257 {
258 Keycode = iKeycode;
259 Duration = iDuration;
260 Empty = false;
261 }
262
263 CecKeypress(void)
264 {
265 Keycode = 0;
266 Duration = 0;
267 Empty = true;
268 }
269
270 property bool Empty;
271 property int Keycode;
272 property unsigned int Duration;
273 };
274
275 public ref class CecLogMessage
276 {
277 public:
278 CecLogMessage(String ^ strMessage, CecLogLevel iLevel, int64_t iTime)
279 {
280 Message = strMessage;
281 Level = iLevel;
282 Time = iTime;
283 Empty = false;
284 }
285
286 CecLogMessage(void)
287 {
288 Message = "";
289 Level = CecLogLevel::None;
290 Time = 0;
291 Empty = true;
292 }
293
294 property bool Empty;
295 property String ^ Message;
296 property CecLogLevel Level;
297 property int64_t Time;
298 };
299
300 public ref class LibCecSharp
301 {
302 public:
303 LibCecSharp(String ^ strDeviceName, CecDeviceTypeList ^ deviceTypes)
304 {
305 marshal_context ^ context = gcnew marshal_context();
306
307 const char* strDeviceNameC = context->marshal_as<const char*>(strDeviceName);
308
309 cec_device_type_list types;
310 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
311 types.types[iPtr] = (cec_device_type)deviceTypes->Types[iPtr];
312 m_libCec = (ICECAdapter *) CECInit(strDeviceNameC, types);
313 delete context;
314 }
315
316 ~LibCecSharp(void)
317 {
318 CECDestroy(m_libCec);
319 m_libCec = NULL;
320 }
321
322 protected:
323 !LibCecSharp(void)
324 {
325 CECDestroy(m_libCec);
326 m_libCec = NULL;
327 }
328
329 public:
330 array<CecAdapter ^> ^ FindAdapters(String ^ path)
331 {
332 cec_adapter *devices = new cec_adapter[10];
333
334 marshal_context ^ context = gcnew marshal_context();
335 const char* strPathC = path->Length > 0 ? context->marshal_as<const char*>(path) : NULL;
336
337 uint8_t iDevicesFound = m_libCec->FindAdapters(devices, 10, NULL);
338
339 array<CecAdapter ^> ^ adapters = gcnew array<CecAdapter ^>(iDevicesFound);
340 for (unsigned int iPtr = 0; iPtr < iDevicesFound; iPtr++)
341 adapters[iPtr] = gcnew CecAdapter(gcnew String(devices[iPtr].path), gcnew String(devices[iPtr].comm));
342
343 delete devices;
344 delete context;
345 return adapters;
346 }
347
348 bool Open(String ^ strPort, int iTimeoutMs)
349 {
350 marshal_context ^ context = gcnew marshal_context();
351 const char* strPortC = context->marshal_as<const char*>(strPort);
352 bool bReturn = m_libCec->Open(strPortC, iTimeoutMs);
353 delete context;
354 return bReturn;
355 }
356
357 void Close(void)
358 {
359 m_libCec->Close();
360 }
361
362 bool PingAdapter(void)
363 {
364 return m_libCec->PingAdapter();
365 }
366
367 bool StartBootloader(void)
368 {
369 return m_libCec->StartBootloader();
370 }
371
372 int GetMinLibVersion(void)
373 {
374 return m_libCec->GetMinLibVersion();
375 }
376
377 int GetLibVersionMajor(void)
378 {
379 return m_libCec->GetLibVersionMajor();
380 }
381
382 int GetLibVersionMinor(void)
383 {
384 return m_libCec->GetLibVersionMinor();
385 }
386
387 CecLogMessage ^ GetNextLogMessage(void)
388 {
389 cec_log_message msg;
390 if (m_libCec->GetNextLogMessage(&msg))
391 {
392 return gcnew CecLogMessage(gcnew String(msg.message), (CecLogLevel)msg.level, msg.time);
393 }
394
395 return gcnew CecLogMessage();
396 }
397
398 CecKeypress ^ GetNextKeypress(void)
399 {
400 cec_keypress key;
401 if (m_libCec->GetNextKeypress(&key))
402 {
403 return gcnew CecKeypress(key.keycode, key.duration);
404 }
405
406 return gcnew CecKeypress();
407 }
408
409 CecCommand ^ GetNextCommand(void)
410 {
411 cec_command command;
412 if (m_libCec->GetNextCommand(&command))
413 {
414 // TODO parameters
415 return gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, command.opcode, command.transmit_timeout);
416 }
417
418 return gcnew CecCommand();
419 }
420
421 bool Transmit(CecCommand ^ command)
422 {
423 cec_command ccommand;
424 cec_command::format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode);
425 ccommand.transmit_timeout = command->TransmitTimeout;
426 ccommand.eom = command->Eom;
427 ccommand.ack = command->Ack;
428 for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++)
429 ccommand.parameters.push_back(command->Parameters->Data[iPtr]);
430
431 return m_libCec->Transmit(ccommand);
432 }
433
434 bool SetLogicalAddress(CecLogicalAddress logicalAddress)
435 {
436 return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress);
437 }
438
439 bool SetPhysicalAddress(int16_t physicalAddress)
440 {
441 return m_libCec->SetPhysicalAddress(physicalAddress);
442 }
443
444 bool PowerOnDevices(CecLogicalAddress logicalAddress)
445 {
446 return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress);
447 }
448
449 bool StandbyDevices(CecLogicalAddress logicalAddress)
450 {
451 return m_libCec->StandbyDevices((cec_logical_address) logicalAddress);
452 }
453
454 bool PollDevice(CecLogicalAddress logicalAddress)
455 {
456 return m_libCec->PollDevice((cec_logical_address) logicalAddress);
457 }
458
459 bool SetActiveSource(CecDeviceType type)
460 {
461 return m_libCec->SetActiveSource((cec_device_type) type);
462 }
463
464 bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate)
465 {
466 return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate);
467 }
468
469 bool SetDeckInfo(CecDeckInfo info, bool sendUpdate)
470 {
471 return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate);
472 }
473
474 bool SetInactiveView(void)
475 {
476 return m_libCec->SetInactiveView();
477 }
478
479 bool SetMenuState(CecMenuState state, bool sendUpdate)
480 {
481 return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate);
482 }
483
484 bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message)
485 {
486 marshal_context ^ context = gcnew marshal_context();
487 const char* strMessageC = context->marshal_as<const char*>(message);
488
489 bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC);
490
491 delete context;
492 return bReturn;
493 }
494
495 bool SwitchMonitoring(bool enable)
496 {
497 return m_libCec->SwitchMonitoring(enable);
498 }
499
500 CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress)
501 {
502 return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress);
503 }
504
505 String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress)
506 {
507 cec_menu_language lang;
508 if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang))
509 {
510 return gcnew String(lang.language);
511 }
512
513 return gcnew String("");
514 }
515
516 uint64_t GetDeviceVendorId(CecLogicalAddress logicalAddress)
517 {
518 return m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress);
519 }
520
521 CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress)
522 {
523 return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress);
524 }
525
526 private:
527 ICECAdapter * m_libCec;
528 };