Commit | Line | Data |
---|---|---|
61f3c2ad LOK |
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 | { | |
0e197148 LOK |
414 | CecCommand ^ retVal = gcnew CecCommand((CecLogicalAddress)command.initiator, (CecLogicalAddress)command.destination, command.ack == 1 ? true : false, command.eom == 1 ? true : false, command.opcode, command.transmit_timeout); |
415 | for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++) | |
416 | retVal->Parameters->PushBack(command.parameters[iPtr]); | |
417 | return retVal; | |
61f3c2ad LOK |
418 | } |
419 | ||
420 | return gcnew CecCommand(); | |
421 | } | |
422 | ||
423 | bool Transmit(CecCommand ^ command) | |
424 | { | |
425 | cec_command ccommand; | |
ab1469a0 | 426 | cec_command::Format(ccommand, (cec_logical_address)command->Initiator, (cec_logical_address)command->Destination, (cec_opcode)command->Opcode); |
61f3c2ad LOK |
427 | ccommand.transmit_timeout = command->TransmitTimeout; |
428 | ccommand.eom = command->Eom; | |
429 | ccommand.ack = command->Ack; | |
430 | for (unsigned int iPtr = 0; iPtr < command->Parameters->Size; iPtr++) | |
ab1469a0 | 431 | ccommand.parameters.PushBack(command->Parameters->Data[iPtr]); |
61f3c2ad LOK |
432 | |
433 | return m_libCec->Transmit(ccommand); | |
434 | } | |
435 | ||
436 | bool SetLogicalAddress(CecLogicalAddress logicalAddress) | |
437 | { | |
438 | return m_libCec->SetLogicalAddress((cec_logical_address) logicalAddress); | |
439 | } | |
440 | ||
441 | bool SetPhysicalAddress(int16_t physicalAddress) | |
442 | { | |
443 | return m_libCec->SetPhysicalAddress(physicalAddress); | |
444 | } | |
445 | ||
446 | bool PowerOnDevices(CecLogicalAddress logicalAddress) | |
447 | { | |
448 | return m_libCec->PowerOnDevices((cec_logical_address) logicalAddress); | |
449 | } | |
450 | ||
451 | bool StandbyDevices(CecLogicalAddress logicalAddress) | |
452 | { | |
453 | return m_libCec->StandbyDevices((cec_logical_address) logicalAddress); | |
454 | } | |
455 | ||
456 | bool PollDevice(CecLogicalAddress logicalAddress) | |
457 | { | |
458 | return m_libCec->PollDevice((cec_logical_address) logicalAddress); | |
459 | } | |
460 | ||
461 | bool SetActiveSource(CecDeviceType type) | |
462 | { | |
463 | return m_libCec->SetActiveSource((cec_device_type) type); | |
464 | } | |
465 | ||
466 | bool SetDeckControlMode(CecDeckControlMode mode, bool sendUpdate) | |
467 | { | |
468 | return m_libCec->SetDeckControlMode((cec_deck_control_mode) mode, sendUpdate); | |
469 | } | |
470 | ||
471 | bool SetDeckInfo(CecDeckInfo info, bool sendUpdate) | |
472 | { | |
473 | return m_libCec->SetDeckInfo((cec_deck_info) info, sendUpdate); | |
474 | } | |
475 | ||
476 | bool SetInactiveView(void) | |
477 | { | |
478 | return m_libCec->SetInactiveView(); | |
479 | } | |
480 | ||
481 | bool SetMenuState(CecMenuState state, bool sendUpdate) | |
482 | { | |
483 | return m_libCec->SetMenuState((cec_menu_state) state, sendUpdate); | |
484 | } | |
485 | ||
486 | bool SetOSDString(CecLogicalAddress logicalAddress, CecDisplayControl duration, String ^ message) | |
487 | { | |
488 | marshal_context ^ context = gcnew marshal_context(); | |
489 | const char* strMessageC = context->marshal_as<const char*>(message); | |
490 | ||
491 | bool bReturn = m_libCec->SetOSDString((cec_logical_address) logicalAddress, (cec_display_control) duration, strMessageC); | |
492 | ||
493 | delete context; | |
494 | return bReturn; | |
495 | } | |
496 | ||
497 | bool SwitchMonitoring(bool enable) | |
498 | { | |
499 | return m_libCec->SwitchMonitoring(enable); | |
500 | } | |
501 | ||
502 | CecVersion GetDeviceCecVersion(CecLogicalAddress logicalAddress) | |
503 | { | |
504 | return (CecVersion) m_libCec->GetDeviceCecVersion((cec_logical_address) logicalAddress); | |
505 | } | |
506 | ||
507 | String ^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress) | |
508 | { | |
509 | cec_menu_language lang; | |
510 | if (m_libCec->GetDeviceMenuLanguage((cec_logical_address) logicalAddress, &lang)) | |
511 | { | |
512 | return gcnew String(lang.language); | |
513 | } | |
514 | ||
515 | return gcnew String(""); | |
516 | } | |
517 | ||
518 | uint64_t GetDeviceVendorId(CecLogicalAddress logicalAddress) | |
519 | { | |
520 | return m_libCec->GetDeviceVendorId((cec_logical_address) logicalAddress); | |
521 | } | |
522 | ||
523 | CecPowerStatus GetDevicePowerStatus(CecLogicalAddress logicalAddress) | |
524 | { | |
525 | return (CecPowerStatus) m_libCec->GetDevicePowerStatus((cec_logical_address) logicalAddress); | |
526 | } | |
527 | ||
528 | private: | |
529 | ICECAdapter * m_libCec; | |
530 | }; |