HardwareCanSinkCanfile.cpp
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // This file is part of FZIs ic_workspace.
5 //
6 // This program is free software licensed under the LGPL
7 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
8 // You can find a copy of this license in LICENSE folder in the top
9 // directory of the source code.
10 //
11 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
12 //
13 // -- END LICENSE BLOCK ------------------------------------------------
14 
15 //----------------------------------------------------------------------
24 //----------------------------------------------------------------------
25 #include "HardwareCanSinkCanfile.h"
26 
27 #include <iomanip>
28 #include <boost/date_time.hpp>
29 
30 #include <icl_sourcesink/SimpleURI.h>
33 
34 namespace icl_hardware {
35 namespace can {
36 
37 HardwareCanSinkCanfile::HardwareCanSinkCanfile(const std::string& uri, const std::string& name)
38  : HardwareCanSink(uri, name),
39  m_data_file(),
40  m_msg_container(),
41  m_msg_container_size(500),
42  m_commit_timediff(boost::posix_time::seconds(1)),
43  m_last_msg_time(),
44  m_last_commit_time()
45 {
46  if (!prepareFile())
47  {
48  LOGGING_WARNING(CAN, "Failed to open URI " << uri << " for recording!" << endl);
49  return;
50  }
51 
53 }
54 
56 { }
57 
59 {
60  icl_sourcesink::SimpleURI parsed_uri(uri());
61 
62  // Extract message container size.
63  boost::optional<std::size_t> msg_container_size = parsed_uri.getQuery<std::size_t>("container_size");
64  if (msg_container_size)
65  {
66  if (msg_container_size > 0)
67  {
68  m_msg_container_size = *msg_container_size;
69  }
70  else
71  {
72  LOGGING_ERROR(CAN, "container_size must be > 0. Using default value " << m_msg_container_size << "." << endl);
73  }
74  }
75 
76  // Ensure the filename ends in ".can".
77  std::string can_filename = parsed_uri.path();
78  if (can_filename.size() < 4 || can_filename.substr(can_filename.size()-4) != ".can")
79  {
80  can_filename += ".can";
81  }
82 
83  m_data_file.open(can_filename.c_str());
84  if (!m_data_file)
85  {
86  LOGGING_ERROR(CAN, "Failed to open data file '" << m_data_file << "'." << endl);
87  return false;
88  }
89 
90  // Write file header.
91  m_data_file << "# FZI-CAN Stream version " << cMAJOR_FILEVERSION << "." << cMINOR_FILEVERSION << std::endl;
92 
93  return true;
94 }
95 
97 {
98  if (!msg || ((*msg)->id == 0 && (*msg)->dlc == 0 && (*msg)->rtr == 0))
99  {
100  throw(tException(eMESSAGE_ERROR, "Received empty message"));
101  }
102 
103  if (!m_last_msg_time.is_special() && msg->header().timestamp < m_last_msg_time)
104  {
105  LOGGING_WARNING(CAN, "CAN message sequence out of order! (" << msg->header().timestamp << " < " << m_last_msg_time << ")" << endl);
106  }
107  m_msg_container.push_back(msg);
108 
110  || m_last_commit_time + m_commit_timediff > msg->header().timestamp)
111  {
112  if (m_data_file.bad())
113  {
114  throw tException(eFILE_ERROR, "Data file stream went bad.");
115  }
116 
117  // Write content to file.
118  m_data_file << std::setfill('0');
119  for (std::vector<CanMessageStamped::ConstPtr>::const_iterator iter = m_msg_container.begin();
120  iter != m_msg_container.end(); ++iter)
121  {
122  // Build unix timestamp.
123  boost::posix_time::time_duration time_since_epoch
124  = (*iter)->header().timestamp - boost::posix_time::from_time_t(0);
125  uint64_t seconds = time_since_epoch.ticks() / boost::posix_time::time_duration::ticks_per_second();
126  long microseconds = time_since_epoch.fractional_seconds() / (boost::posix_time::time_duration::ticks_per_second() / 1000000);
127  m_data_file << std::dec << seconds << "." << std::setw(6) << microseconds
128  << " " << (**iter)->id << " " << unsigned((**iter)->dlc)
129  << std::hex
130  << " " << std::setw(2) << unsigned((**iter)->data[0])
131  << " " << std::setw(2) << unsigned((**iter)->data[1])
132  << " " << std::setw(2) << unsigned((**iter)->data[2])
133  << " " << std::setw(2) << unsigned((**iter)->data[3])
134  << " " << std::setw(2) << unsigned((**iter)->data[4])
135  << " " << std::setw(2) << unsigned((**iter)->data[5])
136  << " " << std::setw(2) << unsigned((**iter)->data[6])
137  << " " << std::setw(2) << unsigned((**iter)->data[7])
138  << "\n";
139 
140  if (m_data_file.bad())
141  {
142  throw tException(eFILE_ERROR, "Stream went bad while writing to file.");
143  }
144  }
145 
146  m_last_commit_time = msg->header().timestamp;
147  m_msg_container.clear();
148  }
149  m_last_msg_time = msg->header().timestamp;
150 }
151 
152 }
153 }
icl_sourcesink::DataSink< tCanMessage > HardwareCanSink
Base type for all sinks providing tCanMessage data.
Contains icl_hardware::tException.
std::vector< CanMessageStamped::ConstPtr > m_msg_container
HardwareCanSinkCanfile(const std::string &uri="HardwareCanSinkCanfile", const std::string &name="UnnamedHardwareCanSinkCanfile")
Constructor.
boost::posix_time::ptime m_last_msg_time
Timestamp of the last processed message.
std::ofstream m_data_file
CAN data file stream.
boost::shared_ptr< Stamped< DataType > > Ptr
#define LOGGING_ERROR(streamname, arg)
unsigned __int64 uint64_t
static const short cMAJOR_FILEVERSION
Major version number of the file format.
ThreadStream & endl(ThreadStream &stream)
#define LOGGING_WARNING(streamname, arg)
static const short cMINOR_FILEVERSION
Minor version number of the file format.
boost::posix_time::time_duration m_commit_timediff
boost::posix_time::ptime m_last_commit_time
Time at which the last message was committed to disk.
bool prepareFile()
Opens the output file and writes the file header.
virtual void set(const CanMessageStamped::Ptr &msg)


fzi_icl_can
Author(s):
autogenerated on Mon Jun 10 2019 13:17:02