blob: 81e668d76378f58d17563191be2a2ff1966b411e [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CECSERVICE_CEC_DEVICE_H_
#define CECSERVICE_CEC_DEVICE_H_
#include <linux/cec.h>
#include <deque>
#include <list>
#include <memory>
#include <string>
#include <base/callback.h>
#include <base/memory/weak_ptr.h>
#include <base/files/file_path.h>
#include <chromeos/dbus/service_constants.h>
#include "cecservice/cec_fd.h"
namespace cecservice {
// Object handling interaction with a single /dev/cec* node.
class CecDevice {
public:
using GetTvPowerStatusCallback = base::Callback<void(TvPowerStatus)>;
virtual ~CecDevice() = default;
// Gets power state of TV.
virtual void GetTvPowerStatus(GetTvPowerStatusCallback callback) = 0;
// Sends stand by request to a TV.
virtual void SetStandBy() = 0;
// Sends wake up (image view on + active source) messages.
virtual void SetWakeUp() = 0;
};
// Actual implementation of CecDevice.
class CecDeviceImpl : public CecDevice {
public:
CecDeviceImpl(std::unique_ptr<CecFd> fd, const base::FilePath& device_path);
~CecDeviceImpl() override;
// Performs object initialization. Returns false if the initialization
// failed and object is unusable.
bool Init();
// CecDevice overrides:
void GetTvPowerStatus(GetTvPowerStatusCallback callback) override;
void SetStandBy() override;
void SetWakeUp() override;
private:
// Represents CEC adapter state.
enum class State {
kStart, // State when no physical address is known, in this state we
// are only allowed to send image view on message.
kNoLogicalAddress, // The physical address is known but the logical
// address is not (yet) configured.
kReady // All is set up, we are free to send any type of messages.
};
// Represents request that either is to be sent or already has been sent
// but we didn't yet get response to.
struct RequestInFlight {
// The callback to invoke when request completes.
GetTvPowerStatusCallback callback;
// Message id assigned by CEC API or 0 if the request has not been sent yet.
uint32_t sequence_id;
};
// Schedules watching for write readiness on the fd if there are some
// outgoing messages.
void RequestWriteWatch();
// Returns the current state.
State GetState() const;
// Updates the state based on the event received from CEC core, returns new
// state.
State UpdateState(const struct cec_event_state_change& event);
// Processes messages lost event from CEC, just logs number of lost events
// and always returns true.
bool ProcessMessagesLostEvent(const struct cec_event_lost_msgs& event);
// Acts on process update event from CEC core. If this method returns false
// then an unexpected error was encountered and the object should be disabled.
bool ProcessStateChangeEvent(const struct cec_event_state_change& event);
// Processes incoming events. If false is returned, then unexpected failure
// occurred and the object should be disabled.
bool ProcessEvents();
// Attempts to read incoming data from the fd. If false is returned, then
// unexpected failure occurred and the object should be disabled.
bool ProcessRead();
// Attempts to write data to fd. If false is returned, then unexpected failure
// occurred and the object should be disabled.
bool ProcessWrite();
// Processes response received to get power status request. Returns false if
// the message is not a response to a previously sent request.
bool ProcessPowerStatusResponse(const struct cec_msg& msg);
// Handles sent message notifications and responses to get tv power queries.
void ProcessSentMessage(const struct cec_msg& msg);
// Handles messages directed to us.
void ProcessIncomingMessage(struct cec_msg* msg);
// Sends provided message.
CecFd::TransmitResult SendMessage(struct cec_msg* msg);
// Sets the type of logical address on the adapter (if it has not been yet
// configured), returns false if the operation failed. Here we are only
// choosing the type of the address, the kernel will then do the probing and
// try to allocate first free address of the chosen type. The address type
// selection is permanent and survives device reconnects (every time EDID
// shows up, kernel will redo the probing and potentially can end up selecting
// different logical address). Since this selection is permanent it is
// sufficient to do it only once when we create the device.
bool SetLogicalAddress();
// Handles fd event.
void OnFdEvent(CecFd::EventType event);
// Immediately responds to all currently ongoing queries.
void RespondToAllPendingQueries(TvPowerStatus response);
// Enqueues messages, returns true if the message was added to the queue.
bool EnqueueMessage(struct cec_msg msg);
// Disables device.
void DisableDevice();
// Current physical address.
uint16_t physical_address_ = CEC_PHYS_ADDR_INVALID;
// Current logical address.
uint8_t logical_address_ = CEC_LOG_ADDR_INVALID;
// Queue of messages we are about to send.
std::deque<struct cec_msg> message_queue_;
// Queue of requests that are in flight.
std::list<RequestInFlight> requests_;
// Flag indicating if we believe we are the active source.
bool active_source_ = false;
// If true, we should send out an active source message when the bus becomes
// ready.
bool pending_active_source_broadcast_ = false;
// The descriptor associated with the device.
std::unique_ptr<CecFd> fd_;
// Path to the device, for logging purposes only.
const base::FilePath device_path_;
base::WeakPtrFactory<CecDeviceImpl> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(CecDeviceImpl);
};
// Factory creating CEC device handlers.
class CecDeviceFactory {
public:
virtual ~CecDeviceFactory() = default;
// Creates a new CEC device node handler from a given path. Returns empty ptr
// on failure.
virtual std::unique_ptr<CecDevice> Create(
const base::FilePath& path) const = 0;
};
// Concrete implementation of the CEC device handlers factory.
class CecDeviceFactoryImpl : public CecDeviceFactory {
public:
explicit CecDeviceFactoryImpl(const CecFdOpener* cec_fd_opener);
~CecDeviceFactoryImpl() override;
// CecDeviceFactory overrides.
std::unique_ptr<CecDevice> Create(const base::FilePath& path) const override;
private:
const CecFdOpener* cec_fd_opener_;
DISALLOW_COPY_AND_ASSIGN(CecDeviceFactoryImpl);
};
} // namespace cecservice
#endif // CECSERVICE_CEC_DEVICE_H_