cec: renamed CCommunication -> CAdapterCommunication
[deb_libcec.git] / src / lib / AdapterCommunication.cpp
CommitLineData
a8f0bd18
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
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.
13 *
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.
18 *
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.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
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/
31 */
32
828682d3 33#include "AdapterCommunication.h"
a8f0bd18
LOK
34#include "CECParser.h"
35#include "libPlatform/serialport.h"
36#include "util/StdString.h"
37
38using namespace std;
39using namespace CEC;
40
828682d3 41CAdapterCommunication::CAdapterCommunication(CCECParser *parser) :
a8f0bd18
LOK
42 m_parser(parser),
43 m_inbuf(NULL),
44 m_iInbufSize(0),
45 m_iInbufUsed(0),
46 m_bStarted(false),
47 m_bStop(false)
48{
49 m_port = new CSerialPort;
50}
51
828682d3 52CAdapterCommunication::~CAdapterCommunication(void)
a8f0bd18
LOK
53{
54 m_port->Close();
55 m_port = NULL;
56}
57
828682d3 58bool CAdapterCommunication::Open(const char *strPort, int iBaudRate /* = 38400 */, int iTimeoutMs /* = 10000 */)
a8f0bd18
LOK
59{
60 CLockObject lock(&m_commMutex);
61 if (m_bStarted)
62 return false;
63
64 if (!m_port->Open(strPort, iBaudRate))
65 {
66 CStdString strError;
67 strError.Format("error opening serial port '%s': %s", strPort, m_port->GetError().c_str());
68 m_parser->AddLog(CEC_LOG_ERROR, strError);
69 return false;
70 }
71
72 m_parser->AddLog(CEC_LOG_DEBUG, "connection opened");
73
74 //clear any input bytes
75 uint8_t buff[1024];
76 m_port->Read(buff, sizeof(buff), 50);
77
78 CCondition::Sleep(CEC_SETTLE_DOWN_TIME);
79
80 m_bStop = false;
81 m_bStarted = true;
828682d3
LOK
82
83 if (CreateThread())
a8f0bd18
LOK
84 {
85 m_parser->AddLog(CEC_LOG_DEBUG, "reader thread created");
a8f0bd18
LOK
86 return true;
87 }
88 else
89 {
90 m_parser->AddLog(CEC_LOG_DEBUG, "could not create a reader thread");
91 }
92
93 return false;
94}
95
828682d3 96void CAdapterCommunication::Close(void)
a8f0bd18 97{
828682d3 98 StopThread();
a8f0bd18
LOK
99 m_port->Close();
100}
101
828682d3 102void *CAdapterCommunication::Process(void)
a8f0bd18
LOK
103{
104 while (!m_bStop)
105 {
106 if (!ReadFromDevice(250))
107 {
108 m_bStarted = false;
109 break;
110 }
111
112 CCondition::Sleep(50);
113 }
114
115 m_parser->AddLog(CEC_LOG_DEBUG, "reader thread terminated");
116
117 CLockObject lock(&m_commMutex);
118 m_bStarted = false;
119 return NULL;
120}
121
828682d3 122bool CAdapterCommunication::ReadFromDevice(int iTimeout)
a8f0bd18
LOK
123{
124 uint8_t buff[1024];
125 CLockObject lock(&m_commMutex);
126 int iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout);
127 lock.Leave();
128 if (iBytesRead < 0)
129 {
130 CStdString strError;
131 strError.Format("error reading from serial port: %s", m_port->GetError().c_str());
132 m_parser->AddLog(CEC_LOG_ERROR, strError);
133 return false;
134 }
135 else if (iBytesRead > 0)
136 AddData(buff, iBytesRead);
137
138 return true;
139}
140
828682d3 141void CAdapterCommunication::AddData(uint8_t *data, int iLen)
a8f0bd18
LOK
142{
143 CLockObject lock(&m_bufferMutex);
144 if (iLen + m_iInbufUsed > m_iInbufSize)
145 {
146 m_iInbufSize = iLen + m_iInbufUsed;
147 m_inbuf = (uint8_t*)realloc(m_inbuf, m_iInbufSize);
148 }
149
150 memcpy(m_inbuf + m_iInbufUsed, data, iLen);
151 m_iInbufUsed += iLen;
152 lock.Leave();
153 m_condition.Signal();
154}
155
828682d3 156bool CAdapterCommunication::Write(const cec_frame &data)
a8f0bd18
LOK
157{
158 CLockObject lock(&m_commMutex);
159
160 if (m_port->Write(data) != data.size())
161 {
162 CStdString strError;
163 strError.Format("error writing to serial port: %s", m_port->GetError().c_str());
164 m_parser->AddLog(CEC_LOG_ERROR, strError);
165 return false;
166 }
167
168 m_parser->AddLog(CEC_LOG_DEBUG, "command sent");
169 return true;
170}
171
828682d3 172bool CAdapterCommunication::Read(cec_frame &msg, int iTimeout)
a8f0bd18
LOK
173{
174 CLockObject lock(&m_bufferMutex);
175
60fa4578 176 if (m_iInbufUsed < 1)
a8f0bd18
LOK
177 m_condition.Wait(&m_bufferMutex, iTimeout);
178
179 if (m_iInbufUsed < 1)
180 return false;
181
182 //search for first start of message
183 int startpos = -1;
184 for (int i = 0; i < m_iInbufUsed; i++)
185 {
186 if (m_inbuf[i] == MSGSTART)
187 {
188 startpos = i;
189 break;
190 }
191 }
192
193 if (startpos == -1)
194 return false;
195
196 //move anything from the first start of message to the beginning of the buffer
197 if (startpos > 0)
198 {
199 memmove(m_inbuf, m_inbuf + startpos, m_iInbufUsed - startpos);
200 m_iInbufUsed -= startpos;
201 }
202
203 if (m_iInbufUsed < 2)
204 return false;
205
206 //look for end of message
207 startpos = -1;
208 int endpos = -1;
209 for (int i = 1; i < m_iInbufUsed; i++)
210 {
211 if (m_inbuf[i] == MSGEND)
212 {
213 endpos = i;
214 break;
215 }
216 else if (m_inbuf[i] == MSGSTART)
217 {
218 startpos = i;
219 break;
220 }
221 }
222
223 if (startpos > 0) //we found a msgstart before msgend, this is not right, remove
224 {
225 m_parser->AddLog(CEC_LOG_ERROR, "received MSGSTART before MSGEND");
226 memmove(m_inbuf, m_inbuf + startpos, m_iInbufUsed - startpos);
227 m_iInbufUsed -= startpos;
228 return false;
229 }
230
231 if (endpos > 0) //found a MSGEND
232 {
233 msg.clear();
234 bool isesc = false;
235 for (int i = 1; i < endpos; i++)
236 {
237 if (isesc)
238 {
239 msg.push_back(m_inbuf[i] + (uint8_t)ESCOFFSET);
240 isesc = false;
241 }
242 else if (m_inbuf[i] == MSGESC)
243 {
244 isesc = true;
245 }
246 else
247 {
248 msg.push_back(m_inbuf[i]);
249 }
250 }
251
252 if (endpos + 1 < m_iInbufUsed)
253 memmove(m_inbuf, m_inbuf + endpos + 1, m_iInbufUsed - endpos - 1);
254
255 m_iInbufUsed -= endpos + 1;
256
257 return true;
258 }
259
260 return false;
261}
262
828682d3 263std::string CAdapterCommunication::GetError(void) const
a8f0bd18
LOK
264{
265 return m_port->GetError();
266}