2 * This file is part of the libCEC(R) library.
4 * libCEC(R) is Copyright (C) 2011-2012 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_NXP_API)
36 #include "NxpCECAdapterCommunication.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()
59 #define TRACE(a) LIB_CEC->AddLog a
64 // these are defined in nxp private header file
65 #define CEC_MSG_SUCCESS 0x00 /*Message transmisson Succeed*/
66 #define CEC_CSP_OFF_STATE 0x80 /*CSP in Off State*/
67 #define CEC_BAD_REQ_SERVICE 0x81 /*Bad .req service*/
68 #define CEC_MSG_FAIL_UNABLE_TO_ACCESS 0x82 /*Message transmisson failed: Unable to access CEC line*/
69 #define CEC_MSG_FAIL_ARBITRATION_ERROR 0x83 /*Message transmisson failed: Arbitration error*/
70 #define CEC_MSG_FAIL_BIT_TIMMING_ERROR 0x84 /*Message transmisson failed: Bit timming error*/
71 #define CEC_MSG_FAIL_DEST_NOT_ACK 0x85 /*Message transmisson failed: Destination Address not aknowledged*/
72 #define CEC_MSG_FAIL_DATA_NOT_ACK 0x86 /*Message transmisson failed: Databyte not acknowledged*/
75 CNxpCECAdapterCommunication::CNxpCECAdapterCommunication(IAdapterCommunicationCallback
*callback
, const char *UNUSED(device
)) :
76 IAdapterCommunication(callback
),
77 m_bLogicalAddressChanged(false)
79 TRACE((CEC_LOG_DEBUG
, "%s called", __func__
));
81 CLockObject
lock(m_mutex
);
84 m_logicalAddresses
.Clear();
85 m_dev
= new CCDevSocket(CEC_NXP_PATH
);
89 CNxpCECAdapterCommunication::~CNxpCECAdapterCommunication(void)
91 TRACE((CEC_LOG_DEBUG
, "%s called", __func__
));
95 CLockObject
lock(m_mutex
);
101 bool CNxpCECAdapterCommunication::IsOpen(void)
103 return IsInitialised() && m_dev
->IsOpen();
107 bool CNxpCECAdapterCommunication::Open(uint32_t iTimeoutMs
, bool bSkipChecks
, bool bStartListening
)
109 TRACE((CEC_LOG_DEBUG
, "%s called (%d,%d,%d)", __func__
, iTimeoutMs
, bSkipChecks
, bStartListening
));
111 if (m_dev
->Open(iTimeoutMs
))
113 unsigned char raw_mode
= 0xff;
115 if (m_dev
->Ioctl(CEC_IOCTL_GET_RAW_MODE
, &raw_mode
) == 0)
118 if (m_dev
->Ioctl(CEC_IOCTL_SET_RAW_MODE
, &raw_mode
) == 0)
120 if (!bStartListening
|| CreateThread())
125 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_SET_RAW_MODE failed !", __func__
);
129 m_dev
->Ioctl(CEC_IOCTL_SET_RAW_MODE
, &raw_mode
);
133 LIB_CEC
->AddLog(CEC_LOG_ERROR
,
134 "%s: CEC_IOCTL_GET_RAW_MODE not supported. Please update your kernel.", __func__
);
144 void CNxpCECAdapterCommunication::Close(void)
146 TRACE((CEC_LOG_DEBUG
, "%s called", __func__
));
150 unsigned char raw_mode
= 0;
151 m_dev
->Ioctl(CEC_IOCTL_SET_RAW_MODE
, &raw_mode
);
157 std::string
CNxpCECAdapterCommunication::GetError(void) const
159 std::string
strError(m_strError
);
164 cec_adapter_message_state
CNxpCECAdapterCommunication::Write(
165 const cec_command
&data
, bool &UNUSED(bRetry
), uint8_t UNUSED(iLineTimeout
), bool UNUSED(bIsReply
))
168 CAdapterMessageQueueEntry
*entry
;
169 cec_adapter_message_state rc
= ADAPTER_MESSAGE_STATE_ERROR
;
171 TRACE((CEC_LOG_DEBUG
, "%s: %x->%x, %d,%d,%d OPC%02x TMO%d LEN%d [%02x,%02x,%02x,%02x...]", __func__
,
172 data
.initiator
, data
.destination
, data
.ack
, data
.eom
, data
.opcode_set
, data
.opcode
, data
.transmit_timeout
,
173 data
.parameters
.size
, data
.parameters
.data
[0], data
.parameters
.data
[1],data
.parameters
.data
[2],data
.parameters
.data
[3]));
175 if ((size_t)data
.parameters
.size
+ data
.opcode_set
> sizeof(frame
.data
))
177 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: data size too large !", __func__
);
178 return ADAPTER_MESSAGE_STATE_ERROR
;
183 frame
.addr
= (data
.initiator
<< 4) | (data
.destination
& 0x0f);
187 frame
.data
[0] = data
.opcode
;
190 memcpy(&frame
.data
[frame
.size
], data
.parameters
.data
, data
.parameters
.size
);
191 frame
.size
+= data
.parameters
.size
;
196 entry
= new CAdapterMessageQueueEntry(data
);
198 m_messageMutex
.Lock();
199 uint32_t msgKey
= ++m_iNextMessage
;
200 m_messages
.insert(make_pair(msgKey
, entry
));
202 if (m_dev
->Write((char *)&frame
, sizeof(frame
)) == sizeof(frame
))
204 m_messageMutex
.Unlock();
206 if (entry
->Wait(CEC_DEFAULT_TRANSMIT_WAIT
))
208 uint32_t status
= entry
->Result();
210 if (status
== CEC_MSG_FAIL_DEST_NOT_ACK
)
211 rc
= ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED
;
212 else if (status
== CEC_MSG_SUCCESS
)
213 rc
= ADAPTER_MESSAGE_STATE_SENT_ACKED
;
215 TRACE((CEC_LOG_DEBUG
, "%s: reply received (0x%02x)", __func__
, status
));
218 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: command timed out !", __func__
);
220 m_messageMutex
.Lock();
223 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: write failed !", __func__
);
225 m_messages
.erase(msgKey
);
226 m_messageMutex
.Unlock();
234 uint16_t CNxpCECAdapterCommunication::GetFirmwareVersion(void)
236 cec_sw_version vers
= { 0 };
238 m_dev
->Ioctl(CEC_IOCTL_GET_SW_VERSION
, &vers
);
240 TRACE((CEC_LOG_DEBUG
,
241 "%s: %s comp: %08lX, major: %08lX, minor: %08lX", __func__
,
242 m_dev
->GetName().c_str(), vers
.compatibilityNr
, vers
.majorVersionNr
, vers
.minorVersionNr
));
244 return (vers
.majorVersionNr
* 100) + vers
.minorVersionNr
;
248 cec_vendor_id
CNxpCECAdapterCommunication::GetVendorId(void)
252 if (m_dev
->Ioctl(CEC_IOCTL_GET_RAW_INFO
, &info
) != 0)
254 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__
);
255 return CEC_VENDOR_LG
;
258 TRACE((CEC_LOG_DEBUG
, "%s: Vendor=%08x", __func__
, info
.VendorID
));
260 return cec_vendor_id(info
.VendorID
);
264 uint16_t CNxpCECAdapterCommunication::GetPhysicalAddress(void)
268 if (m_dev
->Ioctl(CEC_IOCTL_GET_RAW_INFO
, &info
) != 0)
270 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__
);
271 return CEC_INVALID_PHYSICAL_ADDRESS
;
274 TRACE((CEC_LOG_DEBUG
, "%s: PhysAddr=%x", __func__
, info
.PhysicalAddress
));
276 return info
.PhysicalAddress
;
280 cec_logical_addresses
CNxpCECAdapterCommunication::GetLogicalAddresses(void)
282 CLockObject
lock(m_mutex
);
284 if (m_bLogicalAddressChanged
|| m_logicalAddresses
.IsEmpty() )
288 m_logicalAddresses
.Clear();
290 if (m_dev
->Ioctl(CEC_IOCTL_GET_RAW_INFO
, &info
) != 0)
292 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_GET_RAW_INFO failed !", __func__
);
294 else if (info
.LogicalAddress
!= CECDEVICE_UNREGISTERED
)
296 m_logicalAddresses
.Set(cec_logical_address(info
.LogicalAddress
));
298 for (int la
= CECDEVICE_TV
; la
< CECDEVICE_BROADCAST
; la
++)
300 m_logicalAddresses
.Set(cec_logical_address(la
));
304 m_bLogicalAddressChanged
= false;
307 TRACE((CEC_LOG_DEBUG
, "%s: LogAddr=%d", __func__
, (int)m_logicalAddresses
.primary
));
309 return m_logicalAddresses
;
313 bool CNxpCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses
&addresses
)
315 TRACE((CEC_LOG_DEBUG
, "%s: LogAddr=%d", __func__
, addresses
.primary
));
317 unsigned char log_addr
= addresses
.primary
;
319 if (m_dev
->Ioctl(CEC_IOCTL_RX_ADDR
, &log_addr
) != 0)
321 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_RX_ADDR failed !", __func__
);
325 cec_rx_mask all_addresses
;
327 all_addresses
.SwitchOn
= addresses
.AckMask() & 0x7fff;
328 all_addresses
.SwitchOff
= ~all_addresses
.SwitchOn
;
330 if (all_addresses
.SwitchOn
!= (1 << addresses
.primary
) &&
331 m_dev
->Ioctl(CEC_IOCTL_SET_RX_ADDR_MASK
, &all_addresses
) != 0)
333 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_SET_RX_ADDR_MASK failed !", __func__
);
337 m_bLogicalAddressChanged
= true;
343 void CNxpCECAdapterCommunication::HandleLogicalAddressLost(cec_logical_address oldAddress
)
345 TRACE((CEC_LOG_DEBUG
, "%s: LogAddr=%d", __func__
, (int)oldAddress
));
347 unsigned char log_addr
= CECDEVICE_BROADCAST
;
349 if (m_dev
->Ioctl(CEC_IOCTL_RX_ADDR
, &log_addr
) != 0)
351 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s: CEC_IOCTL_RX_ADDR failed !", __func__
);
356 void *CNxpCECAdapterCommunication::Process(void)
360 uint32_t opcode
, status
;
361 cec_logical_address initiator
, destination
;
365 if (m_dev
->Read((char *)&frame
, sizeof(frame
), 500) == sizeof(frame
))
367 initiator
= cec_logical_address(frame
.addr
>> 4);
368 destination
= cec_logical_address(frame
.addr
& 0x0f);
370 TRACE((CEC_LOG_DEBUG
,
371 "%s: frame received [%x->%x] (srvc=%d, len=%d)",
372 __func__
, initiator
, destination
, frame
.service
, frame
.size
));
374 if (frame
.service
== CEC_RX_PKT
)
379 cmd
, initiator
, destination
,
380 ( frame
.size
> 3 ) ? cec_opcode(frame
.data
[0]) : CEC_OPCODE_NONE
);
382 for( uint8_t i
= 1; i
< frame
.size
-3; i
++ )
383 cmd
.parameters
.PushBack(frame
.data
[i
]);
385 m_callback
->OnCommandReceived(cmd
);
387 else if (frame
.service
== CEC_ACK_PKT
)
390 status
= ( frame
.size
> 3 ) ? frame
.data
[0] : 255;
391 opcode
= ( frame
.size
> 4 ) ? frame
.data
[1] : (uint32_t)CEC_OPCODE_NONE
;
393 m_messageMutex
.Lock();
394 for (map
<uint32_t, CAdapterMessageQueueEntry
*>::iterator it
= m_messages
.begin();
395 !bHandled
&& it
!= m_messages
.end(); it
++)
397 bHandled
= it
->second
->CheckMatch(opcode
, initiator
, destination
, status
);
399 m_messageMutex
.Unlock();
402 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "%s: unhandled response received !", __func__
);
411 #endif // HAVE_NXP_API