blob: 903aa78fb25960820a8859adef182a18f25e0f5e [file] [log] [blame]
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __VOM_HW_H__
#define __VOM_HW_H__
#include <deque>
#include <map>
#include <queue>
#include <sstream>
#include <string>
#include <thread>
#include "vom/cmd.hpp"
#include "vom/connection.hpp"
#include "vom/types.hpp"
namespace VOM {
class cmd;
class HW
{
public:
/**
* A HW::item is data that is either to be written to or read from
* VPP/HW.
* The item is a pair of the data written/read and the result of that
* operation.
*/
template <typename T>
class item
{
public:
/**
* Constructor
*/
item(const T& data)
: item_data(data)
, item_rc(rc_t::NOOP)
{
}
/**
* Constructor
*/
item()
: item_data()
, item_rc(rc_t::UNSET)
{
}
/**
* Constructor
*/
item(rc_t rc)
: item_data()
, item_rc(rc)
{
}
/**
* Constructor
*/
item(const T& data, rc_t rc)
: item_data(data)
, item_rc(rc)
{
}
/**
* Destructor
*/
~item() = default;
/**
* Comparison operator
*/
bool operator==(const item<T>& i) const
{
return (item_data == i.item_data);
}
/**
* Copy assignment
*/
item& operator=(const item& other)
{
item_data = other.item_data;
item_rc = other.item_rc;
return (*this);
}
/**
* Return the data read/written
*/
T& data() { return (item_data); }
/**
* Const reference to the data
*/
const T& data() const { return (item_data); }
/**
* Get the HW return code
*/
rc_t rc() const { return (item_rc); }
/**
* Set the HW return code - should only be called from the
* family of Command objects
*/
void set(const rc_t& rc) { item_rc = rc; }
/**
* Return true if the HW item is configred in HW
*/
operator bool() const { return (rc_t::OK == item_rc); }
/**
* update the item to the desired state.
* return true if a HW update is required
*/
bool update(const item& desired)
{
bool need_hw_update = false;
/*
* if the deisred set is unset (i.e. defaulted, we've
* no update to make
*/
if (rc_t::UNSET == desired.rc()) {
return (false);
}
/*
* A HW update is needed if thestate is different
* or the state is not yet in HW
*/
need_hw_update = (item_data != desired.data() || rc_t::OK != rc());
item_data = desired.data();
return (need_hw_update);
}
/**
* convert to string format for debug purposes
*/
std::string to_string() const
{
std::ostringstream os;
os << "hw-item:["
<< "rc:" << item_rc.to_string() << " data:" << item_data.to_string()
<< "]";
return (os.str());
}
private:
/**
* The data
*/
T item_data;
/**
* The result when the item was written
*/
rc_t item_rc;
};
/**
* The pipe to VPP into which we write the commands
*/
class cmd_q
{
public:
/**
* Constructor
*/
cmd_q();
/**
* Destructor
*/
~cmd_q();
/**
* Copy assignement - only used in UT
*/
cmd_q& operator=(const cmd_q& f);
/**
* Enqueue a command into the Q.
*/
virtual void enqueue(cmd* c);
/**
* Enqueue a command into the Q.
*/
virtual void enqueue(std::shared_ptr<cmd> c);
/**
* Enqueue a set of commands
*/
virtual void enqueue(std::queue<cmd*>& c);
/**
* Write all the commands to HW
*/
virtual rc_t write();
/**
* Blocking Connect to VPP - call once at bootup
*/
virtual void connect();
/**
* Disable the passing of commands to VPP. Whilst disabled all
* writes will be discarded. Use this during the reset phase.
*/
void disable();
/**
* Enable the passing of commands to VPP - undoes the disable.
* The Q is enabled by default.
*/
void enable();
private:
/**
* A queue of enqueued commands, ready to be written
*/
std::deque<std::shared_ptr<cmd>> m_queue;
/**
* A map of issued, but uncompleted, commands.
* i.e. those that we are waiting, async stylee,
* for VPP to complete
*/
std::map<cmd*, std::shared_ptr<cmd>> m_pending;
/**
* VPP Q poll function
*/
void rx_run();
/**
* The thread object running the poll/dispatch/connect thread
*/
std::unique_ptr<std::thread> m_rx_thread;
/**
* A flag indicating the client has disabled the cmd Q.
*/
bool m_enabled;
/**
* A flag for the thread to poll to see if the queue is still alive
*/
bool m_connected;
/**
* The connection to VPP
*/
connection m_conn;
};
/**
* Initialise the HW connection to VPP - the UT version passing
* a mock Q.
*/
static void init(cmd_q* f);
/**
* Initialise the HW
*/
static void init();
/**
* Enqueue A command for execution
*/
static void enqueue(cmd* f);
/**
* Enqueue A command for execution
*/
static void enqueue(std::shared_ptr<cmd> c);
/**
* Enqueue A set of commands for execution
*/
static void enqueue(std::queue<cmd*>& c);
/**
* Write/Execute all commands hitherto enqueued.
*/
static rc_t write();
/**
* Blocking Connect to VPP
*/
static void connect();
/**
* Blocking pool of the HW connection
*/
static bool poll();
private:
/**
* The command Q toward HW
*/
static cmd_q* m_cmdQ;
/**
* HW::item representing the connection state as determined by polling
*/
static HW::item<bool> m_poll_state;
/**
* Disable the passing of commands to VPP. Whilst disabled all writes
* will be discarded. Use this during the reset phase.
*/
static void disable();
/**
* Enable the passing of commands to VPP - undoes the disable.
* The Q is enabled by default.
*/
static void enable();
/**
* Only the OM can enable/disable HW
*/
friend class OM;
};
/**
* bool Specialisation for HW::item to_string
*/
template <>
std::string HW::item<bool>::to_string() const;
/**
* uint Specialisation for HW::item to_string
*/
template <>
std::string HW::item<unsigned int>::to_string() const;
};
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/
#endif