2 * This file is part of the libCEC(R) library.
4 * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
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.
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.
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.
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
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/
35 #if defined(HAVE_RPI_API)
36 #include "RPiCECAdapterMessageQueue.h"
38 // use vc_cec_send_message2() if defined and vc_cec_send_message() if not
39 //#define RPI_USE_SEND_MESSAGE2
41 #include "RPiCECAdapterCommunication.h"
42 #include "lib/LibCEC.h"
43 #include "lib/CECTypeUtils.h"
44 #include "lib/platform/util/StdString.h"
47 #include <interface/vmcs_host/vc_cecservice.h>
48 #include <interface/vchiq_arm/vchiq.h>
53 using namespace PLATFORM
;
55 #define LIB_CEC m_com->m_callback->GetLib()
57 CRPiCECAdapterMessageQueueEntry::CRPiCECAdapterMessageQueueEntry(CRPiCECAdapterMessageQueue
*queue
, const cec_command
&command
) :
60 m_retval(VC_CEC_ERROR_NO_ACK
),
66 void CRPiCECAdapterMessageQueueEntry::Broadcast(void)
68 CLockObject
lock(m_mutex
);
69 m_condition
.Broadcast();
72 bool CRPiCECAdapterMessageQueueEntry::MessageReceived(cec_opcode opcode
, cec_logical_address initiator
, cec_logical_address destination
, uint32_t response
)
74 if ((!m_command
.opcode_set
|| m_command
.opcode
== opcode
) &&
75 m_command
.initiator
== initiator
&&
76 m_command
.destination
== destination
)
78 CLockObject
lock(m_mutex
);
88 bool CRPiCECAdapterMessageQueueEntry::Wait(uint32_t iTimeout
)
91 /* wait until we receive a signal when the tranmission succeeded */
93 CLockObject
lock(m_mutex
);
94 bReturn
= m_bSucceeded
? true : m_condition
.Wait(m_mutex
, m_bSucceeded
, iTimeout
);
98 bReturn
= m_retval
== VCHIQ_SUCCESS
;
103 bool CRPiCECAdapterMessageQueueEntry::IsWaiting(void)
105 CLockObject
lock(m_mutex
);
109 void CRPiCECAdapterMessageQueue::Clear(void)
111 CLockObject
lock(m_mutex
);
115 void CRPiCECAdapterMessageQueue::MessageReceived(cec_opcode opcode
, cec_logical_address initiator
, cec_logical_address destination
, uint32_t response
)
117 bool bHandled(false);
118 CLockObject
lock(m_mutex
);
119 /* send the received message to each entry in the queue until it is handled */
120 for (map
<uint64_t, CRPiCECAdapterMessageQueueEntry
*>::iterator it
= m_messages
.begin(); !bHandled
&& it
!= m_messages
.end(); it
++)
121 bHandled
= it
->second
->MessageReceived(opcode
, initiator
, destination
, response
);
124 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "unhandled response received: opcode=%x initiator=%x destination=%x response=%x", (int)opcode
, (int)initiator
, (int)destination
, response
);
127 bool CRPiCECAdapterMessageQueue::Write(const cec_command
&command
, bool bIsReply
)
129 CRPiCECAdapterMessageQueueEntry
*entry
= new CRPiCECAdapterMessageQueueEntry(this, command
);
130 uint64_t iEntryId(0);
131 /* add to the wait for ack queue */
133 CLockObject
lock(m_mutex
);
134 iEntryId
= m_iNextMessage
++;
135 m_messages
.insert(make_pair(iEntryId
, entry
));
138 #if defined(RPI_USE_SEND_MESSAGE2)
139 VC_CEC_MESSAGE_T message
;
140 message
.initiator
= (CEC_AllDevices_T
)command
.initiator
;
141 message
.follower
= (CEC_AllDevices_T
)command
.destination
;
144 if (command
.opcode_set
)
147 message
.payload
[0] = command
.opcode
;
149 message
.length
+= command
.parameters
.size
;
150 for (uint8_t iPtr
= 0; iPtr
< command
.parameters
.size
; iPtr
++)
151 message
.payload
[iPtr
+ 1] = command
.parameters
.At(iPtr
);
156 strDump
.Format("len = %d, payload = %X%X", message
.length
, (int)message
.initiator
, (int)message
.follower
);
157 for (uint8_t iPtr
= 0; iPtr
< message
.length
- 1; iPtr
++)
158 strDump
.AppendFormat(":%02X", message
.payload
[iPtr
]);
159 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "sending data: %s", strDump
.c_str());
162 int iReturn
= vc_cec_send_message2(&message
);
167 if (command
.opcode_set
)
170 payload
[0] = command
.opcode
;
172 iLength
+= command
.parameters
.size
;
173 for (uint8_t iPtr
= 0; iPtr
< command
.parameters
.size
; iPtr
++)
174 payload
[iPtr
+ 1] = command
.parameters
.At(iPtr
);
179 strDump
.Format("len = %d, payload = %X%X", iLength
, (int)command
.initiator
, (int)command
.destination
);
180 for (uint8_t iPtr
= 0; iPtr
< iLength
; iPtr
++)
181 strDump
.AppendFormat(":%02X", payload
[iPtr
]);
182 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "sending data: %s", strDump
.c_str());
185 int iReturn
= vc_cec_send_message((uint32_t)command
.destination
, (uint8_t*)&payload
, iLength
, bIsReply
);
188 if (iReturn
!= VCHIQ_SUCCESS
)
190 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "sending command '%s' failed (%d)", command
.opcode_set
? CCECTypeUtils::ToString(command
.opcode
) : "POLL", iReturn
);
198 if (!entry
->Wait(CEC_DEFAULT_TRANSMIT_WAIT
))
200 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "command '%s' was not acked by the controller", command
.opcode_set
? CCECTypeUtils::ToString(command
.opcode
) : "POLL");
204 CLockObject
lock(m_mutex
);
205 m_messages
.erase(iEntryId
);