BlinkenArea - GitList
Repositories
Blog
Wiki
Blinker
Code
Commits
Branches
Tags
Search
Tree:
8b98b69
Branches
Tags
master
Blinker
src
noarch
Output.cpp
retry harder to output data fast, update to current frame quickly if last frame had been dropped
Stefan Schuermans
commited
8b98b69
at 2011-12-27 19:23:46
Output.cpp
Blame
History
Raw
/* Blinker Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #include <string> #include <BlinkenLib/BlinkenFrame.h> #include <BlinkenLib/BlinkenProto.h> #include "Device.h" #include "Directory.h" #include "File.h" #include "InStreamFile.h" #include "Mgrs.h" #include "Module.h" #include "NameFile.h" #include "Output.h" #include "Protocol.h" #include "ProtocolFile.h" #include "SerCfgFile.h" #include "StreamRecv.h" #include "Time.h" #include "TimeCallee.h" namespace Blinker { /** * @brief constructor * @param[in] name module name * @param[in] mgrs managers * @param[in] dirBase base directory */ Output::Output(const std::string &name, Mgrs &mgrs, const Directory &dirBase): Module(name, mgrs, dirBase), m_fileInStream(dirBase.getFile("instream"), mgrs.m_streamMgr), m_fileProtocol(dirBase.getFile("protocol")), m_fileDevice(dirBase.getFile("device")), m_fileSerCfg(dirBase.getFile("ser_cfg")), m_pDevice(NULL) { // set up m_fileInStream.setStreamRecv(this); readProto(); openDevice(); } /// virtual destructor Output::~Output() { // clean up closeDevice(); m_fileInStream.setStreamRecv(NULL); m_mgrs.m_callMgr.cancelTimeCall(this); } /// check for update of configuration void Output::updateConfig() { // input stream name file was modified -> re-get input stream if (m_fileInStream.checkModified()) m_fileInStream.update(); // protocol file was modified -> re-read protocol if (m_fileProtocol.checkModified()) readProto(); // device file or serial settings file was modified -> re-open device if (m_fileDevice.checkModified() || m_fileSerCfg.checkModified()) openDevice(); } /** * @brief set current frame * @param[in] stream stream name * @param[in] pFrame current frame (NULL for none) */ void Output::setFrame(const std::string &stream, stBlinkenFrame *pFrame) { outputFrame(); (void)stream; // unused (void)pFrame; // unused } /// callback when requested time reached void Output::timeCall() { // device is not open -> try to (re-)open it if (!m_pDevice) { openDevice(); return; } // buffer not empty -> try to output rest of data if (!m_buffer.empty()) { outputBufferedData(); return; } // (re-)output current frame outputFrame(); } /// (re-)read protocol void Output::readProto() { // update protocol from file m_fileProtocol.update(); // re-output current frame using new protocol outputFrame(); } /// open device void Output::openDevice() { closeDevice(); // get new device name and new serial config m_fileDevice.update(); m_fileSerCfg.update(); // open device if (m_fileDevice.m_valid) m_pDevice = new Device(m_fileDevice.m_obj.m_str); // serial config available -> configure serial port if (m_pDevice && m_fileSerCfg.m_valid) { if (!m_pDevice->setSerCfg(m_fileSerCfg.m_obj)) closeDevice(); // error -> close device } // output current frame to device outputFrame(); } /// close device void Output::closeDevice() { // close device if (m_pDevice) { delete m_pDevice; m_pDevice = NULL; } // reset internal status m_buffer.clear(); m_dropped = false; updateTimeCallback(); } /// output current frame to device void Output::outputFrame() { stBlinkenFrame *pFrame; char buf[65536]; int len; std::string data; // no protocol or no device -> leave if (!m_fileProtocol.m_valid || !m_pDevice) return; // get current frame from input stream pFrame = m_fileInStream.getCurFrame(); // convert frame to protocol data if (pFrame) len = BlinkenFrameToNetwork(pFrame, m_fileProtocol.m_obj.m_proto, buf, sizeof(buf)); else len = BlinkenProtoMakePacket(m_fileProtocol.m_obj.m_proto, BlinkenPacketStreamEnd, buf, sizeof(buf)); if (len < 0) len = 0; data.assign(buf, len); outputFrameData(data); updateTimeCallback(); } /** * @brief output frame data to device * @param[in] data data of one frame to output to device */ void Output::outputFrameData(const std::string &data) { // add data to buffer (if current buffer contains less than 10 frames) if (m_buffer.size() < data.size() * 10) { m_buffer += data; m_dropped = false; // last frame was not dropped } else { m_dropped = true; // remember that last frame was dropped } outputBufferedData(); } /// write data in output buffer to device void Output::outputBufferedData() { // no device -> forget buffered data, leave if (!m_pDevice) { m_buffer.clear(); return; } // write (at least some) data to device std::string::size_type len; if (!m_pDevice->write(m_buffer, len)) { closeDevice(); // error -> close device return; } // remove written data from buffer m_buffer = m_buffer.substr(len); updateTimeCallback(); } /// update time callback request void Output::updateTimeCallback() { /* no device -> call in 1s for re-opening device buffer empty, last frame not dropped -> call in 1s for re-outputting buffer not empty -> call in 50ms for outputting more data last frame dropped -> call in 50ms for frame update */ Time delay(1); if (m_pDevice && (!m_buffer.empty() || m_dropped)) delay.fromMs(50); m_mgrs.m_callMgr.requestTimeCall(this, Time::now() + delay); } } // namespace Blinker