Skip to content

Commit

Permalink
Update of Log to sync the command time.
Browse files Browse the repository at this point in the history
  • Loading branch information
branoholy committed Feb 23, 2016
1 parent 01164b4 commit fa5b582
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 110 deletions.
21 changes: 14 additions & 7 deletions include/regilo/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class Controller
* @brief Get the current Log (a const variant).
* @return The Log or nullptr
*/
virtual const std::shared_ptr<Log>& getLog() const = 0;
virtual std::shared_ptr<const Log> getLog() const = 0;

/**
* @brief Set a Log (it can be shared between more controllers).
Expand Down Expand Up @@ -105,7 +105,7 @@ class BaseController : public Controller
ba::io_service ioService;
Stream stream;

std::shared_ptr<Log> log;
std::shared_ptr<BasicLog> log;

virtual std::string sendCommand() final;

Expand Down Expand Up @@ -141,10 +141,10 @@ class BaseController : public Controller

virtual inline bool isConnected() const override { return stream.is_open(); }

virtual std::shared_ptr<Log> getLog() override { return log; }
virtual const std::shared_ptr<Log>& getLog() const override { return log; }
virtual inline std::shared_ptr<Log> getLog() override { return log; }
virtual inline std::shared_ptr<const Log> getLog() const override { return log; }

virtual void setLog(std::shared_ptr<Log> log) override { this->log.swap(log); }
virtual void setLog(std::shared_ptr<Log> log) override;

/**
* @brief Send a command to the device.
Expand Down Expand Up @@ -189,14 +189,14 @@ BaseController<Stream>::BaseController(const std::string& logPath) : BaseControl
{
if(logPath.length() > 0)
{
log.reset(new Log(logPath));
log.reset(new BasicLog(logPath));
}
}

template<typename Stream>
BaseController<Stream>::BaseController(std::iostream& logStream) : BaseController()
{
this->log.reset(new Log(logStream));
this->log.reset(new BasicLog(logStream));
}

template<typename Stream>
Expand All @@ -205,6 +205,13 @@ BaseController<Stream>::~BaseController()
if(stream.is_open()) stream.close();
}

template<typename Stream>
void BaseController<Stream>::setLog(std::shared_ptr<Log> log)
{
std::shared_ptr<BasicLog> basicLog = std::dynamic_pointer_cast<BasicLog>(log);
this->log.swap(basicLog);
}

template<typename Stream>
std::string BaseController<Stream>::sendCommand(const std::string& command)
{
Expand Down
167 changes: 127 additions & 40 deletions include/regilo/log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,103 +22,190 @@
#ifndef REGILO_LOG_HPP
#define REGILO_LOG_HPP

#include <chrono>
#include <fstream>
#include <iostream>
#include <limits>
#include <sstream>
#include <thread>

#include <boost/algorithm/string/predicate.hpp>

#include "regilo/utils.hpp"

namespace regilo {

/**
* @brief The Log class is used to log all commands that were send to the device.
*/
class Log
{
private:
std::string filePath;
std::fstream *fileStream;

std::iostream& stream;

long commandTime;

public:
static char MESSAGE_END;

/**
* @brief Log constructor with logging to a file.
* @param filePath The path of file
*/
Log(const std::string& filePath);

/**
* @brief Log constructor with logging to a stream.
* @param stream Input/output stream
*/
Log(std::iostream& stream);

/**
* @brief Default destructor.
*/
virtual ~Log();
virtual ~Log() = default;

/**
* @brief Get the path of file if the log was created with a path otherwise the empty string.
* @return The path or empty string.
*/
inline const std::string& getFilePath() const { return filePath; }
virtual const std::string& getFilePath() const = 0;

/**
* @brief Get the current underlying stream.
* @return The underlying stream
*/
inline std::iostream& getStream() { return stream; }
virtual std::iostream& getStream() = 0;

/**
* @brief Test if the stream is EOF.
* @return true/false
*/
inline bool isEnd() const { return !stream; }

/**
* @brief Get the last command time (after reading).
* @return Seconds since epoch
*/
inline long getLastCommandTime() const { return commandTime; }
virtual bool isEnd() const = 0;

/**
* @brief Read one command from the log.
* @return The response of the command.
*/
std::string read();
virtual std::string read() = 0;

/**
* @brief Read one command from the log.
* @param logCommand The input of the command that was read.
* @return The response of the command.
*/
std::string read(std::string& logCommand);
virtual std::string read(std::string& logCommand) = 0;

/**
* @brief Read specified command from the log (the others are skipped).
* @param command The command to read (The boost::algorithm::starts_with() method is used to compare).
* @return The response of the command.
*/
std::string readCommand(const std::string& command);
virtual std::string readCommand(const std::string& command) = 0;

/**
* @brief Read specified command from the log (the others are skipped).
* @param command The command to read (The boost::algorithm::starts_with() method is used to compare).
* @param logCommand The input of the command that was read.
* @return The response of the command.
*/
std::string readCommand(const std::string& command, std::string& logCommand);
virtual std::string readCommand(const std::string& command, std::string& logCommand) = 0;

/**
* @brief Write a command and response to the log.
* @param command The command (with all parameters).
* @param response The response of the command.
*/
void write(const std::string& command, const std::string& response);
virtual void write(const std::string& command, const std::string& response) = 0;
};

