cec: set line timeout when (re)transmitting. don't sleep after transmitting
[deb_libcec.git] / src / lib / CECProcessor.cpp
CommitLineData
abbca718
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
2abe74eb 33#include "CECProcessor.h"
abbca718 34
2abe74eb 35#include "AdapterCommunication.h"
eafa9d46 36#include "devices/CECBusDevice.h"
51b2a094
LOK
37#include "devices/CECAudioSystem.h"
38#include "devices/CECPlaybackDevice.h"
39#include "devices/CECRecordingDevice.h"
40#include "devices/CECTuner.h"
41#include "devices/CECTV.h"
62f5527d 42#include "implementations/CECCommandHandler.h"
2abe74eb 43#include "LibCEC.h"
abbca718 44#include "util/StdString.h"
b9187cc6 45#include "platform/timeutils.h"
abbca718
LOK
46
47using namespace CEC;
48using namespace std;
49
1113cb7d 50CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
f8513317 51 m_bStarted(false),
16b1e052 52 m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
d2f1c157 53 m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
855a3a98 54 m_lastInitiator(CECDEVICE_UNKNOWN),
2abe74eb 55 m_strDeviceName(strDeviceName),
8b7e5ff6 56 m_controller(controller),
7c63a480 57 m_bMonitor(false),
9902f4e8
LOK
58 m_busScan(NULL),
59 m_iLineTimeout(0)
abbca718 60{
1113cb7d 61 m_communication = new CAdapterCommunication(this);
ab1469a0
LOK
62 m_logicalAddresses.Clear();
63 m_logicalAddresses.Set(iLogicalAddress);
20b8870a 64 m_types.clear();
7871d66e 65 for (int iPtr = 0; iPtr <= 16; iPtr++)
09c10b66 66 m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, iPtr == iLogicalAddress ? iPhysicalAddress : 0);
abbca718
LOK
67}
68
1113cb7d 69CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types) :
f8513317 70 m_bStarted(false),
16b1e052 71 m_iHDMIPort(CEC_DEFAULT_HDMI_PORT),
d2f1c157 72 m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE),
f8513317
LOK
73 m_strDeviceName(strDeviceName),
74 m_types(types),
f8513317 75 m_controller(controller),
9902f4e8
LOK
76 m_bMonitor(false),
77 m_iLineTimeout(0)
f8513317 78{
1113cb7d 79 m_communication = new CAdapterCommunication(this);
ab1469a0 80 m_logicalAddresses.Clear();
f8513317 81 for (int iPtr = 0; iPtr < 16; iPtr++)
51b2a094
LOK
82 {
83 switch(iPtr)
84 {
85 case CECDEVICE_AUDIOSYSTEM:
5d5a2dc2 86 m_busDevices[iPtr] = new CCECAudioSystem(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
87 break;
88 case CECDEVICE_PLAYBACKDEVICE1:
89 case CECDEVICE_PLAYBACKDEVICE2:
90 case CECDEVICE_PLAYBACKDEVICE3:
5d5a2dc2 91 m_busDevices[iPtr] = new CCECPlaybackDevice(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
92 break;
93 case CECDEVICE_RECORDINGDEVICE1:
94 case CECDEVICE_RECORDINGDEVICE2:
95 case CECDEVICE_RECORDINGDEVICE3:
5d5a2dc2 96 m_busDevices[iPtr] = new CCECRecordingDevice(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
97 break;
98 case CECDEVICE_TUNER1:
99 case CECDEVICE_TUNER2:
100 case CECDEVICE_TUNER3:
101 case CECDEVICE_TUNER4:
5d5a2dc2 102 m_busDevices[iPtr] = new CCECTuner(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
103 break;
104 case CECDEVICE_TV:
105 m_busDevices[iPtr] = new CCECTV(this, (cec_logical_address) iPtr, 0);
106 break;
107 default:
5d5a2dc2 108 m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr, 0xFFFF);
51b2a094
LOK
109 break;
110 }
111 }
f8513317
LOK
112}
113
2abe74eb 114CCECProcessor::~CCECProcessor(void)
abbca718 115{
7c63a480
LOK
116 if (m_busScan)
117 {
118 m_busScan->StopThread();
119 delete m_busScan;
120 }
121
8b0ee2cc 122 m_startCondition.Broadcast();
2abe74eb 123 StopThread();
7c63a480 124
1113cb7d 125 delete m_communication;
2abe74eb
LOK
126 m_communication = NULL;
127 m_controller = NULL;
d1998c7b
LOK
128 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
129 delete m_busDevices[iPtr];
abbca718
LOK
130}
131
1113cb7d 132bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */)
abbca718 133{
8b0ee2cc 134 CLockObject lock(&m_mutex);
1113cb7d 135 if (!m_communication || m_communication->IsOpen())
13fd6a66 136 {
1113cb7d
LOK
137 m_controller->AddLog(CEC_LOG_ERROR, "connection already opened");
138 return false;
139 }
140
141 if (!m_communication->Open(strPort, iBaudRate, iTimeoutMs))
142 {
143 m_controller->AddLog(CEC_LOG_ERROR, "could not open a connection");
a8f0bd18 144 return false;
13fd6a66 145 }
abbca718 146
60fa4578 147 if (CreateThread())
8b0ee2cc 148 {
f8513317 149 if (!m_startCondition.Wait(&m_mutex) || !m_bStarted)
8b0ee2cc
LOK
150 {
151 m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
152 return false;
153 }
9fd73dd4
LOK
154
155 lock.Leave();
156 if (SetAckMask(m_logicalAddresses.AckMask()) &&
d2f1c157 157 SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true))
9fd73dd4 158 {
7c63a480
LOK
159 m_busScan = new CCECBusScan(this);
160 m_busScan->CreateThread(true);
9fd73dd4
LOK
161 return true;
162 }
8b0ee2cc 163 }
a8f0bd18 164 else
2abe74eb 165 m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
abbca718 166
a8f0bd18 167 return false;
abbca718
LOK
168}
169
b58d9277 170bool CCECProcessor::TryLogicalAddress(cec_logical_address address)
f8513317 171{
93fff5c1 172 if (m_busDevices[address]->TryLogicalAddress())
f8513317 173 {
8747dd4f 174 /* only set our OSD name and active source for the primary device */
ab1469a0 175 if (m_logicalAddresses.IsEmpty())
8747dd4f 176 {
787a3cb8 177 m_busDevices[address]->m_strDeviceName = m_strDeviceName;
8747dd4f
LOK
178 m_busDevices[address]->m_bActiveSource = true;
179 }
ab1469a0 180 m_logicalAddresses.Set(address);
f8513317
LOK
181 return true;
182 }
183
f8513317
LOK
184 return false;
185}
186
b58d9277 187bool CCECProcessor::FindLogicalAddressRecordingDevice(void)
f8513317
LOK
188{
189 AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
b58d9277
LOK
190 return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1) ||
191 TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2) ||
192 TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3);
f8513317
LOK
193}
194
b58d9277 195bool CCECProcessor::FindLogicalAddressTuner(void)
f8513317
LOK
196{
197 AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
b58d9277
LOK
198 return TryLogicalAddress(CECDEVICE_TUNER1) ||
199 TryLogicalAddress(CECDEVICE_TUNER2) ||
200 TryLogicalAddress(CECDEVICE_TUNER3) ||
201 TryLogicalAddress(CECDEVICE_TUNER4);
f8513317
LOK
202}
203
b58d9277 204bool CCECProcessor::FindLogicalAddressPlaybackDevice(void)
f8513317
LOK
205{
206 AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
b58d9277
LOK
207 return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1) ||
208 TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2) ||
209 TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3);
f8513317
LOK
210}
211
b58d9277 212bool CCECProcessor::FindLogicalAddressAudioSystem(void)
f8513317
LOK
213{
214 AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audio'");
b58d9277 215 return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM);
f8513317
LOK
216}
217
218bool CCECProcessor::FindLogicalAddresses(void)
219{
220 bool bReturn(true);
ab1469a0 221 m_logicalAddresses.Clear();
f8513317
LOK
222 CStdString strLog;
223
224 for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
225 {
226 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
227 continue;
228
229 strLog.Format("%s - device %d: type %d", __FUNCTION__, iPtr, m_types.types[iPtr]);
230 AddLog(CEC_LOG_DEBUG, strLog);
231
232 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
b58d9277 233 bReturn &= FindLogicalAddressRecordingDevice();
f8513317 234 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
b58d9277 235 bReturn &= FindLogicalAddressTuner();
f8513317 236 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
b58d9277 237 bReturn &= FindLogicalAddressPlaybackDevice();
f8513317 238 if (m_types.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
b58d9277 239 bReturn &= FindLogicalAddressAudioSystem();
f8513317
LOK
240 }
241
242 return bReturn;
243}
244
855a3a98
LOK
245bool CCECProcessor::SetLineTimeout(uint8_t iTimeout)
246{
9902f4e8 247 bool bReturn(m_iLineTimeout != iTimeout);
855a3a98 248
9902f4e8
LOK
249 if (!bReturn)
250 {
251 CCECAdapterMessage *output = new CCECAdapterMessage;
252
253 output->push_back(MSGSTART);
254 output->push_escaped(MSGCODE_TRANSMIT_IDLETIME);
255 output->push_escaped(iTimeout);
256 output->push_back(MSGEND);
257
258 if ((bReturn = Transmit(output)) == false)
259 m_controller->AddLog(CEC_LOG_ERROR, "could not set the idletime");
260 delete output;
261 }
855a3a98 262
855a3a98
LOK
263 return bReturn;
264}
265
2abe74eb 266void *CCECProcessor::Process(void)
f99bc831 267{
8747dd4f 268 bool bParseFrame(false);
e0407d3d
LOK
269 cec_command command;
270 CCECAdapterMessage msg;
271
9fd73dd4 272 if (m_logicalAddresses.IsEmpty() && !FindLogicalAddresses())
8b0ee2cc 273 {
9fd73dd4
LOK
274 CLockObject lock(&m_mutex);
275 m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
276 m_startCondition.Signal();
277 return NULL;
278 }
279 else
280 {
281 CLockObject lock(&m_mutex);
282 m_bStarted = true;
283 m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
284 m_startCondition.Signal();
8b0ee2cc 285 }
abbca718 286
13fd6a66 287 while (!IsStopped())
abbca718 288 {
ab1469a0 289 command.Clear();
76321de4
LOK
290 msg.clear();
291
60fa4578
LOK
292 {
293 CLockObject lock(&m_mutex);
8747dd4f
LOK
294 if (m_commandBuffer.Pop(command))
295 {
296 bParseFrame = true;
297 }
298 else if (m_communication->IsOpen() && m_communication->Read(msg, 50))
b5f34cf9 299 {
f2198ab5 300 if ((bParseFrame = (ParseMessage(msg) && !IsStopped())) == true)
8747dd4f 301 command = m_currentframe;
b5f34cf9 302 }
60fa4578
LOK
303 }
304
13fd6a66 305 if (bParseFrame)
9dee1670 306 ParseCommand(command);
8747dd4f 307 bParseFrame = false;
abbca718 308
b5f34cf9
LOK
309 Sleep(5);
310
13fd6a66 311 m_controller->CheckKeypressTimeout();
abbca718
LOK
312 }
313
1113cb7d
LOK
314 if (m_communication)
315 m_communication->Close();
316
60fa4578 317 return NULL;
abbca718
LOK
318}
319
18203d17 320bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
abbca718 321{
8ac9c610
LOK
322 bool bReturn(false);
323
60fa4578 324 if (!IsRunning())
8ac9c610 325 return bReturn;
f99bc831 326
18203d17 327 cec_logical_address addr = m_logicalAddresses.primary;
04437dcf 328
18203d17
LOK
329 if (type != CEC_DEVICE_TYPE_RESERVED)
330 {
f2198ab5 331 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
18203d17
LOK
332 {
333 if (m_logicalAddresses[iPtr] && m_busDevices[iPtr]->m_type == type)
334 {
335 addr = (cec_logical_address) iPtr;
336 break;
337 }
338 }
339 }
340
16b1e052 341 return SetStreamPath(m_busDevices[addr]->GetPhysicalAddress(false)) &&
4a870dc8 342 m_busDevices[addr]->TransmitActiveSource();
18203d17
LOK
343}
344
1a6669b8
LOK
345bool CCECProcessor::SetActiveSource(cec_logical_address iAddress)
346{
16b1e052 347 return SetStreamPath(m_busDevices[iAddress]->GetPhysicalAddress(false));
1a6669b8
LOK
348}
349
18203d17
LOK
350bool CCECProcessor::SetActiveView(void)
351{
4a870dc8 352 return SetActiveSource(m_types.IsEmpty() ? CEC_DEVICE_TYPE_RESERVED : m_types[0]);
8ac9c610
LOK
353}
354
28fa6c97 355bool CCECProcessor::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
a9232a79
LOK
356{
357 bool bReturn(false);
358
359 CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
360 if (device)
361 {
362 ((CCECPlaybackDevice *) device)->SetDeckControlMode(mode);
28fa6c97
LOK
363 if (bSendUpdate)
364 ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
a9232a79
LOK
365 bReturn = true;
366 }
367
368 return bReturn;
369}
370
28fa6c97 371bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
a9232a79
LOK
372{
373 bool bReturn(false);
374
375 CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
376 if (device)
377 {
378 ((CCECPlaybackDevice *) device)->SetDeckStatus(info);
28fa6c97
LOK
379 if (bSendUpdate)
380 ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
a9232a79
LOK
381 bReturn = true;
382 }
383
384 return bReturn;
385}
386
d2f1c157 387bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
16b1e052
LOK
388{
389 bool bReturn(false);
390
391 CStdString strLog;
d2f1c157 392 strLog.Format("setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
16b1e052
LOK
393 AddLog(CEC_LOG_DEBUG, strLog);
394
d2f1c157 395 m_iBaseDevice = iBaseDevice;
16b1e052 396 m_iHDMIPort = iPort;
9fd73dd4 397 if (!m_bStarted && !bForce)
16b1e052
LOK
398 return true;
399
400 uint16_t iPhysicalAddress(0);
d2f1c157
LOK
401 iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress();
402 uint16_t iPos = 0;
403 if (iPhysicalAddress == 0)
404 iPos = 0x1000;
405 else if (iPhysicalAddress % 0x1000 == 0)
406 iPos = 0x100;
407 else if (iPhysicalAddress % 0x100 == 0)
408 iPos = 0x10;
409 else if (iPhysicalAddress % 0x10 == 0)
410 iPos = 0x1;
411
412 while(!bReturn && iPos > 0)
16b1e052 413 {
d2f1c157 414 iPhysicalAddress += (uint16_t)(iPort * iPos);
16b1e052
LOK
415 strLog.Format("checking physical address %4x", iPhysicalAddress);
416 AddLog(CEC_LOG_DEBUG, strLog);
417 if (CheckPhysicalAddress(iPhysicalAddress))
418 {
419 strLog.Format("physical address %4x is in use", iPhysicalAddress);
420 AddLog(CEC_LOG_DEBUG, strLog);
d2f1c157 421 iPos = (iPos == 1) ? 0 : iPos / 0x10;
16b1e052
LOK
422 }
423 else
424 {
425 SetPhysicalAddress(iPhysicalAddress);
426 bReturn = true;
427 }
428 }
429
430 return bReturn;
431}
432
433bool CCECProcessor::CheckPhysicalAddress(uint16_t iPhysicalAddress)
434{
9fd73dd4 435 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
16b1e052
LOK
436 {
437 if (m_busDevices[iPtr]->GetPhysicalAddress(false) == iPhysicalAddress)
438 return true;
439 }
440 return false;
441}
442
8ac9c610
LOK
443bool CCECProcessor::SetStreamPath(uint16_t iStreamPath)
444{
04437dcf
LOK
445 bool bReturn(false);
446
8ac9c610
LOK
447 CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
448 if (device)
449 {
7856411b 450 device->SetActiveDevice();
91bea174 451 bReturn = true;
8ac9c610
LOK
452 }
453
04437dcf 454 return bReturn;
abbca718
LOK
455}
456
ab27363d 457bool CCECProcessor::TransmitInactiveSource(void)
abbca718 458{
60fa4578 459 if (!IsRunning())
f99bc831
LOK
460 return false;
461
ab1469a0 462 if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
ab27363d 463 return m_busDevices[m_logicalAddresses.primary]->TransmitInactiveSource();
cc60ab1c 464 return false;
abbca718
LOK
465}
466
9dee1670 467void CCECProcessor::LogOutput(const cec_command &data)
abbca718 468{
1d3ca3de 469 CStdString strTx;
57f45e6c
LOK
470 strTx.Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
471 if (data.opcode_set)
472 strTx.AppendFormat(":%02x", (uint8_t)data.opcode);
9dee1670 473
06a1f7ce 474 for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
1d3ca3de
LOK
475 strTx.AppendFormat(":%02x", data.parameters[iPtr]);
476 m_controller->AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
9dee1670 477}
2abe74eb 478
06bfd4d7 479bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
abbca718 480{
f8513317 481 if (m_logicalAddresses.primary != iLogicalAddress)
06775107
LOK
482 {
483 CStdString strLog;
f8513317 484 strLog.Format("<< setting primary logical address to %1x", iLogicalAddress);
06775107 485 m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
f8513317 486 m_logicalAddresses.primary = iLogicalAddress;
ab1469a0
LOK
487 m_logicalAddresses.Set(iLogicalAddress);
488 return SetAckMask(m_logicalAddresses.AckMask());
06775107 489 }
2abe74eb 490
06bfd4d7 491 return true;
abbca718 492}
825ddb96 493
28fa6c97
LOK
494bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
495{
496 for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
497 {
498 if (m_logicalAddresses[iPtr])
499 m_busDevices[iPtr]->SetMenuState(state);
500 }
501
502 if (bSendUpdate)
503 m_busDevices[m_logicalAddresses.primary]->TransmitMenuState(CECDEVICE_TV);
504
505 return true;
506}
507
2492216a
LOK
508bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress)
509{
16b1e052 510 if (!m_logicalAddresses.IsEmpty())
cc60ab1c 511 {
16b1e052
LOK
512 for (uint8_t iPtr = 0; iPtr < 15; iPtr++)
513 if (m_logicalAddresses[iPtr])
514 m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress);
8ac9c610 515 return SetActiveView();
cc60ab1c
LOK
516 }
517 return false;
1969b140
LOK
518}
519
8b7e5ff6
LOK
520bool CCECProcessor::SwitchMonitoring(bool bEnable)
521{
522 CStdString strLog;
523 strLog.Format("== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
524 m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
525
855a3a98
LOK
526 {
527 CLockObject lock(&m_mutex);
528 m_bMonitor = bEnable;
529
530 if (bEnable)
531 {
532 if (!m_busScan)
533 {
534 m_busScan = new CCECBusScan(this);
535 m_busScan->CreateThread(true);
536 }
537 }
538 else
539 {
540 if (m_busScan)
541 {
542 m_busScan->StopThread();
543 delete m_busScan;
544 m_busScan = NULL;
545 }
546 }
547 }
548
8b7e5ff6 549 if (bEnable)
06bfd4d7 550 return SetAckMask(0);
8b7e5ff6 551 else
ab1469a0 552 return SetAckMask(m_logicalAddresses.AckMask());
8b7e5ff6
LOK
553}
554
57f45e6c
LOK
555bool CCECProcessor::PollDevice(cec_logical_address iAddress)
556{
557 if (iAddress != CECDEVICE_UNKNOWN && m_busDevices[iAddress])
95a73fa7
LOK
558 {
559 return m_logicalAddresses.primary == CECDEVICE_UNKNOWN ?
560 m_busDevices[iAddress]->TransmitPoll(iAddress) :
561 m_busDevices[m_logicalAddresses.primary]->TransmitPoll(iAddress);
562 }
57f45e6c
LOK
563 return false;
564}
565
9f332fe2 566uint8_t CCECProcessor::VolumeUp(bool bWait /* = true */)
04e637f9
LOK
567{
568 uint8_t status = 0;
569 if (IsActiveDevice(CECDEVICE_AUDIOSYSTEM))
9f332fe2 570 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp(bWait);
04e637f9
LOK
571
572 return status;
573}
574
9f332fe2 575uint8_t CCECProcessor::VolumeDown(bool bWait /* = true */)
04e637f9
LOK
576{
577 uint8_t status = 0;
578 if (IsActiveDevice(CECDEVICE_AUDIOSYSTEM))
9f332fe2 579 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown(bWait);
04e637f9
LOK
580
581 return status;
582}
583
9f332fe2 584uint8_t CCECProcessor::MuteAudio(bool bWait /* = true */)
04e637f9
LOK
585{
586 uint8_t status = 0;
587 if (IsActiveDevice(CECDEVICE_AUDIOSYSTEM))
9f332fe2 588 status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio(bWait);
04e637f9
LOK
589
590 return status;
591}
592
16b1e052 593CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */) const
8ac9c610 594{
16b1e052 595 if (m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress)
b58d9277 596 return m_busDevices[m_logicalAddresses.primary];
8ac9c610 597
b58d9277 598 CCECBusDevice *device = NULL;
8ac9c610
LOK
599 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
600 {
16b1e052 601 if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh) == iPhysicalAddress)
8ac9c610
LOK
602 {
603 device = m_busDevices[iPtr];
604 break;
605 }
606 }
607
608 return device;
609}
610
a9232a79
LOK
611CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const
612{
613 CCECBusDevice *device = NULL;
614
615 for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
616 {
617 if (m_busDevices[iPtr]->m_type == type)
618 {
619 device = m_busDevices[iPtr];
620 break;
621 }
622 }
623
624 return device;
625}
626
6a1c0009
LOK
627cec_version CCECProcessor::GetDeviceCecVersion(cec_logical_address iAddress)
628{
629 return m_busDevices[iAddress]->GetCecVersion();
630}
631
ed21be2a
LOK
632cec_osd_name CCECProcessor::GetDeviceOSDName(cec_logical_address iAddress)
633{
634 CStdString strOSDName = m_busDevices[iAddress]->GetOSDName();
635 cec_osd_name retVal;
636
637 snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
638 retVal.device = iAddress;
639
640 return retVal;
641}
642
a3269a0a
LOK
643bool CCECProcessor::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
644{
cc60ab1c
LOK
645 if (m_busDevices[iAddress])
646 {
647 *language = m_busDevices[iAddress]->GetMenuLanguage();
5744fbba 648 return (strcmp(language->language, "???") != 0);
cc60ab1c
LOK
649 }
650 return false;
a3269a0a
LOK
651}
652
44c74256
LOK
653uint64_t CCECProcessor::GetDeviceVendorId(cec_logical_address iAddress)
654{
cc60ab1c
LOK
655 if (m_busDevices[iAddress])
656 return m_busDevices[iAddress]->GetVendorId();
657 return false;
44c74256
LOK
658}
659
e55f3f70
LOK
660cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddress)
661{
cc60ab1c
LOK
662 if (m_busDevices[iAddress])
663 return m_busDevices[iAddress]->GetPowerStatus();
664 return CEC_POWER_STATUS_UNKNOWN;
e55f3f70
LOK
665}
666
8d84e2c0 667bool CCECProcessor::Transmit(const cec_command &data)
825ddb96 668{
28352a04 669 bool bReturn(false);
13929cff
LOK
670 LogOutput(data);
671
28352a04
LOK
672 CCECAdapterMessage *output = new CCECAdapterMessage(data);
673 bReturn = Transmit(output);
674 delete output;
675
676 return bReturn;
06bfd4d7 677}
13929cff 678
28352a04 679bool CCECProcessor::Transmit(CCECAdapterMessage *output)
06bfd4d7
LOK
680{
681 bool bReturn(false);
2abe74eb 682 CLockObject lock(&m_mutex);
eb35e4ca 683 {
9902f4e8
LOK
684 SetLineTimeout(3);
685
fd5e333a 686 do
0e31a62c 687 {
9902f4e8
LOK
688 if (output->tries > 0)
689 SetLineTimeout(5);
690
82d1a9a1
LOK
691 CLockObject msgLock(&output->mutex);
692 if (!m_communication || !m_communication->Write(output))
0e31a62c 693 return bReturn;
82d1a9a1
LOK
694 else
695 {
696 output->condition.Wait(&output->mutex);
697 if (output->state != ADAPTER_MESSAGE_STATE_SENT)
698 {
699 m_controller->AddLog(CEC_LOG_ERROR, "command was not sent");
700 return bReturn;
701 }
0e31a62c 702 }
2abe74eb 703
82d1a9a1
LOK
704 if (output->transmit_timeout > 0)
705 {
706 if ((bReturn = WaitForTransmitSucceeded(output)) == false)
707 m_controller->AddLog(CEC_LOG_DEBUG, "did not receive ack");
708 }
709 else
710 bReturn = true;
fd5e333a 711 }while (output->transmit_timeout > 0 && output->needs_retry() && ++output->tries <= output->maxTries);
2abe74eb
LOK
712 }
713
9902f4e8
LOK
714 SetLineTimeout(3);
715
7ea0d558 716 return bReturn;
825ddb96 717}
abbca718 718
22b4e74a 719void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
abbca718 720{
9dee1670
LOK
721 m_controller->AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
722
06a1f7ce 723 cec_command command;
f8513317 724 // TODO
ab1469a0
LOK
725 cec_command::Format(command, m_logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT);
726 command.parameters.PushBack((uint8_t)opcode);
727 command.parameters.PushBack((uint8_t)reason);
9dee1670
LOK
728
729 Transmit(command);
abbca718
LOK
730}
731
82d1a9a1 732bool CCECProcessor::WaitForTransmitSucceeded(CCECAdapterMessage *message)
abbca718 733{
1f0e9e0f
LOK
734 bool bError(false);
735 bool bTransmitSucceeded(false);
82d1a9a1 736 uint8_t iPacketsLeft(message->size() / 4);
abbca718
LOK
737
738 int64_t iNow = GetTimeMs();
82d1a9a1 739 int64_t iTargetTime = iNow + message->transmit_timeout;
abbca718 740
82d1a9a1 741 while (!bTransmitSucceeded && !bError && (message->transmit_timeout == 0 || iNow < iTargetTime))
abbca718 742 {
220537f2 743 CCECAdapterMessage msg;
25701fa6 744
82d1a9a1 745 if (!m_communication->Read(msg, message->transmit_timeout > 0 ? (int32_t)(iTargetTime - iNow) : 1000))
abbca718 746 {
abbca718 747 iNow = GetTimeMs();
5d38b0b6
LOK
748 continue;
749 }
750
855a3a98
LOK
751 if (msg.message() == MSGCODE_FRAME_START && msg.ack())
752 {
753 m_busDevices[msg.initiator()]->GetHandler()->HandlePoll(msg.initiator(), msg.destination());
754 m_lastInitiator = msg.initiator();
755 iNow = GetTimeMs();
756 continue;
757 }
758
759 bError = msg.is_error();
760 if (msg.message() == MSGCODE_RECEIVE_FAILED &&
761 m_lastInitiator != CECDEVICE_UNKNOWN &&
762 !m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed())
763 {
764 iNow = GetTimeMs();
765 continue;
766 }
767
82d1a9a1 768 if (bError)
fd5e333a 769 {
82d1a9a1 770 message->reply = msg.message();
fd5e333a
LOK
771 m_controller->AddLog(CEC_LOG_DEBUG, msg.ToString());
772 }
82d1a9a1 773 else
7ea0d558 774 {
edab6137
LOK
775 switch(msg.message())
776 {
777 case MSGCODE_COMMAND_ACCEPTED:
fd5e333a 778 m_controller->AddLog(CEC_LOG_DEBUG, msg.ToString());
edab6137
LOK
779 if (iPacketsLeft > 0)
780 iPacketsLeft--;
781 break;
782 case MSGCODE_TRANSMIT_SUCCEEDED:
fd5e333a 783 m_controller->AddLog(CEC_LOG_DEBUG, msg.ToString());
edab6137
LOK
784 bTransmitSucceeded = (iPacketsLeft == 0);
785 bError = !bTransmitSucceeded;
82d1a9a1 786 message->reply = MSGCODE_TRANSMIT_SUCCEEDED;
edab6137
LOK
787 break;
788 default:
26128836
LOK
789 // ignore other data while waiting
790 break;
edab6137 791 }
7ea0d558 792
edab6137
LOK
793 iNow = GetTimeMs();
794 }
abbca718
LOK
795 }
796
1f0e9e0f 797 return bTransmitSucceeded && !bError;
abbca718
LOK
798}
799
0e7b6c54 800bool CCECProcessor::ParseMessage(const CCECAdapterMessage &msg)
abbca718 801{
855a3a98
LOK
802 bool bEom(false);
803 bool bIsError(msg.is_error());
60fa4578 804
0e7b6c54 805 if (msg.empty())
7ea0d558 806 return bEom;
abbca718 807
0e7b6c54 808 switch(msg.message())
abbca718 809 {
abbca718
LOK
810 case MSGCODE_FRAME_START:
811 {
ab1469a0 812 m_currentframe.Clear();
0e7b6c54 813 if (msg.size() >= 2)
abbca718 814 {
0e7b6c54
LOK
815 m_currentframe.initiator = msg.initiator();
816 m_currentframe.destination = msg.destination();
817 m_currentframe.ack = msg.ack();
818 m_currentframe.eom = msg.eom();
abbca718 819 }
855a3a98
LOK
820 if (m_currentframe.ack == true)
821 {
822 m_lastInitiator = m_currentframe.initiator;
823 m_busDevices[m_lastInitiator]->GetHandler()->HandlePoll(m_currentframe.initiator, m_currentframe.destination);
824 }
825 }
826 break;
827 case MSGCODE_RECEIVE_FAILED:
828 {
829 if (m_lastInitiator != CECDEVICE_UNKNOWN)
830 bIsError = m_busDevices[m_lastInitiator]->GetHandler()->HandleReceiveFailed();
abbca718
LOK
831 }
832 break;
833 case MSGCODE_FRAME_DATA:
834 {
0e7b6c54 835 if (msg.size() >= 2)
78e8010a 836 {
ab1469a0 837 m_currentframe.PushBack(msg[1]);
0e7b6c54 838 m_currentframe.eom = msg.eom();
abbca718 839 }
0e7b6c54 840 bEom = msg.eom();
abbca718 841 }
78e8010a 842 break;
abbca718
LOK
843 default:
844 break;
845 }
7ea0d558 846
855a3a98 847 m_controller->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
7ea0d558 848 return bEom;
abbca718
LOK
849}
850
e9de9629 851void CCECProcessor::ParseCommand(cec_command &command)
abbca718 852{
e9de9629 853 CStdString dataStr;
1d3ca3de 854 dataStr.Format(">> %1x%1x:%02x", command.initiator, command.destination, command.opcode);
e9de9629
LOK
855 for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
856 dataStr.AppendFormat(":%02x", (unsigned int)command.parameters[iPtr]);
1d3ca3de 857 m_controller->AddLog(CEC_LOG_TRAFFIC, dataStr.c_str());
dc113aca 858
7871d66e 859 if (!m_bMonitor && command.initiator >= CECDEVICE_TV && command.initiator <= CECDEVICE_BROADCAST)
e9de9629 860 m_busDevices[(uint8_t)command.initiator]->HandleCommand(command);
dc113aca
LOK
861}
862
6d858ba4
LOK
863cec_logical_addresses CCECProcessor::GetActiveDevices(void)
864{
865 cec_logical_addresses addresses;
988de7b9 866 addresses.Clear();
6d858ba4
LOK
867 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
868 {
869 if (m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
870 addresses.Set((cec_logical_address) iPtr);
871 }
872 return addresses;
873}
874
875bool CCECProcessor::IsActiveDevice(cec_logical_address address)
876{
877 return m_busDevices[address]->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
878}
879
880bool CCECProcessor::IsActiveDeviceType(cec_device_type type)
881{
6d858ba4 882 for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
2813bd07
LOK
883 {
884 if (m_busDevices[iPtr]->GetType() == type && m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
6d858ba4 885 return true;
2813bd07
LOK
886 }
887
6d858ba4
LOK
888 return false;
889}
890
0f23c85c
LOK
891uint16_t CCECProcessor::GetPhysicalAddress(void) const
892{
ab1469a0 893 if (!m_logicalAddresses.IsEmpty() && m_busDevices[m_logicalAddresses.primary])
16b1e052 894 return m_busDevices[m_logicalAddresses.primary]->GetPhysicalAddress(false);
cc60ab1c 895 return false;
0f23c85c
LOK
896}
897
e9de9629 898void CCECProcessor::SetCurrentButton(cec_user_control_code iButtonCode)
dc113aca 899{
e9de9629 900 m_controller->SetCurrentButton(iButtonCode);
dc113aca
LOK
901}
902
e9de9629 903void CCECProcessor::AddCommand(const cec_command &command)
dc113aca 904{
0544ff56 905 m_controller->AddCommand(command);
dc113aca
LOK
906}
907
95ba7a09
LOK
908void CCECProcessor::AddKey(cec_keypress &key)
909{
910 m_controller->AddKey(key);
911}
912
e9de9629 913void CCECProcessor::AddKey(void)
dc113aca 914{
e9de9629 915 m_controller->AddKey();
abbca718 916}
acec5f48 917
e9de9629 918void CCECProcessor::AddLog(cec_log_level level, const CStdString &strMessage)
acec5f48 919{
e9de9629 920 m_controller->AddLog(level, strMessage);
acec5f48 921}
06bfd4d7
LOK
922
923bool CCECProcessor::SetAckMask(uint16_t iMask)
924{
28352a04 925 bool bReturn(false);
06bfd4d7
LOK
926 CStdString strLog;
927 strLog.Format("setting ackmask to %2x", iMask);
928 m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
929
28352a04 930 CCECAdapterMessage *output = new CCECAdapterMessage;
06bfd4d7
LOK
931
932 output->push_back(MSGSTART);
933 output->push_escaped(MSGCODE_SET_ACK_MASK);
934 output->push_escaped(iMask >> 8);
935 output->push_escaped((uint8_t)iMask);
936 output->push_back(MSGEND);
937
28352a04 938 if ((bReturn = Transmit(output)) == false)
06bfd4d7 939 m_controller->AddLog(CEC_LOG_ERROR, "could not set the ackmask");
06bfd4d7 940
28352a04
LOK
941 delete output;
942
943 return bReturn;
06bfd4d7 944}
a33794d8
LOK
945
946bool CCECProcessor::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = false */)
947{
948 return m_busDevices[iDestination]->SendKeypress(key, bWait);
949}
950
951bool CCECProcessor::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = false */)
952{
953 return m_busDevices[iDestination]->SendKeyRelease(bWait);
954}
7c63a480 955
03ae897d
LOK
956const char *CCECProcessor::ToString(const cec_menu_state state)
957{
958 switch (state)
959 {
960 case CEC_MENU_STATE_ACTIVATED:
961 return "activated";
962 case CEC_MENU_STATE_DEACTIVATED:
963 return "deactivated";
964 default:
965 return "unknown";
966 }
967}
968
969const char *CCECProcessor::ToString(const cec_version version)
970{
971 switch (version)
972 {
973 case CEC_VERSION_1_2:
974 return "1.2";
975 case CEC_VERSION_1_2A:
976 return "1.2a";
977 case CEC_VERSION_1_3:
978 return "1.3";
979 case CEC_VERSION_1_3A:
980 return "1.3a";
981 case CEC_VERSION_1_4:
982 return "1.4";
983 default:
984 return "unknown";
985 }
986}
987
988const char *CCECProcessor::ToString(const cec_power_status status)
989{
990 switch (status)
991 {
992 case CEC_POWER_STATUS_ON:
993 return "on";
994 case CEC_POWER_STATUS_STANDBY:
995 return "standby";
996 case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
997 return "in transition from on to standby";
998 case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
999 return "in transition from standby to on";
1000 default:
1001 return "unknown";
1002 }
1003}
1004
1005const char *CCECProcessor::ToString(const cec_logical_address address)
1006{
1007 switch(address)
1008 {
1009 case CECDEVICE_AUDIOSYSTEM:
1010 return "Audio";
1011 case CECDEVICE_BROADCAST:
1012 return "Broadcast";
1013 case CECDEVICE_FREEUSE:
1014 return "Free use";
1015 case CECDEVICE_PLAYBACKDEVICE1:
1016 return "Playback 1";
1017 case CECDEVICE_PLAYBACKDEVICE2:
1018 return "Playback 2";
1019 case CECDEVICE_PLAYBACKDEVICE3:
1020 return "Playback 3";
1021 case CECDEVICE_RECORDINGDEVICE1:
1022 return "Recorder 1";
1023 case CECDEVICE_RECORDINGDEVICE2:
1024 return "Recorder 2";
1025 case CECDEVICE_RECORDINGDEVICE3:
1026 return "Recorder 3";
1027 case CECDEVICE_RESERVED1:
1028 return "Reserved 1";
1029 case CECDEVICE_RESERVED2:
1030 return "Reserved 2";
1031 case CECDEVICE_TUNER1:
1032 return "Tuner 1";
1033 case CECDEVICE_TUNER2:
1034 return "Tuner 2";
1035 case CECDEVICE_TUNER3:
1036 return "Tuner 3";
1037 case CECDEVICE_TUNER4:
1038 return "Tuner 4";
1039 case CECDEVICE_TV:
1040 return "TV";
1041 default:
1042 return "unknown";
1043 }
1044}
1045
1046const char *CCECProcessor::ToString(const cec_deck_control_mode mode)
1047{
1048 switch (mode)
1049 {
1050 case CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND:
1051 return "skip forward wind";
1052 case CEC_DECK_CONTROL_MODE_EJECT:
1053 return "eject";
1054 case CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND:
1055 return "reverse rewind";
1056 case CEC_DECK_CONTROL_MODE_STOP:
1057 return "stop";
1058 default:
1059 return "unknown";
1060 }
1061}
1062
1063const char *CCECProcessor::ToString(const cec_deck_info status)
1064{
1065 switch (status)
1066 {
1067 case CEC_DECK_INFO_PLAY:
1068 return "play";
1069 case CEC_DECK_INFO_RECORD:
1070 return "record";
1071 case CEC_DECK_INFO_PLAY_REVERSE:
1072 return "play reverse";
1073 case CEC_DECK_INFO_STILL:
1074 return "still";
1075 case CEC_DECK_INFO_SLOW:
1076 return "slow";
1077 case CEC_DECK_INFO_SLOW_REVERSE:
1078 return "slow reverse";
1079 case CEC_DECK_INFO_FAST_FORWARD:
1080 return "fast forward";
1081 case CEC_DECK_INFO_FAST_REVERSE:
1082 return "fast reverse";
1083 case CEC_DECK_INFO_NO_MEDIA:
1084 return "no media";
1085 case CEC_DECK_INFO_STOP:
1086 return "stop";
1087 case CEC_DECK_INFO_SKIP_FORWARD_WIND:
1088 return "info skip forward wind";
1089 case CEC_DECK_INFO_SKIP_REVERSE_REWIND:
1090 return "info skip reverse rewind";
1091 case CEC_DECK_INFO_INDEX_SEARCH_FORWARD:
1092 return "info index search forward";
1093 case CEC_DECK_INFO_INDEX_SEARCH_REVERSE:
1094 return "info index search reverse";
1095 case CEC_DECK_INFO_OTHER_STATUS:
1096 return "other";
1097 default:
1098 return "unknown";
1099 }
1100}
1101
1102const char *CCECProcessor::ToString(const cec_opcode opcode)
1103{
1104 switch (opcode)
1105 {
1106 case CEC_OPCODE_ACTIVE_SOURCE:
1107 return "active source";
1108 case CEC_OPCODE_IMAGE_VIEW_ON:
1109 return "image view on";
1110 case CEC_OPCODE_TEXT_VIEW_ON:
1111 return "text view on";
1112 case CEC_OPCODE_INACTIVE_SOURCE:
1113 return "inactive source";
1114 case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
1115 return "request active source";
1116 case CEC_OPCODE_ROUTING_CHANGE:
1117 return "routing change";
1118 case CEC_OPCODE_ROUTING_INFORMATION:
1119 return "routing information";
1120 case CEC_OPCODE_SET_STREAM_PATH:
1121 return "set stream path";
1122 case CEC_OPCODE_STANDBY:
1123 return "standby";
1124 case CEC_OPCODE_RECORD_OFF:
1125 return "record off";
1126 case CEC_OPCODE_RECORD_ON:
1127 return "record on";
1128 case CEC_OPCODE_RECORD_STATUS:
1129 return "record status";
1130 case CEC_OPCODE_RECORD_TV_SCREEN:
1131 return "record tv screen";
1132 case CEC_OPCODE_CLEAR_ANALOGUE_TIMER:
1133 return "clear analogue timer";
1134 case CEC_OPCODE_CLEAR_DIGITAL_TIMER:
1135 return "clear digital timer";
1136 case CEC_OPCODE_CLEAR_EXTERNAL_TIMER:
1137 return "clear external timer";
1138 case CEC_OPCODE_SET_ANALOGUE_TIMER:
1139 return "set analogue timer";
1140 case CEC_OPCODE_SET_DIGITAL_TIMER:
1141 return "set digital timer";
1142 case CEC_OPCODE_SET_EXTERNAL_TIMER:
1143 return "set external timer";
1144 case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE:
1145 return "set timer program title";
1146 case CEC_OPCODE_TIMER_CLEARED_STATUS:
1147 return "timer cleared status";
1148 case CEC_OPCODE_TIMER_STATUS:
1149 return "timer status";
1150 case CEC_OPCODE_CEC_VERSION:
1151 return "cec version";
1152 case CEC_OPCODE_GET_CEC_VERSION:
1153 return "get cec version";
1154 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
1155 return "give physical address";
1156 case CEC_OPCODE_GET_MENU_LANGUAGE:
1157 return "get menu language";
1158 case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
1159 return "report physical address";
1160 case CEC_OPCODE_SET_MENU_LANGUAGE:
1161 return "set menu language";
1162 case CEC_OPCODE_DECK_CONTROL:
1163 return "deck control";
1164 case CEC_OPCODE_DECK_STATUS:
1165 return "deck status";
1166 case CEC_OPCODE_GIVE_DECK_STATUS:
1167 return "give deck status";
1168 case CEC_OPCODE_PLAY:
1169 return "play";
1170 case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
1171 return "give tuner status";
1172 case CEC_OPCODE_SELECT_ANALOGUE_SERVICE:
1173 return "select analogue service";
1174 case CEC_OPCODE_SELECT_DIGITAL_SERVICE:
1175 return "set digital service";
1176 case CEC_OPCODE_TUNER_DEVICE_STATUS:
1177 return "tuner device status";
1178 case CEC_OPCODE_TUNER_STEP_DECREMENT:
1179 return "tuner step decrement";
1180 case CEC_OPCODE_TUNER_STEP_INCREMENT:
1181 return "tuner step increment";
1182 case CEC_OPCODE_DEVICE_VENDOR_ID:
1183 return "device vendor id";
1184 case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
1185 return "give device vendor id";
1186 case CEC_OPCODE_VENDOR_COMMAND:
1187 return "vendor command";
1188 case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
1189 return "vendor command with id";
1190 case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
1191 return "vendor remote button down";
1192 case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
1193 return "vendor remote button up";
1194 case CEC_OPCODE_SET_OSD_STRING:
1195 return "set osd string";
1196 case CEC_OPCODE_GIVE_OSD_NAME:
1197 return "give osd name";
1198 case CEC_OPCODE_SET_OSD_NAME:
1199 return "set osd name";
1200 case CEC_OPCODE_MENU_REQUEST:
1201 return "menu request";
1202 case CEC_OPCODE_MENU_STATUS:
1203 return "menu status";
1204 case CEC_OPCODE_USER_CONTROL_PRESSED:
1205 return "user control pressed";
1206 case CEC_OPCODE_USER_CONTROL_RELEASE:
1207 return "user control release";
1208 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
1209 return "give device power status";
1210 case CEC_OPCODE_REPORT_POWER_STATUS:
1211 return "report power status";
1212 case CEC_OPCODE_FEATURE_ABORT:
1213 return "feature abort";
1214 case CEC_OPCODE_ABORT:
1215 return "abort";
1216 case CEC_OPCODE_GIVE_AUDIO_STATUS:
1217 return "give audio status";
1218 case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
1219 return "give audio mode status";
1220 case CEC_OPCODE_REPORT_AUDIO_STATUS:
1221 return "report audio status";
1222 case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
1223 return "set system audio mode";
1224 case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
1225 return "system audio mode request";
1226 case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
1227 return "system audio mode status";
1228 case CEC_OPCODE_SET_AUDIO_RATE:
1229 return "set audio rate";
1230 default:
1231 return "UNKNOWN";
1232 }
1233}
1234
1235const char *CCECProcessor::ToString(const cec_system_audio_status mode)
1236{
1237 switch(mode)
1238 {
1239 case CEC_SYSTEM_AUDIO_STATUS_ON:
1240 return "on";
1241 case CEC_SYSTEM_AUDIO_STATUS_OFF:
1242 return "off";
1243 default:
1244 return "unknown";
1245 }
1246}
1247
1248const char *CCECProcessor::ToString(const cec_audio_status status)
1249{
1250 // TODO this is a mask
1251 return "TODO";
1252}
1253
1254const char *CCECProcessor::ToString(const cec_vendor_id vendor)
1255{
1256 switch (vendor)
1257 {
1258 case CEC_VENDOR_SAMSUNG:
1259 return "Samsung";
1260 case CEC_VENDOR_LG:
1261 return "LG";
1262 case CEC_VENDOR_PANASONIC:
1263 return "Panasonic";
1264 case CEC_VENDOR_PIONEER:
1265 return "Pioneer";
1266 case CEC_VENDOR_ONKYO:
1267 return "Onkyo";
1268 case CEC_VENDOR_YAMAHA:
1269 return "Yamaha";
ec0deac1
LOK
1270 case CEC_VENDOR_PHILIPS:
1271 return "Philips";
03ae897d
LOK
1272 default:
1273 return "Unknown";
1274 }
1275}
1276
7c63a480
LOK
1277void *CCECBusScan::Process(void)
1278{
1279 CCECBusDevice *device(NULL);
5e5637c6 1280 while (!IsStopped())
7c63a480 1281 {
5e5637c6 1282 for (unsigned int iPtr = 0; iPtr < 15 && !IsStopped(); iPtr++)
7c63a480 1283 {
5e5637c6
LOK
1284 device = m_processor->m_busDevices[iPtr];
1285 if (device && device->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
1286 {
5e5637c6
LOK
1287 if (!IsStopped())
1288 device->GetVendorId();
1289 Sleep(5);
1290 }
7c63a480 1291 }
34d46707 1292 Sleep(5000);
7c63a480
LOK
1293 }
1294 return NULL;
1295}
1113cb7d
LOK
1296
1297bool CCECProcessor::StartBootloader(void)
1298{
1299 return m_communication->StartBootloader();
1300}
1301
1302bool CCECProcessor::PingAdapter(void)
1303{
1304 return m_communication->PingAdapter();
1305}