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_TDA995X_API)
36 #include "TDA995xCECAdapterCommunication.h"
38 #include "lib/CECTypeUtils.h"
39 #include "lib/LibCEC.h"
40 #include "lib/platform/sockets/cdevsocket.h"
41 #include "lib/platform/util/StdString.h"
42 #include "lib/platform/util/buffer.h"
46 #include <../comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h>
47 #include <../tda998x_ioctl.h>
52 using namespace PLATFORM
;
54 #include "AdapterMessageQueue.h"
56 #define LIB_CEC m_callback->GetLib()
58 // these are defined in nxp private header file
59 #define CEC_MSG_SUCCESS 0x00 /*Message transmisson Succeed*/
60 #define CEC_CSP_OFF_STATE 0x80 /*CSP in Off State*/
61 #define CEC_BAD_REQ_SERVICE 0x81 /*Bad .req service*/
62 #define CEC_MSG_FAIL_UNABLE_TO_ACCESS 0x82 /*Message transmisson failed: Unable to access CEC line*/
63 #define CEC_MSG_FAIL_ARBITRATION_ERROR 0x83 /*Message transmisson failed: Arbitration error*/
64 #define CEC_MSG_FAIL_BIT_TIMMING_ERROR 0x84 /*Message transmisson failed: Bit timming error*/
65 #define CEC_MSG_FAIL_DEST_NOT_ACK 0x85 /*Message transmisson failed: Destination Address not aknowledged*/
66 #define CEC_MSG_FAIL_DATA_NOT_ACK 0x86 /*Message transmisson failed: Databyte not acknowledged*/
69 CTDA995xCECAdapterCommunication::CTDA995xCECAdapterCommunication(IAdapterCommunicationCallback
*callback
) :
70 IAdapterCommunication(callback
),
71 m_bLogicalAddressChanged(false)
73 CLockObject
lock(m_mutex
);
76 m_logicalAddresses
.Clear();
77 m_dev
= new CCDevSocket(CEC_TDA995x_PATH
);
81 CTDA995xCECAdapterCommunication::~CTDA995xCECAdapterCommunication(void)
85 CLockObject
lock(m_mutex
);
91 bool CTDA995xCECAdapterCommunication::IsOpen(void)
93 return IsInitialised() && m_dev
->IsOpen();
97 bool CTDA995xCECAdapterCommunication::Open(uint32_t iTimeoutMs
, bool UNUSED(bSkipChecks
), bool bStartListening
)
99 if (m_dev
->Open(iTimeoutMs
))
101 unsigned char raw_mode
= 0xff;
103 if (m_dev
->Ioctl(CEC_IOCTL_GET_RAW_MODE
, &raw_mode
) == 0)
106 if (m_dev
->Ioctl(CEC_IOCTL_SET_RAW_MODE
, &raw_mode
) == 0)
108 if (!bStartListening
|| CreateThread())
113 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_SET_RAW_MODE failed !", __func__
);
117 m_dev
->Ioctl(CEC_IOCTL_SET_RAW_MODE
, &raw_mode
);
121 LIB_CEC
->AddLog(CEC_LOG_ERROR
,
122 "%s: CEC_IOCTL_GET_RAW_MODE not supported. Please update your kernel.", __func__
);
132 void CTDA995xCECAdapterCommunication::Close(void)
136 unsigned char raw_mode
= 0;
137 m_dev
->Ioctl(CEC_IOCTL_SET_RAW_MODE
, &raw_mode
);
143 std::string
CTDA995xCECAdapterCommunication::GetError(void) const
145 std::string
strError(m_strError
);
150 cec_adapter_message_state
CTDA995xCECAdapterCommunication::Write(
151 const cec_command
&data
, bool &UNUSED(bRetry
), uint8_t UNUSED(iLineTimeout
), bool UNUSED(bIsReply
))
154 CAdapterMessageQueueEntry
*entry
;
155 cec_adapter_message_state rc
= ADAPTER_MESSAGE_STATE_ERROR
;
157 if ((size_t)data
.parameters
.size
+ data
.opcode_set
> sizeof(frame
.data
))
159 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: data size too large !", __func__
);
160 return ADAPTER_MESSAGE_STATE_ERROR
;
165 frame
.addr
= (data
.initiator
<< 4) | (data
.destination
& 0x0f);
169 frame
.data
[0] = data
.opcode
;
172 memcpy(&frame
.data
[frame
.size
], data
.parameters
.data
, data
.parameters
.size
);
173 frame
.size
+= data
.parameters
.size
;
178 entry
= new CAdapterMessageQueueEntry(data
);
180 m_messageMutex
.Lock();
181 uint32_t msgKey
= ++m_iNextMessage
;
182 m_messages
.insert(make_pair(msgKey
, entry
));
184 if (m_dev
->Write((char *)&frame
, sizeof(frame
)) == sizeof(frame
))
186 m_messageMutex
.Unlock();
188 if (entry
->Wait(CEC_DEFAULT_TRANSMIT_WAIT
))
190 uint32_t status
= entry
->Result();
192 if (status
== CEC_MSG_FAIL_DEST_NOT_ACK
)
193 rc
= ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED
;
194 else if (status
== CEC_MSG_SUCCESS
)
195 rc
= ADAPTER_MESSAGE_STATE_SENT_ACKED
;
198 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: command timed out !", __func__
);
200 m_messageMutex
.Lock();
203 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: write failed !", __func__
);
205 m_messages
.erase(msgKey
);
206 m_messageMutex
.Unlock();
214 uint16_t CTDA995xCECAdapterCommunication::GetFirmwareVersion(void)
216 cec_sw_version vers
= { 0 };
218 m_dev
->Ioctl(CEC_IOCTL_GET_SW_VERSION
, &vers
);
220 return vers
.majorVersionNr
;
224 cec_vendor_id
CTDA995xCECAdapterCommunication::GetVendorId(void)
228 if (m_dev
->Ioctl(CEC_IOCTL_GET_RAW_INFO
, &info
) != 0)
230 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__
);
231 return CEC_VENDOR_LG
;
234 return cec_vendor_id(info
.VendorID
);
238 uint16_t CTDA995xCECAdapterCommunication::GetPhysicalAddress(void)
242 if (m_dev
->Ioctl(CEC_IOCTL_GET_RAW_INFO
, &info
) != 0)
244 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__
);
245 return CEC_INVALID_PHYSICAL_ADDRESS
;
248 return info
.PhysicalAddress
;
252 cec_logical_addresses
CTDA995xCECAdapterCommunication::GetLogicalAddresses(void)
254 CLockObject
lock(m_mutex
);
256 if (m_bLogicalAddressChanged
|| m_logicalAddresses
.IsEmpty() )
260 m_logicalAddresses
.Clear();
262 if (m_dev
->Ioctl(CEC_IOCTL_GET_RAW_INFO
, &info
) != 0)
264 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__
);
266 else if (info
.LogicalAddress
!= CECDEVICE_UNREGISTERED
)
268 m_logicalAddresses
.Set(cec_logical_address(info
.LogicalAddress
));
270 for (int la
= CECDEVICE_TV
; la
< CECDEVICE_BROADCAST
; la
++)
272 m_logicalAddresses
.Set(cec_logical_address(la
));
276 m_bLogicalAddressChanged
= false;
279 return m_logicalAddresses
;
283 bool CTDA995xCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses
&addresses
)
285 unsigned char log_addr
= addresses
.primary
;
287 if (m_dev
->Ioctl(CEC_IOCTL_RX_ADDR
, &log_addr
) != 0)
289 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_RX_ADDR failed !", __func__
);
293 cec_rx_mask all_addresses
;
295 all_addresses
.SwitchOn
= addresses
.AckMask() & 0x7fff;
296 all_addresses
.SwitchOff
= ~all_addresses
.SwitchOn
;
298 if (all_addresses
.SwitchOn
!= (1 << addresses
.primary
) &&
299 m_dev
->Ioctl(CEC_IOCTL_SET_RX_ADDR_MASK
, &all_addresses
) != 0)
301 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_SET_RX_ADDR_MASK failed !", __func__
);
305 m_bLogicalAddressChanged
= true;
311 void CTDA995xCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address
UNUSED(oldAddress
))
313 unsigned char log_addr
= CECDEVICE_BROADCAST
;
315 if (m_dev
->Ioctl(CEC_IOCTL_RX_ADDR
, &log_addr
) != 0)
317 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_RX_ADDR failed !", __func__
);
322 void *CTDA995xCECAdapterCommunication::Process(void)
326 uint32_t opcode
, status
;
327 cec_logical_address initiator
, destination
;
331 if (m_dev
->Read((char *)&frame
, sizeof(frame
), 500) == sizeof(frame
))
333 initiator
= cec_logical_address(frame
.addr
>> 4);
334 destination
= cec_logical_address(frame
.addr
& 0x0f);
336 if (frame
.service
== CEC_RX_PKT
)
341 cmd
, initiator
, destination
,
342 ( frame
.size
> 3 ) ? cec_opcode(frame
.data
[0]) : CEC_OPCODE_NONE
);
344 for( uint8_t i
= 1; i
< frame
.size
-3; i
++ )
345 cmd
.parameters
.PushBack(frame
.data
[i
]);
347 m_callback
->OnCommandReceived(cmd
);
349 else if (frame
.service
== CEC_ACK_PKT
)
352 status
= ( frame
.size
> 3 ) ? frame
.data
[0] : 255;
353 opcode
= ( frame
.size
> 4 ) ? frame
.data
[1] : (uint32_t)CEC_OPCODE_NONE
;
355 m_messageMutex
.Lock();
356 for (map
<uint32_t, CAdapterMessageQueueEntry
*>::iterator it
= m_messages
.begin();
357 !bHandled
&& it
!= m_messages
.end(); it
++)
359 bHandled
= it
->second
->CheckMatch(opcode
, initiator
, destination
, status
);
361 m_messageMutex
.Unlock();
364 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "%s: unhandled response received !", __func__
);
372 #endif // HAVE_TDA995X_API