| /* |
| * This file is part of the PulseView project. |
| * |
| * Copyright (C) 2014 Joel Holdsworth <joel@airwebreathe.org.uk> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include "storesession.h" |
| |
| #include <pv/sigsession.h> |
| #include <pv/data/logic.h> |
| #include <pv/data/logicsnapshot.h> |
| #include <pv/view/signal.h> |
| |
| using boost::dynamic_pointer_cast; |
| using boost::mutex; |
| using boost::shared_ptr; |
| using boost::thread; |
| using boost::lock_guard; |
| using std::deque; |
| using std::make_pair; |
| using std::min; |
| using std::pair; |
| using std::set; |
| using std::string; |
| using std::vector; |
| |
| namespace pv { |
| |
| const size_t StoreSession::BlockSize = 1024 * 1024; |
| |
| StoreSession::StoreSession(const std::string &file_name, |
| const SigSession &session) : |
| _file_name(file_name), |
| _session(session), |
| _units_stored(0), |
| _unit_count(0) |
| { |
| } |
| |
| StoreSession::~StoreSession() |
| { |
| wait(); |
| } |
| |
| pair<uint64_t, uint64_t> StoreSession::progress() const |
| { |
| lock_guard<mutex> lock(_mutex); |
| return make_pair(_units_stored, _unit_count); |
| } |
| |
| const QString& StoreSession::error() const |
| { |
| lock_guard<mutex> lock(_mutex); |
| return _error; |
| } |
| |
| bool StoreSession::start() |
| { |
| set< shared_ptr<data::SignalData> > data_set = |
| _session.get_data(); |
| const vector< shared_ptr<view::Signal> > sigs = |
| _session.get_signals(); |
| |
| // Check we have logic data |
| if (data_set.empty() || sigs.empty()) { |
| _error = tr("No data to save."); |
| return false; |
| } |
| |
| if (data_set.size() > 1) { |
| _error = tr("PulseView currently only has support for " |
| "storing a single data stream."); |
| return false; |
| } |
| |
| // Get the logic data |
| //shared_ptr<data::SignalData |
| shared_ptr<data::Logic> data; |
| if (!(data = dynamic_pointer_cast<data::Logic>(*data_set.begin()))) { |
| _error = tr("PulseView currently only has support for " |
| "storing a logic data."); |
| return false; |
| } |
| |
| // Get the snapshot |
| const deque< shared_ptr<data::LogicSnapshot> > &snapshots = |
| data->get_snapshots(); |
| |
| if (snapshots.empty()) { |
| _error = tr("No snapshots to save."); |
| return false; |
| } |
| |
| const shared_ptr<data::LogicSnapshot> snapshot(snapshots.front()); |
| assert(snapshot); |
| |
| // Make a list of probes |
| char **const probes = new char*[sigs.size() + 1]; |
| for (size_t i = 0; i < sigs.size(); i++) { |
| shared_ptr<view::Signal> sig(sigs[i]); |
| assert(sig); |
| probes[i] = strdup(sig->get_name().toUtf8().constData()); |
| } |
| probes[sigs.size()] = NULL; |
| |
| // Begin storing |
| if (sr_session_save_init(_file_name.c_str(), |
| data->samplerate(), probes) != SR_OK) { |
| _error = tr("Error while saving."); |
| return false; |
| } |
| |
| // Delete the probes array |
| for (size_t i = 0; i <= sigs.size(); i++) |
| free(probes[i]); |
| delete[] probes; |
| |
| _thread = boost::thread(&StoreSession::store_proc, this, snapshot); |
| return true; |
| } |
| |
| void StoreSession::wait() |
| { |
| if (_thread.joinable()) |
| _thread.join(); |
| } |
| |
| void StoreSession::cancel() |
| { |
| _thread.interrupt(); |
| } |
| |
| void StoreSession::store_proc(shared_ptr<data::LogicSnapshot> snapshot) |
| { |
| assert(snapshot); |
| |
| uint64_t start_sample = 0; |
| |
| /// TODO: Wrap this in a std::unique_ptr when we transition to C++11 |
| uint8_t *const data = new uint8_t[BlockSize]; |
| assert(data); |
| |
| const int unit_size = snapshot->unit_size(); |
| assert(unit_size != 0); |
| |
| { |
| lock_guard<mutex> lock(_mutex); |
| _unit_count = snapshot->get_sample_count(); |
| } |
| |
| const unsigned int samples_per_block = BlockSize / unit_size; |
| |
| while (!boost::this_thread::interruption_requested() && |
| start_sample < _unit_count) |
| { |
| progress_updated(); |
| |
| const uint64_t end_sample = min( |
| start_sample + samples_per_block, _unit_count); |
| snapshot->get_samples(data, start_sample, end_sample); |
| |
| if(sr_session_append(_file_name.c_str(), data, unit_size, |
| end_sample - start_sample) != SR_OK) |
| { |
| _error = tr("Error while saving."); |
| break; |
| } |
| |
| start_sample = end_sample; |
| |
| { |
| lock_guard<mutex> lock(_mutex); |
| _units_stored = start_sample; |
| } |
| } |
| |
| progress_updated(); |
| |
| delete[] data; |
| } |
| |
| } // pv |