class BasicLog : public Log
{
private:
std::string filePath;
std::fstream *fileStream;

protected:
std::iostream& stream;

public:
char MESSAGE_END = '$';

/**
* @brief Log constructor with logging to a file.
* @param filePath The path of file
*/
BasicLog(const std::string& filePath);

/**
* @brief Log constructor with logging to a stream.
* @param stream Input/output stream
*/
BasicLog(std::iostream& stream);

virtual ~BasicLog();

virtual inline const std::string& getFilePath() const override { return filePath; }
virtual inline std::iostream& getStream() override { return stream; }
virtual inline bool isEnd() const override { return !stream; }

virtual std::string read() override;
virtual std::string read(std::string& logCommand) override;
virtual std::string readCommand(const std::string& command) override;
virtual std::string readCommand(const std::string& command, std::string& logCommand) override;

virtual void write(const std::string& command, const std::string& response) override;
};

/**
* @brief The Log class is used to log all commands that were send to the device.
*/
template<typename Duration = std::chrono::milliseconds>
class TimedLog : public BasicLog
{
private:
typename Duration::rep commandTime;

typename Duration::rep firstReadTime;
typename Duration::rep firstCommandTime = std::numeric_limits<typename Duration::rep>::max();

public:
using BasicLog::BasicLog;

virtual ~TimedLog() = default;

/**
* @brief Get last command time (after reading).
* @return Time since epoch in Duration units
*/
inline typename Duration::rep getLastCommandTime() const { return commandTime; }

/**
* @brief Sync command times with real time. It means that all read methods will block
* its execution until the current time is bigger than the command time.
*/
inline void syncTime(bool sync = true) { firstCommandTime = (sync ? -1 : std::numeric_limits<long>::max()); }

virtual std::string read(std::string& logCommand) override;
virtual void write(const std::string& command, const std::string& response) override;
};

template<typename Duration>
std::string TimedLog<Duration>::read(std::string& logCommand)
{
std::string epochTime;
std::getline(stream, epochTime, MESSAGE_END);
std::istringstream epochStream(epochTime);
epochStream >> commandTime;

std::string response = BasicLog::read(logCommand); // TODO: Swap with time

if(firstCommandTime == -1)
{
firstReadTime = epoch<Duration>();
firstCommandTime = commandTime;
}
else
{
typename Duration::rep elapsed = epoch<Duration>() - firstReadTime;
typename Duration::rep elapsedLog = commandTime - firstCommandTime;

while(elapsed < elapsedLog)
{
std::this_thread::sleep_for(Duration(elapsedLog - elapsed));
elapsed = epoch<Duration>() - firstReadTime;
}
}

return response;
}

template<typename Duration>
void TimedLog<Duration>::write(const std::string& command, const std::string& response)
{
stream << epoch<Duration>() << MESSAGE_END;

BasicLog::write(command, response); // TODO: Swap with time
}

}

#endif // REGILO_LOG_HPP
8 changes: 4 additions & 4 deletions include/regilo/scancontroller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ScanController : public Controller
virtual bool isConnected() const override = 0;
virtual std::string getEndpoint() const override = 0;
virtual std::shared_ptr<Log> getLog() override = 0;
virtual const std::shared_ptr<Log>& getLog() const override = 0;
virtual std::shared_ptr<const Log> getLog() const override = 0;
virtual void setLog(std::shared_ptr<Log> log) override = 0;

/**
Expand Down Expand Up @@ -67,7 +67,7 @@ class BaseScanController : public ScanController, public ProtocolController
virtual inline bool isConnected() const override { return ProtocolController::isConnected(); }
virtual inline std::string getEndpoint() const override { return ProtocolController::getEndpoint(); }
virtual inline std::shared_ptr<Log> getLog() override { return ProtocolController::getLog(); }
virtual inline const std::shared_ptr<Log>& getLog() const override { return ProtocolController::getLog(); }
virtual inline std::shared_ptr<const Log> getLog() const override { return ProtocolController::getLog(); }
virtual inline void setLog(std::shared_ptr<Log> log) override { return ProtocolController::setLog(log); }

virtual ScanData getScan(bool fromDevice = true) override final;
Expand Down Expand Up @@ -99,14 +99,14 @@ ScanData BaseScanController<ProtocolController>::getScan(bool fromDevice)
if(fromDevice)
{
this->sendCommand(getScanCommand());
data.time = epochSeconds();
data.time = epoch<std::chrono::seconds>();

parseScanData(this->deviceOutput, data);
}
else
{
std::istringstream response(this->log->readCommand(getScanCommand()));
data.time = this->log->getLastCommandTime();
// data.time = this->log->getLastCommandTime(); // TODO: Set from log

parseScanData(response, data);
}
Expand Down
13 changes: 10 additions & 3 deletions include/regilo/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@
#ifndef REGILO_UTILS_HPP
#define REGILO_UTILS_HPP

#include <chrono>

namespace regilo {

/**
* @brief Get seconds since epoch.
* @return Seconds
* @brief Get time since epoch.
* @return Time in (s, ms, etc.)
*/
long epochSeconds();
template<typename T>
typename T::rep epoch()
{
auto sinceEpoch = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration_cast<T>(sinceEpoch).count();
}

}

Expand Down
Loading

0 comments on commit fa5b582

Please sign in to comment.