RDK Documentation (Open Sourced RDK Components)
Bus.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 
21 
22 /**
23 * @defgroup hdmicec
24 * @{
25 * @defgroup ccec
26 * @{
27 **/
28 
29 /**
30  * @defgroup hdmi_bus HDMI-CEC BUS
31  * @ingroup HDMI_CEC
32  * @addtogroup hdmi_bus
33  * @{
34  */
35 
36 
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include "ccec/CECFrame.hpp"
41 #include "ccec/FrameListener.hpp"
42 #include "ccec/Driver.hpp"
43 #include "ccec/Exception.hpp"
44 #include "ccec/Util.hpp"
45 
46 #include "Bus.hpp"
47 
49 using CCEC_OSAL::Thread;
50 
51 CCEC_BEGIN_NAMESPACE
52 
53 /**
54  * @brief This function is used to create the instance of Bus class.
55  *
56  * @return instance Instance of the Bus class.
57  */
59 {
60  static Bus instance;
61  return instance;
62 }
63 
64 /**
65  * @brief This function is a constructor for the class Bus. It is used to starts
66  * the read and write thread which creates its instance.
67  *
68  * @return None
69  */
70 Bus::Bus(void) : reader(*this), writer(*this)
71 {
72  CCEC_LOG( LOG_DEBUG, "Bus Instance Created\r\n");
73  Thread(this->reader).start();
74  Thread(this->writer).start();
75  CCEC_LOG( LOG_DEBUG, "Bus Instance DONE\r\n");
76 }
77 
78 /**
79  * @brief This function starts the threads and gets the instance for Bus.
80  *
81  * @return None
82  */
83 void Bus::start(void)
84 {AutoLock rlock_(rMutex), wlock_(wMutex);
85  CCEC_LOG( LOG_INFO, "Bus::start is called \r\n");
86 
87  if(reader.isStopped())
88  {
89  Thread(reader).start();
90  }
91  if(writer.isStopped())
92  {
93  Thread(writer).start();
94  }
95 
96  Driver::getInstance().open();
97  started = true;
98 }
99 
100 /**
101  * @brief This function stops the reader & writer threads and removes the
102  * instance for Bus.
103  *
104  * @return None
105  */
106 void Bus::stop(void)
107 {AutoLock rlock_(rMutex), wlock_(wMutex);
108 
109 CCEC_LOG( LOG_INFO, "Bus::stop is called\r\n");
110 
111  started = false;
112  reader.stop(true);
113  writer.stop(true);
114 
115  Driver::getInstance().close();
116  CCEC_LOG( LOG_INFO, "Bus::stop is called reader isstop :%d writer isstop :%d \r\n",reader.isStopped(),writer.isStopped());
117 }
118 
119 /**
120  * @brief This is a destructor for class BUS. This function initiates the closing
121  * of threads and the instance for Bus will be freed.
122  *
123  * @return None
124  */
126 {
127  Assert(!started);
128 
129  reader.stop(true);
130  writer.stop(true);
131 
132  CCEC_LOG( LOG_DEBUG, "Bus::Destroyed\r\n");
133 
134 }
135 
136 /**
137  * @brief This function is used to read CECFrame from the driver. This gets
138  * notified to the frameListener which is listening for frames in CEC bus.
139  *
140  * @return None
141  */
143 {
144  CECFrame frame;
145 
146  if(isStopped())
147  {
148  runStarted();
149  }
150 
151  CCEC_LOG( LOG_INFO, "Bus::Reader::run() started\r\n");
152  while (isRunning()) {
153  try {
154  Driver::getInstance().read(frame);
155  {AutoLock lock_(bus.rMutex);
156  if (bus.listeners.size() == 0) CCEC_LOG( LOG_DEBUG, "Bus::Reader discarding msgs for lack of listener\r\n");
157  std::list<FrameListener *>::iterator list_it;
158  for(list_it = bus.listeners.begin(); list_it!= bus.listeners.end(); list_it++) {
159  CCEC_LOG( LOG_DEBUG, "Bus::Reader::run() notify Listener\r\n");
160  (*list_it)->notify(frame);
161  //CCEC_LOG( LOG_DEBUG, "Bus::Reader::run() notify Listener Done\r\n");
162  }
163  }
164  }
165  catch(InvalidStateException &e) {
166  CCEC_LOG( LOG_DEBUG, "EOF for reader [%d]\r\n", isRunning());
167  }
168  }
169 
170  stopCompleted();
171 }
172 
173 /**
174  * @brief This function is used to stop the reader to read frames from the bus.
175  *
176  * @param[in] block State of Reader.
177  *
178  * @return None
179  */
180 void Bus::Reader::stop(bool block)
181 {
182  CCEC_LOG( LOG_INFO, "Bus::Reader::stop::stop Entering [%d]\r\n", block);
183 
184  {AutoLock lock_(bus.rMutex);
185  stopStarted();
186  }
187 
188  Driver::getInstance().close();
189 
190  if (block) {
191  while (!isStopped()) {
192  usleep(50 * 1000);
193  }
194 
195  CCEC_LOG( LOG_DEBUG, "Bus::Reader::stop::stop completed\r\n");
196  }
197 
198 }
199 
200 /**
201  * @brief This function is used to add new listener for reading frames.
202  *
203  * @param[in] listener Struct pointer for the addition of listener.
204  *
205  * @return None
206  */
208 {
209  {AutoLock lock_(rMutex);
210  if (!started) throw InvalidStateException();
211  listeners.push_back(listener);
212  }
213 }
214 
215 /**
216  * @brief This function is used to remove the listener.
217  *
218  * @param[in] listener Struct pointer of a listener which is to be removed.
219  *
220  * @return None
221  */
223 {
224  { AutoLock lock_(rMutex);
225  if (!started) throw InvalidStateException();
226  listeners.remove(listener);
227  }
228 
229 }
230 
231 /**
232  * @brief This function is used to poll the bus for frame availability and it
233  * writes the CEC frame to the driver.
234  *
235  * @return None
236  */
238 {
239  CECFrame frame;
240  //Driver::getInstance()->open();
241  CCEC_LOG( LOG_INFO, "Bus::Writer::run() started\r\n");
242  CECFrame * outFrame = NULL;
243 
244  if(isStopped())
245  {
246  runStarted();
247  }
248 
249  do {
250  CCEC_LOG( LOG_DEBUG, "Bus::Writer::run Looping [%d]\r\n", isRunning());
251 
252  try {
253  outFrame = bus.wQueue.poll();
254  if (outFrame != 0) {
255  Driver::getInstance().write(*outFrame);
256  }
257  else {
258  CCEC_LOG( LOG_DEBUG, "Bus::Writer::run EOF [%d]\r\n", isRunning());
259  /* sentinel value */
260  throw InvalidStateException();
261  }
262  }
263  catch(InvalidStateException &e) {
264  CCEC_LOG( LOG_EXP, "Driver closed writer[%d]\r\n", isRunning());
265  }
266  catch(Exception &e) {
267  CCEC_LOG( LOG_EXP,"Driver write failed\r\n");
268  e.what();
269  }
270 
271  delete outFrame;
272  }
273 
274  while (isRunning());
275 
276  if (!isRunning()) {
277  while(bus.wQueue.size() > 0) {
278  outFrame = bus.wQueue.poll();
279  delete outFrame;
280  }
281  }
282 
283  stopCompleted();
284 }
285 
286 /**
287  * @brief This function is used to stop the writer for polling the bus and writing
288  * to the driver.
289  *
290  * @param[in] block State of Writer.
291  *
292  * @return None
293  */
294 void Bus::Writer::stop(bool block)
295 {
296  CCEC_LOG( LOG_INFO, "Bus::Writer::stop::stop Entering [%d]\r\n", block);
297 
298  {AutoLock lock_(bus.wMutex);
299  if (isRunning()) {
300  stopStarted();
301  bus.wQueue.offer(0);
302  CCEC_LOG( LOG_DEBUG, "Bus::Writer::stop::stop offer completed [%d]\r\n", isRunning());
303  }
304  }
305 
306  if (block) {
307  while (!isStopped()) {
308  usleep(50 * 1000);
309  }
310 
311  CCEC_LOG( LOG_DEBUG, "Bus::Writer::stop::stop completed\r\n");
312  }
313 
314 }
315 
316 /**
317  * @brief This function is used to write the frame to the driver. If it fails,
318  * as it is a synchronous function, it retries every 250ms till the retry count lapse.
319  *
320  * @param[in] frame CEC frame to be sent.
321  * @param[in] timeout Time period for retrying.
322  *
323  * @return None
324  */
325 void Bus::send(const CECFrame &frame, int timeout)
326 {
327  {AutoLock rlock_(rMutex), wlock_(wMutex);
328 
329  if (timeout <= 0) {
330  if (!started) throw InvalidStateException();
331 
332  try {
333  Driver::getInstance().write(frame);
334  CCEC_LOG( LOG_DEBUG, "Bus::send write done\r\n");
335  }
336  catch (Exception &e){
337  if( frame.length() > 1) CCEC_LOG( LOG_EXP, "Bus::send exp caught [%s] \r\n", e.what());
338  throw;
339  }
340  }
341  }
342 
343  {AutoLock rlock_(rMutex), wlock_(wMutex);
344  if (timeout > 0) {
345  /* Retry in 250ms increment till timeout */
346  int retry = (timeout / 250);
347  do {
348  try {
349  if (!started) throw InvalidStateException();
350  send(frame, 0);
351  retry = 0;
352  }
353  catch (Exception &e){
354  if( frame.length() > 1) CCEC_LOG( LOG_EXP, "Bus::send exp caught [%s], retry [%d]\r\n", e.what(), retry);
355  if (retry == 0) {
356  throw;
357  }
358  usleep(250000);
359  }
360  } while (retry--);
361  }
362  }
363 }
364 
365 /**
366  * @brief This function is used to keep asynchronously sending the frame by
367  * keeping copy of cec frame in the queue of the driver.
368  *
369  * @param[in] frame CEC frame which need to be sent asynchronously.
370  *
371  * @return None
372  */
373 void Bus::sendAsync(const CECFrame &frame)
374 {
375  {AutoLock lock_(wMutex);
376 
377  if (!started) throw InvalidStateException();
378 
379  CECFrame *copyFrame = (new CECFrame());
380  *copyFrame = frame;
381 
382  wQueue.offer((copyFrame));
383  }
384 }
385 
386 /**
387  * @brief This function is used to poll the logical address
388  * and returns the ACK or NACK received from other devices.
389  * If NACK then the device can use this logical address.
390  *
391  * @param[in] Logical address of initiator.
392  * @param[in] Logical address of follower.
393  *
394  * @return throws exception if there is NACK
395  */
396 void Bus::poll(const LogicalAddress &from, const LogicalAddress &to)
397 {
398  {AutoLock rlock_(rMutex), wlock_(wMutex);
399 
400  if (!started) throw InvalidStateException();
401 
402  try {
403  Driver::getInstance().poll(from, to);
404  CCEC_LOG( LOG_DEBUG, "Bus::poll done\r\n");
405  }
406  catch (Exception &e){
407  CCEC_LOG( LOG_DEBUG, "Bus::poll exp caught [%s] \r\n", e.what());
408  throw;
409  }
410  }
411 }
412 
413 /**
414  * @brief This function is used to ping devices, to know whether it present
415  * and returns the ACK or NACK received from other devices.
416  * If ACK is received, then the device is present.
417  *
418  * @param[in] Logical address of initiator.
419  * @param[in] Logical address of follower.
420  *
421  * @return throws exception if there is NACK
422  */
423 void Bus::ping(const LogicalAddress &from, const LogicalAddress &to)
424 {
425  {AutoLock rlock_(rMutex), wlock_(wMutex);
426 
427  if (!started) throw InvalidStateException();
428 
429  try {
430  Driver::getInstance().poll(from, to);
431  CCEC_LOG( LOG_DEBUG, "Bus::ping done\r\n");
432  }
433  catch (Exception &e){
434  CCEC_LOG( LOG_DEBUG, "Bus::ping exp caught [%s] \r\n", e.what());
435  throw;
436  }
437  }
438 }
439 
440 
441 CCEC_END_NAMESPACE
442 
443 
444 /** @} */
445 /** @} */
446 /** @} */
CCEC_OSAL::Thread
Definition: Thread.hpp:64
CCEC_OSAL::AutoLock
Definition: Mutex.hpp:121
Bus::stop
void stop(void)
This function stops the reader & writer threads and removes the instance for Bus.
Definition: Bus.cpp:106
FrameListener
Definition: FrameListener.hpp:39
Bus::removeFrameListener
void removeFrameListener(FrameListener *listener)
This function is used to remove the listener.
Definition: Bus.cpp:222
Bus::getInstance
static Bus & getInstance(void)
This function is used to create the instance of Bus class.
Definition: Bus.cpp:58
Bus::Reader::stop
void stop(bool block=true)
This function is used to stop the reader to read frames from the bus.
Definition: Bus.cpp:180
LogicalAddress
Definition: Operands.hpp:409
Bus::poll
void poll(const LogicalAddress &from, const LogicalAddress &to)
This function is used to poll the logical address and returns the ACK or NACK received from other dev...
Definition: Bus.cpp:396
Bus::Writer::stop
void stop(bool block=true)
This function is used to stop the writer for polling the bus and writing to the driver.
Definition: Bus.cpp:294
Bus::sendAsync
void sendAsync(const CECFrame &frame)
This function is used to keep asynchronously sending the frame by keeping copy of cec frame in the qu...
Definition: Bus.cpp:373
Bus::Writer::run
void run(void)
This function is used to poll the bus for frame availability and it writes the CEC frame to the drive...
Definition: Bus.cpp:237
Bus::Bus
Bus(void)
This function is a constructor for the class Bus. It is used to starts the read and write thread whic...
Definition: Bus.cpp:70
InvalidStateException
Definition: Exception.hpp:81
Bus::Reader::run
void run(void)
This function is used to read CECFrame from the driver. This gets notified to the frameListener which...
Definition: Bus.cpp:142
Bus::start
void start(void)
This function starts the threads and gets the instance for Bus.
Definition: Bus.cpp:83
CCEC_OSAL::EventQueue::offer
void offer(E element)
send an event to the queue.
Definition: EventQueue.hpp:167
CCEC_OSAL::Thread::start
void start(void)
Starts excecution of the thread.
Definition: Thread.cpp:62
Bus::~Bus
~Bus(void)
This is a destructor for class BUS. This function initiates the closing of threads and the instance f...
Definition: Bus.cpp:125
LOG_INFO
#define LOG_INFO(AAMP_JS_OBJECT, FORMAT,...)
Definition: jsutils.h:39
Bus
Definition: Bus.hpp:53
Bus::addFrameListener
void addFrameListener(FrameListener *listener)
This function is used to add new listener for reading frames.
Definition: Bus.cpp:207
Bus::send
void send(const CECFrame &frame, int timeout=0)
This function is used to write the frame to the driver. If it fails, as it is a synchronous function,...
Definition: Bus.cpp:325
Exception
Definition: Exception.hpp:42
CECFrame
Definition: CECFrame.hpp:40
Bus::ping
void ping(const LogicalAddress &from, const LogicalAddress &to)
This function is used to ping devices, to know whether it present and returns the ACK or NACK receive...
Definition: Bus.cpp:423
CCEC_LOG
void CCEC_LOG(int level, const char *format ...)
This function is used to gets the logs depending on the level of log and print these to standard outp...
Definition: Util.cpp:120