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/
34 #include "USBCECAdapterCommunication.h"
36 #include "USBCECAdapterCommands.h"
37 #include "USBCECAdapterMessageQueue.h"
38 #include "USBCECAdapterMessage.h"
39 #include "USBCECAdapterDetection.h"
40 #include "lib/platform/sockets/serialport.h"
41 #include "lib/platform/util/timeutils.h"
42 #include "lib/platform/util/util.h"
43 #include "lib/platform/util/edid.h"
44 #include "lib/platform/adl/adl-edid.h"
45 #include "lib/platform/nvidia/nv-edid.h"
46 #include "lib/LibCEC.h"
47 #include "lib/CECProcessor.h"
51 using namespace PLATFORM
;
53 #define CEC_ADAPTER_PING_TIMEOUT 15000
54 #define CEC_ADAPTER_EEPROM_WRITE_INTERVAL 30000
55 #define CEC_ADAPTER_EEPROM_WRITE_RETRY 5000
58 #define CEC_LATEST_ADAPTER_FW_VERSION 2
59 // firmware date Thu Aug 2 08:31:24 UTC 2012
60 #define CEC_LATEST_ADAPTER_FW_DATE 0x501a4b0c
62 #define CEC_FW_DATE_EXTENDED_RESPONSE 0x501a4b0c
63 #define CEC_FW_DATE_DESCRIPTOR2 0x5045dbf5
65 #define LIB_CEC m_callback->GetLib()
67 CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCallback
*callback
, const char *strPort
, uint16_t iBaudRate
/* = CEC_SERIAL_DEFAULT_BAUDRATE */) :
68 IAdapterCommunication(callback
),
71 m_lastPollDestination(CECDEVICE_UNKNOWN
),
72 m_bInitialised(false),
74 m_eepromWriteThread(NULL
),
76 m_adapterMessageQueue(NULL
)
78 m_logicalAddresses
.Clear();
79 for (unsigned int iPtr
= CECDEVICE_TV
; iPtr
< CECDEVICE_BROADCAST
; iPtr
++)
80 m_bWaitingForAck
[iPtr
] = false;
81 m_port
= new CSerialPort(strPort
, iBaudRate
);
82 m_commands
= new CUSBCECAdapterCommands(this);
85 CUSBCECAdapterCommunication::~CUSBCECAdapterCommunication(void)
88 DELETE_AND_NULL(m_commands
);
89 DELETE_AND_NULL(m_adapterMessageQueue
);
90 DELETE_AND_NULL(m_port
);
93 void CUSBCECAdapterCommunication::ResetMessageQueue(void)
95 DELETE_AND_NULL(m_adapterMessageQueue
);
96 m_adapterMessageQueue
= new CCECAdapterMessageQueue(this);
97 m_adapterMessageQueue
->CreateThread();
100 bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs
/* = CEC_DEFAULT_CONNECT_TIMEOUT */, bool bSkipChecks
/* = false */, bool bStartListening
/* = true */)
102 bool bConnectionOpened(false);
104 CLockObject
lock(m_mutex
);
106 /* we need the port settings here */
109 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "port is NULL");
110 return bConnectionOpened
;
113 /* return true when the port is already open */
116 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "port is already open");
122 /* try to open the connection */
124 CTimeout
timeout(iTimeoutMs
);
125 while (!bConnectionOpened
&& timeout
.TimeLeft() > 0)
127 if ((bConnectionOpened
= m_port
->Open(timeout
.TimeLeft())) == false)
129 strError
.Format("error opening serial port '%s': %s", m_port
->GetName().c_str(), m_port
->GetError().c_str());
132 /* and retry every 250ms until the timeout passed */
135 /* return false when we couldn't connect */
136 if (!bConnectionOpened
)
138 LIB_CEC
->AddLog(CEC_LOG_ERROR
, strError
);
140 if (m_port
->GetErrorNumber() == EACCES
)
142 libcec_parameter param
;
143 param
.paramType
= CEC_PARAMETER_TYPE_STRING
;
144 param
.paramData
= (void*)"No permission to open the device";
145 LIB_CEC
->Alert(CEC_ALERT_PERMISSION_ERROR
, param
);
147 else if (m_port
->GetErrorNumber() == EBUSY
)
149 libcec_parameter param
;
150 param
.paramType
= CEC_PARAMETER_TYPE_STRING
;
151 param
.paramData
= (void*)"The serial port is busy. Only one program can access the device directly.";
152 LIB_CEC
->Alert(CEC_ALERT_PORT_BUSY
, param
);
157 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
161 // always start by setting the ackmask to 0, to clear previous values
162 cec_logical_addresses addresses
; addresses
.Clear();
163 SetLogicalAddresses(addresses
);
167 bConnectionOpened
= false;
168 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "could not create a communication thread");
170 else if (!bSkipChecks
&& !CheckAdapter())
172 bConnectionOpened
= false;
173 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "the adapter failed to pass basic checks");
175 else if (bStartListening
)
177 /* start the eeprom write thread, that handles all eeprom writes async */
178 m_eepromWriteThread
= new CAdapterEepromWriteThread(this);
179 if (!m_eepromWriteThread
->CreateThread())
181 bConnectionOpened
= false;
182 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "could not create the eeprom write thread");
186 /* start a ping thread, that will ping the adapter every 15 seconds
187 if it doesn't receive any ping for 30 seconds, it'll switch to auto mode */
188 m_pingThread
= new CAdapterPingThread(this, CEC_ADAPTER_PING_TIMEOUT
);
189 if (m_pingThread
->CreateThread())
191 bConnectionOpened
= true;
195 bConnectionOpened
= false;
196 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "could not create a ping thread");
201 if (!bConnectionOpened
|| !bStartListening
)
204 return bConnectionOpened
;
207 void CUSBCECAdapterCommunication::Close(void)
209 /* stop the reader thread */
212 CLockObject
lock(m_mutex
);
214 /* set the ackmask to 0 before closing the connection */
215 if (IsOpen() && m_port
->GetErrorNumber() == 0)
217 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - closing the connection", __FUNCTION__
);
218 cec_logical_addresses addresses
; addresses
.Clear();
219 SetLogicalAddresses(addresses
);
220 if (m_commands
->GetFirmwareVersion() >= 2)
221 SetControlledMode(false);
224 m_adapterMessageQueue
->Clear();
226 /* stop and delete the write thread */
227 if (m_eepromWriteThread
)
228 m_eepromWriteThread
->Stop();
229 DELETE_AND_NULL(m_eepromWriteThread
);
231 /* stop and delete the ping thread */
232 DELETE_AND_NULL(m_pingThread
);
234 /* close and delete the com port connection */
239 cec_adapter_message_state
CUSBCECAdapterCommunication::Write(const cec_command
&data
, bool &bRetry
, uint8_t iLineTimeout
, bool bIsReply
)
241 cec_adapter_message_state
retVal(ADAPTER_MESSAGE_STATE_UNKNOWN
);
245 CCECAdapterMessage
*output
= new CCECAdapterMessage(data
, iLineTimeout
);
246 output
->bFireAndForget
= bIsReply
;
248 /* mark as waiting for an ack from the destination */
249 MarkAsWaiting(data
.destination
);
251 /* send the message */
254 retVal
= m_adapterMessageQueue
->Write(output
) ?
255 ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT
: ADAPTER_MESSAGE_STATE_ERROR
;
259 bRetry
= (!m_adapterMessageQueue
->Write(output
) || output
->NeedsRetry()) && output
->transmit_timeout
> 0;
261 Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT
);
262 retVal
= output
->state
;
269 void *CUSBCECAdapterCommunication::Process(void)
271 CCECAdapterMessage msg
;
272 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "communication thread started");
276 /* read from the serial port */
277 if (!ReadFromDevice(50, 5))
279 libcec_parameter param
;
280 param
.paramData
= NULL
; param
.paramType
= CEC_PARAMETER_TYPE_UNKOWN
;
281 LIB_CEC
->Alert(CEC_ALERT_CONNECTION_LOST
, param
);
286 /* TODO sleep 5 ms so other threads can get a lock */
291 m_adapterMessageQueue
->Clear();
292 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "communication thread ended");
296 bool CUSBCECAdapterCommunication::HandlePoll(const CCECAdapterMessage
&msg
)
298 bool bIsError(msg
.IsError());
299 cec_adapter_messagecode
messageCode(msg
.Message());
300 CLockObject
lock(m_mutex
);
302 if (messageCode
== MSGCODE_FRAME_START
&& msg
.IsACK())
304 m_lastPollDestination
= msg
.Destination();
305 if (msg
.Destination() < CECDEVICE_BROADCAST
)
307 if (!m_bWaitingForAck
[msg
.Destination()] && !msg
.IsEOM())
310 m_callback
->HandlePoll(msg
.Initiator(), msg
.Destination());
313 m_bWaitingForAck
[msg
.Destination()] = false;
316 else if (messageCode
== MSGCODE_RECEIVE_FAILED
)
318 /* hack to suppress warnings when an LG is polling */
319 if (m_lastPollDestination
!= CECDEVICE_UNKNOWN
)
320 bIsError
= m_callback
->HandleReceiveFailed(m_lastPollDestination
);
326 void CUSBCECAdapterCommunication::MarkAsWaiting(const cec_logical_address dest
)
328 /* mark as waiting for an ack from the destination */
329 if (dest
< CECDEVICE_BROADCAST
)
331 CLockObject
lock(m_mutex
);
332 m_bWaitingForAck
[dest
] = true;
336 void CUSBCECAdapterCommunication::ClearInputBytes(uint32_t iTimeout
/* = CEC_CLEAR_INPUT_DEFAULT_WAIT */)
338 CTimeout
timeout(iTimeout
);
340 ssize_t
iBytesRead(0);
341 bool bGotMsgEnd(true);
343 while (timeout
.TimeLeft() > 0 && ((iBytesRead
= m_port
->Read(buff
, 1024, 5)) > 0 || !bGotMsgEnd
))
346 /* if something was received, wait for MSGEND */
347 for (ssize_t iPtr
= 0; iPtr
< iBytesRead
; iPtr
++)
348 bGotMsgEnd
= buff
[iPtr
] == MSGEND
;
352 bool CUSBCECAdapterCommunication::SetLineTimeout(uint8_t iTimeout
)
355 bool bChanged(false);
357 /* only send the command if the timeout changed */
359 CLockObject
lock(m_mutex
);
360 bChanged
= (m_iLineTimeout
!= iTimeout
);
361 m_iLineTimeout
= iTimeout
;
365 bReturn
= m_commands
->SetLineTimeout(iTimeout
);
370 bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage
*message
)
372 CLockObject
adapterLock(m_mutex
);
375 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "error writing command '%s' to serial port '%s': the connection is closed", CCECAdapterMessage::ToString(message
->Message()), m_port
->GetName().c_str());
376 message
->state
= ADAPTER_MESSAGE_STATE_ERROR
;
380 /* write the message */
381 if (m_port
->Write(message
->packet
.data
, message
->Size()) != (ssize_t
) message
->Size())
383 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message
->Message()), m_port
->GetName().c_str(), m_port
->GetError().c_str());
384 message
->state
= ADAPTER_MESSAGE_STATE_ERROR
;
385 // this will trigger an alert in the reader thread
391 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "command '%s' sent", message
->IsTranmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message
->Message()));
393 message
->state
= ADAPTER_MESSAGE_STATE_SENT
;
397 bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout
, size_t iSize
/* = 256 */)
399 ssize_t
iBytesRead(0);
404 /* read from the serial port */
406 CLockObject
lock(m_mutex
);
411 /* retry Read() if it was interrupted */
412 iBytesRead
= m_port
->Read(buff
, sizeof(uint8_t) * iSize
, iTimeout
);
413 } while(m_port
->GetErrorNumber() == EINTR
);
416 if (m_port
->GetErrorNumber())
418 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "error reading from serial port: %s", m_port
->GetError().c_str());
424 if (iBytesRead
< 0 || iBytesRead
> 256)
426 else if (iBytesRead
> 0)
428 /* add the data to the current frame */
429 m_adapterMessageQueue
->AddData(buff
, iBytesRead
);
435 CCECAdapterMessage
*CUSBCECAdapterCommunication::SendCommand(cec_adapter_messagecode msgCode
, CCECAdapterMessage
¶ms
, bool bIsRetry
/* = false */)
437 if (!IsOpen() || !m_adapterMessageQueue
)
440 /* create the adapter message for this command */
441 CCECAdapterMessage
*output
= new CCECAdapterMessage
;
442 output
->PushBack(MSGSTART
);
443 output
->PushEscaped((uint8_t)msgCode
);
444 output
->Append(params
);
445 output
->PushBack(MSGEND
);
447 /* write the command */
448 if (!m_adapterMessageQueue
->Write(output
))
450 // this will trigger an alert in the reader thread
451 if (output
->state
== ADAPTER_MESSAGE_STATE_ERROR
)
457 if (!bIsRetry
&& output
->Reply() == MSGCODE_COMMAND_REJECTED
&& msgCode
!= MSGCODE_SET_CONTROLLED
&&
458 msgCode
!= MSGCODE_GET_BUILDDATE
/* same messagecode value had a different meaning in older fw builds */)
460 /* if the controller reported that the command was rejected, and we didn't send the command
461 to set controlled mode, then the controller probably switched to auto mode. set controlled
463 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "setting controlled mode and retrying");
465 if (SetControlledMode(true))
466 return SendCommand(msgCode
, params
, true);
473 bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs
/* = CEC_DEFAULT_CONNECT_TIMEOUT */)
476 CTimeout
timeout(iTimeoutMs
> 0 ? iTimeoutMs
: CEC_DEFAULT_TRANSMIT_WAIT
);
478 /* try to ping the adapter */
480 unsigned iPingTry(0);
481 while (timeout
.TimeLeft() > 0 && (bPinged
= PingAdapter()) == false)
483 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry
);
487 /* try to read the firmware version */
488 if (bPinged
&& timeout
.TimeLeft() > 0 && m_commands
->RequestFirmwareVersion() >= 2)
490 /* try to set controlled mode for v2+ firmwares */
491 unsigned iControlledTry(0);
492 bool bControlled(false);
493 while (timeout
.TimeLeft() > 0 && (bControlled
= SetControlledMode(true)) == false)
495 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry
);
498 bReturn
= bControlled
;
503 if (m_commands
->GetFirmwareVersion() >= 2)
505 /* try to read the build date */
506 m_commands
->RequestBuildDate();
508 /* try to read the adapter type */
509 m_commands
->RequestAdapterType();
512 SetInitialised(bReturn
);
516 bool CUSBCECAdapterCommunication::IsOpen(void)
518 /* thread is not being stopped, the port is open and the thread is running */
519 return !IsStopped() && m_port
->IsOpen() && IsRunning();
522 std::string
CUSBCECAdapterCommunication::GetError(void) const
524 return m_port
->GetError();
527 void CUSBCECAdapterCommunication::SetInitialised(bool bSetTo
/* = true */)
529 CLockObject
lock(m_mutex
);
530 m_bInitialised
= bSetTo
;
533 bool CUSBCECAdapterCommunication::IsInitialised(void)
535 CLockObject
lock(m_mutex
);
536 return m_bInitialised
;
539 bool CUSBCECAdapterCommunication::StartBootloader(void)
541 if (m_port
->IsOpen() && m_commands
->StartBootloader())
549 bool CUSBCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses
&addresses
)
552 CLockObject
lock(m_mutex
);
553 if (m_logicalAddresses
== addresses
)
557 if (IsOpen() && m_commands
->SetAckMask(addresses
.AckMask()))
559 CLockObject
lock(m_mutex
);
560 m_logicalAddresses
= addresses
;
564 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "couldn't change the ackmask: the connection is closed");
568 cec_logical_addresses
CUSBCECAdapterCommunication::GetLogicalAddresses(void)
570 cec_logical_addresses addresses
;
571 CLockObject
lock(m_mutex
);
572 addresses
= m_logicalAddresses
;
576 bool CUSBCECAdapterCommunication::PingAdapter(void)
578 return IsOpen() ? m_commands
->PingAdapter() : false;
581 uint16_t CUSBCECAdapterCommunication::GetFirmwareVersion(void)
583 return m_commands
? m_commands
->GetFirmwareVersion() : CEC_FW_VERSION_UNKNOWN
;
586 uint32_t CUSBCECAdapterCommunication::GetFirmwareBuildDate(void)
588 uint32_t iBuildDate(0);
590 iBuildDate
= m_commands
->GetPersistedBuildDate();
591 if (iBuildDate
== 0 && IsOpen())
592 iBuildDate
= m_commands
->RequestBuildDate();
597 cec_adapter_type
CUSBCECAdapterCommunication::GetAdapterType(void)
599 cec_adapter_type
type(ADAPTERTYPE_UNKNOWN
);
601 type
= (cec_adapter_type
)m_commands
->GetPersistedAdapterType();
602 if (type
== ADAPTERTYPE_UNKNOWN
&& IsOpen())
603 type
= (cec_adapter_type
)m_commands
->RequestAdapterType();
608 bool CUSBCECAdapterCommunication::ProvidesExtendedResponse(void)
610 uint32_t iBuildDate(0);
612 iBuildDate
= m_commands
->GetPersistedBuildDate();
614 return iBuildDate
>= CEC_FW_DATE_EXTENDED_RESPONSE
;
617 uint16_t CUSBCECAdapterCommunication::GetAdapterVendorId(void) const
622 uint16_t CUSBCECAdapterCommunication::GetAdapterProductId(void) const
624 uint32_t iBuildDate(0);
626 iBuildDate
= m_commands
->GetPersistedBuildDate();
628 return iBuildDate
>= CEC_FW_DATE_DESCRIPTOR2
? CEC_PID2
: CEC_PID
;
631 bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void)
633 return GetFirmwareBuildDate() >= CEC_LATEST_ADAPTER_FW_DATE
&&
634 GetFirmwareVersion() >= CEC_LATEST_ADAPTER_FW_VERSION
;
637 bool CUSBCECAdapterCommunication::PersistConfiguration(const libcec_configuration
&configuration
)
640 m_commands
->PersistConfiguration(configuration
) && m_eepromWriteThread
->Write() :
644 bool CUSBCECAdapterCommunication::GetConfiguration(libcec_configuration
&configuration
)
646 return IsOpen() ? m_commands
->GetConfiguration(configuration
) : false;
649 std::string
CUSBCECAdapterCommunication::GetPortName(void)
651 return m_port
->GetName();
654 bool CUSBCECAdapterCommunication::SetControlledMode(bool controlled
)
656 return IsOpen() ? m_commands
->SetControlledMode(controlled
) : false;
659 uint16_t CUSBCECAdapterCommunication::GetPhysicalAddress(void)
663 // try to get the PA from ADL
664 #if defined(HAS_ADL_EDID_PARSER)
666 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - trying to get the physical address via ADL", __FUNCTION__
);
668 iPA
= adl
.GetPhysicalAddress();
669 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - ADL returned physical address %04x", __FUNCTION__
, iPA
);
673 // try to get the PA from the nvidia driver
674 #if defined(HAS_NVIDIA_EDID_PARSER)
677 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - trying to get the physical address via nvidia driver", __FUNCTION__
);
679 iPA
= nv
.GetPhysicalAddress();
680 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - nvidia driver returned physical address %04x", __FUNCTION__
, iPA
);
684 // try to get the PA from the OS
687 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - trying to get the physical address from the OS", __FUNCTION__
);
688 iPA
= CEDIDParser::GetPhysicalAddress();
689 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - OS returned physical address %04x", __FUNCTION__
, iPA
);
695 void *CAdapterPingThread::Process(void)
699 if (m_timeout
.TimeLeft() == 0)
701 /* reinit the timeout */
702 m_timeout
.Init(CEC_ADAPTER_PING_TIMEOUT
);
704 /* send a ping to the adapter */
706 int iFailedCounter(0);
707 while (!bPinged
&& iFailedCounter
< 3)
709 if (!m_com
->PingAdapter())
711 /* sleep and retry */
712 Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT
);
721 if (iFailedCounter
== 3)
723 /* failed to ping the adapter 3 times in a row. something must be wrong with the connection */
724 m_com
->LIB_CEC
->AddLog(CEC_LOG_ERROR
, "failed to ping the adapter 3 times in a row. closing the connection.");
725 m_com
->StopThread(false);
735 void CAdapterEepromWriteThread::Stop(void)
739 CLockObject
lock(m_mutex
);
740 if (m_iScheduleEepromWrite
> 0)
741 m_com
->LIB_CEC
->AddLog(CEC_LOG_WARNING
, "write thread stopped while a write was queued");
743 m_condition
.Signal();
748 void *CAdapterEepromWriteThread::Process(void)
752 CLockObject
lock(m_mutex
);
753 if ((m_iScheduleEepromWrite
> 0 && m_iScheduleEepromWrite
< GetTimeMs()) ||
754 m_condition
.Wait(m_mutex
, m_bWrite
, 100))
759 if (m_com
->m_commands
->WriteEEPROM())
761 m_iLastEepromWrite
= GetTimeMs();
762 m_iScheduleEepromWrite
= 0;
766 m_iScheduleEepromWrite
= GetTimeMs() + CEC_ADAPTER_EEPROM_WRITE_RETRY
;
773 bool CAdapterEepromWriteThread::Write(void)
775 CLockObject
lock(m_mutex
);
776 if (m_iScheduleEepromWrite
== 0)
778 int64_t iNow
= GetTimeMs();
779 if (m_iLastEepromWrite
+ CEC_ADAPTER_EEPROM_WRITE_INTERVAL
> iNow
)
781 m_com
->LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "delaying eeprom write by %ld ms", m_iLastEepromWrite
+ CEC_ADAPTER_EEPROM_WRITE_INTERVAL
- iNow
);
782 m_iScheduleEepromWrite
= m_iLastEepromWrite
+ CEC_ADAPTER_EEPROM_WRITE_INTERVAL
;
787 m_condition
.Signal();