cec: removed dupe m_bRunning properties. wait until a thread is started before return...
[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
LOK
35#include "AdapterCommunication.h"
36#include "LibCEC.h"
abbca718 37#include "util/StdString.h"
b9187cc6 38#include "platform/timeutils.h"
abbca718
LOK
39
40using namespace CEC;
41using namespace std;
42
2b4d8297 43CCECProcessor::CCECProcessor(CLibCEC *controller, CAdapterCommunication *serComm, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) :
df7339c6
LOK
44 m_physicaladdress(iPhysicalAddress),
45 m_iLogicalAddress(iLogicalAddress),
2abe74eb
LOK
46 m_strDeviceName(strDeviceName),
47 m_communication(serComm),
48 m_controller(controller)
abbca718 49{
abbca718
LOK
50}
51
2abe74eb 52CCECProcessor::~CCECProcessor(void)
abbca718 53{
2abe74eb
LOK
54 StopThread();
55 m_communication = NULL;
56 m_controller = NULL;
abbca718
LOK
57}
58
2abe74eb 59bool CCECProcessor::Start(void)
abbca718 60{
2abe74eb 61 if (!m_communication || !m_communication->IsOpen())
13fd6a66
LOK
62 {
63 m_controller->AddLog(CEC_LOG_ERROR, "connection is closed");
a8f0bd18 64 return false;
13fd6a66 65 }
abbca718 66
a8f0bd18 67 if (!SetLogicalAddress(m_iLogicalAddress))
abbca718 68 {
2abe74eb 69 m_controller->AddLog(CEC_LOG_ERROR, "could not set the logical address");
a8f0bd18 70 return false;
abbca718
LOK
71 }
72
60fa4578 73 if (CreateThread())
a8f0bd18 74 return true;
a8f0bd18 75 else
2abe74eb 76 m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
abbca718 77
a8f0bd18 78 return false;
abbca718
LOK
79}
80
2abe74eb 81void *CCECProcessor::Process(void)
f99bc831 82{
2abe74eb 83 m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started");
abbca718 84
13fd6a66 85 while (!IsStopped())
abbca718 86 {
60fa4578
LOK
87 bool bParseFrame(false);
88 {
89 CLockObject lock(&m_mutex);
90 cec_frame msg;
25701fa6
LOK
91 msg.clear();
92
13fd6a66
LOK
93 if (m_communication->IsOpen() && m_communication->Read(msg, CEC_BUTTON_TIMEOUT))
94 bParseFrame = ParseMessage(msg) && !IsStopped();
60fa4578
LOK
95 }
96
13fd6a66 97 if (bParseFrame)
60fa4578 98 ParseCurrentFrame();
abbca718 99
13fd6a66
LOK
100 m_controller->CheckKeypressTimeout();
101
102 if (!IsStopped())
12027dbe 103 Sleep(50);
abbca718
LOK
104 }
105
60fa4578 106 return NULL;
abbca718
LOK
107}
108
2abe74eb 109bool CCECProcessor::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
abbca718 110{
60fa4578 111 if (!IsRunning())
f99bc831
LOK
112 return false;
113
abbca718
LOK
114 CStdString strLog;
115 strLog.Format("powering on devices with logical address %d", (int8_t)address);
2abe74eb 116 m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
abbca718 117 cec_frame frame;
25701fa6
LOK
118 frame.clear();
119
abbca718 120 frame.push_back(GetSourceDestination(address));
8bca69de 121 frame.push_back((uint8_t) CEC_OPCODE_TEXT_VIEW_ON);
abbca718
LOK
122 return Transmit(frame);
123}
124
2abe74eb 125bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
abbca718 126{
60fa4578 127 if (!IsRunning())
f99bc831
LOK
128 return false;
129
abbca718
LOK
130 CStdString strLog;
131 strLog.Format("putting all devices with logical address %d in standby mode", (int8_t)address);
2abe74eb 132 m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
abbca718 133 cec_frame frame;
25701fa6
LOK
134 frame.clear();
135
abbca718 136 frame.push_back(GetSourceDestination(address));
8bca69de 137 frame.push_back((uint8_t) CEC_OPCODE_STANDBY);
abbca718
LOK
138 return Transmit(frame);
139}
140
2abe74eb 141bool CCECProcessor::SetActiveView(void)
abbca718 142{
60fa4578 143 if (!IsRunning())
f99bc831
LOK
144 return false;
145
2abe74eb 146 m_controller->AddLog(CEC_LOG_DEBUG, "setting active view");
abbca718 147 cec_frame frame;
25701fa6
LOK
148 frame.clear();
149
abbca718 150 frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
8bca69de 151 frame.push_back((uint8_t) CEC_OPCODE_ACTIVE_SOURCE);
abbca718
LOK
152 frame.push_back((m_physicaladdress >> 8) & 0xFF);
153 frame.push_back(m_physicaladdress & 0xFF);
154 return Transmit(frame);
155}
156
2abe74eb 157bool CCECProcessor::SetInactiveView(void)
abbca718 158{
60fa4578 159 if (!IsRunning())
f99bc831
LOK
160 return false;
161
2abe74eb 162 m_controller->AddLog(CEC_LOG_DEBUG, "setting inactive view");
abbca718 163 cec_frame frame;
25701fa6
LOK
164 frame.clear();
165
abbca718 166 frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
8bca69de 167 frame.push_back((uint8_t) CEC_OPCODE_INACTIVE_SOURCE);
abbca718
LOK
168 frame.push_back((m_physicaladdress >> 8) & 0xFF);
169 frame.push_back(m_physicaladdress & 0xFF);
170 return Transmit(frame);
171}
172
2abe74eb 173bool CCECProcessor::Transmit(const cec_frame &data, bool bWaitForAck /* = true */)
abbca718 174{
2abe74eb 175 CStdString txStr = "transmit ";
25701fa6
LOK
176 for (unsigned int i = 0; i < data.size; i++)
177 txStr.AppendFormat(" %02x", data.data[i]);
2abe74eb
LOK
178 m_controller->AddLog(CEC_LOG_DEBUG, txStr.c_str());
179
25701fa6 180 if (data.size == 0)
2abe74eb
LOK
181 {
182 m_controller->AddLog(CEC_LOG_WARNING, "transmit buffer is empty");
183 return false;
184 }
185
186 cec_frame output;
25701fa6 187 output.clear();
2abe74eb
LOK
188
189 //set ack polarity to high when transmitting to the broadcast address
190 //set ack polarity low when transmitting to any other address
191 output.push_back(MSGSTART);
192 CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT_ACK_POLARITY);
193
25701fa6 194 if ((data.data[0] & 0xF) == 0xF)
2abe74eb
LOK
195 CAdapterCommunication::PushEscaped(output, CEC_TRUE);
196 else
197 CAdapterCommunication::PushEscaped(output, CEC_FALSE);
198
199 output.push_back(MSGEND);
200
25701fa6 201 for (int8_t i = 0; i < data.size; i++)
2abe74eb
LOK
202 {
203 output.push_back(MSGSTART);
204
25701fa6 205 if (i == (int8_t)data.size - 1)
2abe74eb
LOK
206 CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT_EOM);
207 else
208 CAdapterCommunication::PushEscaped(output, MSGCODE_TRANSMIT);
209
25701fa6 210 CAdapterCommunication::PushEscaped(output, data.data[i]);
2abe74eb
LOK
211
212 output.push_back(MSGEND);
213 }
214
215 return TransmitFormatted(output, bWaitForAck);
abbca718
LOK
216}
217
2abe74eb 218bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
abbca718 219{
2abe74eb
LOK
220 CStdString strLog;
221 strLog.Format("setting logical address to %d", iLogicalAddress);
222 m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
223
224 m_iLogicalAddress = iLogicalAddress;
225 return m_communication && m_communication->SetAckMask(0x1 << (uint8_t)m_iLogicalAddress);
abbca718 226}
825ddb96 227
2abe74eb 228bool CCECProcessor::TransmitFormatted(const cec_frame &data, bool bWaitForAck /* = true */)
825ddb96 229{
2abe74eb
LOK
230 CLockObject lock(&m_mutex);
231 if (!m_communication || !m_communication->Write(data))
232 return false;
233
234 if (bWaitForAck && !WaitForAck())
235 {
236 m_controller->AddLog(CEC_LOG_DEBUG, "did not receive ACK");
237 return false;
238 }
239
240 return true;
825ddb96 241}
abbca718 242
2abe74eb 243void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, ECecAbortReason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
abbca718 244{
2abe74eb 245 m_controller->AddLog(CEC_LOG_DEBUG, "transmitting abort message");
abbca718 246 cec_frame frame;
25701fa6
LOK
247 frame.clear();
248
abbca718 249 frame.push_back(GetSourceDestination(address));
8bca69de
LOK
250 frame.push_back((uint8_t) CEC_OPCODE_FEATURE_ABORT);
251 frame.push_back((uint8_t) opcode);
252 frame.push_back((uint8_t) reason);
abbca718
LOK
253 Transmit(frame);
254}
255
2abe74eb 256void CCECProcessor::ReportCECVersion(cec_logical_address address /* = CECDEVICE_TV */)
abbca718
LOK
257{
258 cec_frame frame;
25701fa6
LOK
259 frame.clear();
260
2abe74eb 261 m_controller->AddLog(CEC_LOG_NOTICE, "reporting CEC version as 1.3a");
abbca718 262 frame.push_back(GetSourceDestination(address));
8bca69de 263 frame.push_back((uint8_t) CEC_OPCODE_CEC_VERSION);
25701fa6 264 frame.push_back((uint8_t) CEC_VERSION_1_3A);
abbca718
LOK
265 Transmit(frame);
266}
267
2abe74eb 268void CCECProcessor::ReportPowerState(cec_logical_address address /*= CECDEVICE_TV */, bool bOn /* = true */)
abbca718
LOK
269{
270 cec_frame frame;
25701fa6
LOK
271 frame.clear();
272
abbca718 273 if (bOn)
2abe74eb 274 m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"On\" power status");
abbca718 275 else
2abe74eb 276 m_controller->AddLog(CEC_LOG_NOTICE, "reporting \"Off\" power status");
abbca718
LOK
277
278 frame.push_back(GetSourceDestination(address));
8bca69de
LOK
279 frame.push_back((uint8_t) CEC_OPCODE_REPORT_POWER_STATUS);
280 frame.push_back(bOn ? (uint8_t) CEC_POWER_STATUS_ON : (uint8_t) CEC_POWER_STATUS_STANDBY);
abbca718
LOK
281 Transmit(frame);
282}
283
2abe74eb 284void CCECProcessor::ReportMenuState(cec_logical_address address /* = CECDEVICE_TV */, bool bActive /* = true */)
abbca718
LOK
285{
286 cec_frame frame;
25701fa6
LOK
287 frame.clear();
288
abbca718 289 if (bActive)
2abe74eb 290 m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as active");
abbca718 291 else
2abe74eb 292 m_controller->AddLog(CEC_LOG_NOTICE, "reporting menu state as inactive");
abbca718
LOK
293
294 frame.push_back(GetSourceDestination(address));
8bca69de
LOK
295 frame.push_back((uint8_t) CEC_OPCODE_MENU_STATUS);
296 frame.push_back(bActive ? (uint8_t) CEC_MENU_STATE_ACTIVATED : (uint8_t) CEC_MENU_STATE_DEACTIVATED);
abbca718
LOK
297 Transmit(frame);
298}
299
2abe74eb 300void CCECProcessor::ReportVendorID(cec_logical_address address /* = CECDEVICE_TV */)
abbca718 301{
2abe74eb 302 m_controller->AddLog(CEC_LOG_NOTICE, "vendor ID requested, feature abort");
abbca718
LOK
303 TransmitAbort(address, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
304}
305
2abe74eb 306void CCECProcessor::ReportOSDName(cec_logical_address address /* = CECDEVICE_TV */)
abbca718
LOK
307{
308 cec_frame frame;
25701fa6
LOK
309 frame.clear();
310
abbca718
LOK
311 const char *osdname = m_strDeviceName.c_str();
312 CStdString strLog;
313 strLog.Format("reporting OSD name as %s", osdname);
2abe74eb 314 m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
abbca718 315 frame.push_back(GetSourceDestination(address));
8bca69de 316 frame.push_back((uint8_t) CEC_OPCODE_SET_OSD_NAME);
abbca718
LOK
317
318 for (unsigned int i = 0; i < strlen(osdname); i++)
319 frame.push_back(osdname[i]);
320
321 Transmit(frame);
322}
323
2abe74eb 324void CCECProcessor::ReportPhysicalAddress(void)
abbca718
LOK
325{
326 cec_frame frame;
25701fa6
LOK
327 frame.clear();
328
abbca718
LOK
329 CStdString strLog;
330 strLog.Format("reporting physical address as %04x", m_physicaladdress);
2abe74eb 331 m_controller->AddLog(CEC_LOG_NOTICE, strLog.c_str());
abbca718 332 frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
8bca69de 333 frame.push_back((uint8_t) CEC_OPCODE_REPORT_PHYSICAL_ADDRESS);
25701fa6
LOK
334 frame.push_back((uint8_t) ((m_physicaladdress >> 8) & 0xFF));
335 frame.push_back((uint8_t) (m_physicaladdress & 0xFF));
336 frame.push_back((uint8_t) CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
abbca718
LOK
337 Transmit(frame);
338}
339
2abe74eb 340void CCECProcessor::BroadcastActiveSource(void)
abbca718
LOK
341{
342 cec_frame frame;
25701fa6
LOK
343 frame.clear();
344
2abe74eb 345 m_controller->AddLog(CEC_LOG_NOTICE, "broadcasting active source");
abbca718 346 frame.push_back(GetSourceDestination(CECDEVICE_BROADCAST));
8bca69de 347 frame.push_back((uint8_t) CEC_OPCODE_ACTIVE_SOURCE);
25701fa6
LOK
348 frame.push_back((uint8_t) ((m_physicaladdress >> 8) & 0xFF));
349 frame.push_back((uint8_t) (m_physicaladdress & 0xFF));
abbca718
LOK
350 Transmit(frame);
351}
352
2abe74eb 353uint8_t CCECProcessor::GetSourceDestination(cec_logical_address destination /* = CECDEVICE_BROADCAST */) const
abbca718 354{
2abe74eb 355 return ((uint8_t)m_iLogicalAddress << 4) + (uint8_t)destination;
abbca718
LOK
356}
357
25701fa6 358bool CCECProcessor::WaitForAck(uint32_t iTimeout /* = 1000 */)
abbca718
LOK
359{
360 bool bGotAck(false);
361 bool bError(false);
362
363 int64_t iNow = GetTimeMs();
25701fa6 364 int64_t iTargetTime = iNow + (uint64_t) iTimeout;
abbca718 365
25701fa6 366 while (!bGotAck && !bError && (iTimeout == 0 || iNow < iTargetTime))
abbca718 367 {
abbca718 368 cec_frame msg;
25701fa6
LOK
369 msg.clear();
370
a8f0bd18 371 while (!bGotAck && !bError && m_communication->Read(msg, iTimeout))
abbca718 372 {
25701fa6 373 uint8_t iCode = msg.data[0] & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK);
abbca718
LOK
374
375 switch (iCode)
376 {
377 case MSGCODE_COMMAND_ACCEPTED:
2abe74eb 378 m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_COMMAND_ACCEPTED");
abbca718
LOK
379 break;
380 case MSGCODE_TRANSMIT_SUCCEEDED:
2abe74eb 381 m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_TRANSMIT_SUCCEEDED");
abbca718
LOK
382 // TODO
383 bGotAck = true;
384 break;
385 case MSGCODE_RECEIVE_FAILED:
2abe74eb 386 m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_RECEIVE_FAILED");
abbca718
LOK
387 bError = true;
388 break;
389 case MSGCODE_COMMAND_REJECTED:
2abe74eb 390 m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_COMMAND_REJECTED");
abbca718
LOK
391 bError = true;
392 break;
393 case MSGCODE_TRANSMIT_FAILED_LINE:
2abe74eb 394 m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_LINE");
abbca718
LOK
395 bError = true;
396 break;
397 case MSGCODE_TRANSMIT_FAILED_ACK:
2abe74eb 398 m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_ACK");
abbca718
LOK
399 bError = true;
400 break;
401 case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
2abe74eb 402 m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA");
abbca718
LOK
403 bError = true;
404 break;
405 case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
2abe74eb 406 m_controller->AddLog(CEC_LOG_WARNING, "MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE");
abbca718
LOK
407 bError = true;
408 break;
409 default:
410 m_frameBuffer.Push(msg);
25701fa6 411 bGotAck = (msg.data[0] & MSGCODE_FRAME_ACK) != 0;
abbca718
LOK
412 break;
413 }
414 iNow = GetTimeMs();
415 }
416 }
417
418 return bGotAck && !bError;
419}
420
2abe74eb 421bool CCECProcessor::ParseMessage(cec_frame &msg)
abbca718 422{
60fa4578
LOK
423 bool bReturn(false);
424
25701fa6 425 if (msg.size == 0)
60fa4578 426 return bReturn;
abbca718
LOK
427
428 CStdString logStr;
25701fa6
LOK
429 uint8_t iCode = msg.data[0] & ~(MSGCODE_FRAME_EOM | MSGCODE_FRAME_ACK);
430 bool bEom = (msg.data[0] & MSGCODE_FRAME_EOM) != 0;
431 bool bAck = (msg.data[0] & MSGCODE_FRAME_ACK) != 0;
abbca718
LOK
432
433 switch(iCode)
434 {
435 case MSGCODE_NOTHING:
2abe74eb 436 m_controller->AddLog(CEC_LOG_DEBUG, "MSGCODE_NOTHING");
abbca718
LOK
437 break;
438 case MSGCODE_TIMEOUT_ERROR:
439 case MSGCODE_HIGH_ERROR:
440 case MSGCODE_LOW_ERROR:
441 {
442 if (iCode == MSGCODE_TIMEOUT_ERROR)
443 logStr = "MSGCODE_TIMEOUT";
444 else if (iCode == MSGCODE_HIGH_ERROR)
445 logStr = "MSGCODE_HIGH_ERROR";
446 else
447 logStr = "MSGCODE_LOW_ERROR";
448
25701fa6
LOK
449 int iLine = (msg.size >= 3) ? (msg.data[1] << 8) | (msg.data[2]) : 0;
450 uint32_t iTime = (msg.size >= 7) ? (msg.data[3] << 24) | (msg.data[4] << 16) | (msg.data[5] << 8) | (msg.data[6]) : 0;
abbca718
LOK
451 logStr.AppendFormat(" line:%i", iLine);
452 logStr.AppendFormat(" time:%u", iTime);
2abe74eb 453 m_controller->AddLog(CEC_LOG_WARNING, logStr.c_str());
abbca718
LOK
454 }
455 break;
456 case MSGCODE_FRAME_START:
457 {
458 logStr = "MSGCODE_FRAME_START";
459 m_currentframe.clear();
25701fa6 460 if (msg.size >= 2)
abbca718 461 {
25701fa6
LOK
462 int iInitiator = msg.data[1] >> 4;
463 int iDestination = msg.data[1] & 0xF;
abbca718
LOK
464 logStr.AppendFormat(" initiator:%u destination:%u ack:%s %s", iInitiator, iDestination, bAck ? "high" : "low", bEom ? "eom" : "");
465
25701fa6 466 m_currentframe.push_back(msg.data[1]);
abbca718 467 }
2abe74eb 468 m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
abbca718
LOK
469 }
470 break;
471 case MSGCODE_FRAME_DATA:
472 {
473 logStr = "MSGCODE_FRAME_DATA";
25701fa6 474 if (msg.size >= 2)
abbca718 475 {
25701fa6 476 uint8_t iData = msg.data[1];
abbca718
LOK
477 logStr.AppendFormat(" %02x", iData);
478 m_currentframe.push_back(iData);
479 }
2abe74eb 480 m_controller->AddLog(CEC_LOG_DEBUG, logStr.c_str());
abbca718
LOK
481 }
482 if (bEom)
60fa4578 483 bReturn = true;
abbca718
LOK
484 break;
485 default:
486 break;
487 }
60fa4578
LOK
488
489 return bReturn;
abbca718
LOK
490}
491
2abe74eb 492void CCECProcessor::ParseCurrentFrame(void)
abbca718 493{
25701fa6
LOK
494 uint8_t initiator = m_currentframe.data[0] >> 4;
495 uint8_t destination = m_currentframe.data[0] & 0xF;
abbca718
LOK
496
497 CStdString dataStr;
498 dataStr.Format("received frame: initiator: %u destination: %u", initiator, destination);
499
25701fa6 500 if (m_currentframe.size > 1)
abbca718
LOK
501 {
502 dataStr += " data:";
25701fa6
LOK
503 for (unsigned int i = 1; i < m_currentframe.size; i++)
504 dataStr.AppendFormat(" %02x", m_currentframe.data[i]);
abbca718 505 }
2abe74eb 506 m_controller->AddLog(CEC_LOG_DEBUG, dataStr.c_str());
abbca718 507
25701fa6 508 if (m_currentframe.size <= 1)
abbca718
LOK
509 return;
510
25701fa6 511 cec_opcode opCode = (cec_opcode) m_currentframe.data[1];
abbca718
LOK
512 if (destination == (uint16_t) m_iLogicalAddress)
513 {
514 switch(opCode)
515 {
516 case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
517 ReportPhysicalAddress();
518 SetActiveView();
519 break;
520 case CEC_OPCODE_GIVE_OSD_NAME:
521 ReportOSDName((cec_logical_address)initiator);
522 break;
523 case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
524 ReportVendorID((cec_logical_address)initiator);
525 break;
526 case CEC_OPCODE_MENU_REQUEST:
527 ReportMenuState((cec_logical_address)initiator);
528 break;
529 case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
530 ReportPowerState((cec_logical_address)initiator);
531 break;
532 case CEC_OPCODE_GET_CEC_VERSION:
533 ReportCECVersion((cec_logical_address)initiator);
534 break;
535 case CEC_OPCODE_USER_CONTROL_PRESSED:
25701fa6 536 if (m_currentframe.size > 2)
abbca718 537 {
2abe74eb 538 m_controller->AddKey();
abbca718 539
25701fa6
LOK
540 if (m_currentframe.data[2] <= CEC_USER_CONTROL_CODE_MAX)
541 m_controller->SetCurrentButton((cec_user_control_code) m_currentframe.data[2]);
abbca718
LOK
542 }
543 break;
544 case CEC_OPCODE_USER_CONTROL_RELEASE:
2abe74eb 545 m_controller->AddKey();
abbca718
LOK
546 break;
547 default:
825ddb96 548 cec_frame params = m_currentframe;
25701fa6 549 params.shift(2);
2abe74eb 550 m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
abbca718
LOK
551 break;
552 }
553 }
554 else if (destination == (uint8_t) CECDEVICE_BROADCAST)
555 {
556 if (opCode == CEC_OPCODE_REQUEST_ACTIVE_SOURCE)
557 {
558 BroadcastActiveSource();
559 }
560 else if (opCode == CEC_OPCODE_SET_STREAM_PATH)
561 {
25701fa6 562 if (m_currentframe.size >= 4)
abbca718 563 {
25701fa6 564 int streamaddr = ((int)m_currentframe.data[2] << 8) | ((int)m_currentframe.data[3]);
abbca718
LOK
565 CStdString strLog;
566 strLog.Format("%i requests stream path from physical address %04x", initiator, streamaddr);
2abe74eb 567 m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
abbca718
LOK
568 if (streamaddr == m_physicaladdress)
569 BroadcastActiveSource();
570 }
571 }
c49c485b
LOK
572 else
573 {
574 cec_frame params = m_currentframe;
25701fa6 575 params.shift(2);
2abe74eb 576 m_controller->AddCommand((cec_logical_address) initiator, (cec_logical_address) destination, opCode, &params);
c49c485b 577 }
abbca718
LOK
578 }
579 else
580 {
581 CStdString strLog;
582 strLog.Format("ignoring frame: destination: %u != %u", destination, (uint16_t)m_iLogicalAddress);
2abe74eb 583 m_controller->AddLog(CEC_LOG_DEBUG, strLog.c_str());
abbca718
LOK
584 }
585}