2 * This file is part of the libCEC(R) library.
4 * libCEC(R) is Copyright (C) 2011 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/
33 #include "AdapterCommunication.h"
35 #include "AdapterMessage.h"
36 #include "CECProcessor.h"
37 #include "platform/serialport/serialport.h"
41 using namespace PLATFORM
;
43 CAdapterCommunication::CAdapterCommunication(CCECProcessor
*processor
) :
45 m_processor(processor
),
48 m_port
= new PLATFORM::CSerialPort
;
51 CAdapterCommunication::~CAdapterCommunication(void)
62 bool CAdapterCommunication::Open(const char *strPort
, uint16_t iBaudRate
/* = 38400 */, uint32_t iTimeoutMs
/* = 10000 */)
64 uint64_t iNow
= GetTimeMs();
65 uint64_t iTimeout
= iNow
+ iTimeoutMs
;
67 CLockObject
lock(m_mutex
);
71 m_processor
->AddLog(CEC_LOG_ERROR
, "port is NULL");
77 m_processor
->AddLog(CEC_LOG_ERROR
, "port is already open");
82 bool bConnected(false);
83 while (!bConnected
&& iNow
< iTimeout
)
85 if ((bConnected
= m_port
->Open(strPort
, iBaudRate
)) == false)
87 strError
.Format("error opening serial port '%s': %s", strPort
, m_port
->GetError().c_str());
95 m_processor
->AddLog(CEC_LOG_ERROR
, strError
);
99 m_processor
->AddLog(CEC_LOG_DEBUG
, "connection opened");
101 //clear any input bytes
103 while (m_port
->Read(buff
, 1, 5) == 1) {}
107 m_processor
->AddLog(CEC_LOG_DEBUG
, "communication thread started");
112 m_processor
->AddLog(CEC_LOG_ERROR
, "could not create a communication thread");
118 void CAdapterCommunication::Close(void)
120 CLockObject
lock(m_mutex
);
121 m_rcvCondition
.Broadcast();
125 void *CAdapterCommunication::Process(void)
134 CCECAdapterMessage
*msg(NULL
);
135 if (m_outBuffer
.Pop(msg
))
136 msg
->condition
.Broadcast();
141 bool CAdapterCommunication::Write(CCECAdapterMessage
*data
)
143 data
->state
= ADAPTER_MESSAGE_STATE_WAITING
;
144 m_outBuffer
.Push(data
);
148 bool CAdapterCommunication::Read(CCECAdapterMessage
&msg
, uint32_t iTimeout
)
150 CLockObject
lock(m_mutex
);
153 uint64_t iNow
= GetTimeMs();
154 uint64_t iTarget
= iNow
+ iTimeout
;
155 bool bGotFullMessage(false);
156 bool bNextIsEscaped(false);
157 bool bGotStart(false);
159 while(!bGotFullMessage
&& iNow
< iTarget
)
162 if (!m_inBuffer
.Pop(buf
))
164 if (!m_rcvCondition
.Wait(m_mutex
, (uint32_t) (iTarget
- iNow
)))
174 else if (buf
== MSGSTART
) //we found a msgstart before msgend, this is not right, remove
177 m_processor
->AddLog(CEC_LOG_WARNING
, "received MSGSTART before MSGEND, removing previous buffer contents");
184 bGotFullMessage
= true;
186 else if (bNextIsEscaped
)
188 msg
.PushBack(buf
+ (uint8_t)ESCOFFSET
);
189 bNextIsEscaped
= false;
191 else if (buf
== MSGESC
)
192 bNextIsEscaped
= true;
198 msg
.state
= ADAPTER_MESSAGE_STATE_RECEIVED
;
200 return bGotFullMessage
;
203 std::string
CAdapterCommunication::GetError(void) const
205 return m_port
->GetError();
208 bool CAdapterCommunication::StartBootloader(void)
214 m_processor
->AddLog(CEC_LOG_DEBUG
, "starting the bootloader");
215 CCECAdapterMessage
*output
= new CCECAdapterMessage
;
217 output
->PushBack(MSGSTART
);
218 output
->PushEscaped(MSGCODE_START_BOOTLOADER
);
219 output
->PushBack(MSGEND
);
221 CLockObject
lock(output
->mutex
);
223 output
->condition
.Wait(output
->mutex
);
224 bReturn
= output
->state
== ADAPTER_MESSAGE_STATE_SENT
;
230 bool CAdapterCommunication::PingAdapter(void)
236 m_processor
->AddLog(CEC_LOG_DEBUG
, "sending ping");
237 CCECAdapterMessage
*output
= new CCECAdapterMessage
;
239 output
->PushBack(MSGSTART
);
240 output
->PushEscaped(MSGCODE_PING
);
241 output
->PushBack(MSGEND
);
243 CLockObject
lock(output
->mutex
);
245 output
->condition
.Wait(output
->mutex
);
246 bReturn
= output
->state
== ADAPTER_MESSAGE_STATE_SENT
;
252 bool CAdapterCommunication::SetLineTimeout(uint8_t iTimeout
)
254 bool bReturn(m_iLineTimeout
!= iTimeout
);
258 CCECAdapterMessage
*output
= new CCECAdapterMessage
;
260 output
->PushBack(MSGSTART
);
261 output
->PushEscaped(MSGCODE_TRANSMIT_IDLETIME
);
262 output
->PushEscaped(iTimeout
);
263 output
->PushBack(MSGEND
);
265 if ((bReturn
= Write(output
)) == false)
266 m_processor
->AddLog(CEC_LOG_ERROR
, "could not set the idletime");
273 bool CAdapterCommunication::IsOpen(void)
275 return !IsStopped() && m_port
->IsOpen() && IsRunning();
278 void CAdapterCommunication::AddData(uint8_t *data
, uint8_t iLen
)
280 CLockObject
lock(m_mutex
);
281 for (uint8_t iPtr
= 0; iPtr
< iLen
; iPtr
++)
282 m_inBuffer
.Push(data
[iPtr
]);
284 m_rcvCondition
.Signal();
287 bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout
)
294 iBytesRead
= m_port
->Read(buff
, sizeof(buff
), iTimeout
);
295 if (iBytesRead
< 0 || iBytesRead
> 256)
298 strError
.Format("error reading from serial port: %s", m_port
->GetError().c_str());
299 m_processor
->AddLog(CEC_LOG_ERROR
, strError
);
302 else if (iBytesRead
> 0)
303 AddData(buff
, (uint8_t) iBytesRead
);
305 return iBytesRead
> 0;
308 void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage
*msg
)
310 CLockObject
lock(msg
->mutex
);
311 if (m_port
->Write(msg
->packet
.data
, msg
->Size()) != (int32_t) msg
->Size())
314 strError
.Format("error writing to serial port: %s", m_port
->GetError().c_str());
315 m_processor
->AddLog(CEC_LOG_ERROR
, strError
);
316 msg
->state
= ADAPTER_MESSAGE_STATE_ERROR
;
320 m_processor
->AddLog(CEC_LOG_DEBUG
, "command sent");
321 msg
->state
= ADAPTER_MESSAGE_STATE_SENT
;
323 msg
->condition
.Signal();
326 void CAdapterCommunication::WriteNextCommand(void)
328 CCECAdapterMessage
*msg(NULL
);
329 if (m_outBuffer
.Pop(msg
))
330 SendMessageToAdapter(msg
);