]> sigrok.org Git - pulseview.git/blob - pv/storesession.cpp
3d0f12fe7cb66b79027125bbc4a3363fdbeadc91
[pulseview.git] / pv / storesession.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2014 Joel Holdsworth <joel@airwebreathe.org.uk>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include "storesession.h"
22
23 #include <pv/sigsession.h>
24 #include <pv/data/logic.h>
25 #include <pv/data/logicsnapshot.h>
26 #include <pv/view/signal.h>
27
28 using boost::dynamic_pointer_cast;
29 using boost::mutex;
30 using boost::shared_ptr;
31 using boost::thread;
32 using boost::lock_guard;
33 using std::deque;
34 using std::make_pair;
35 using std::min;
36 using std::pair;
37 using std::set;
38 using std::string;
39 using std::vector;
40
41 namespace pv {
42
43 const size_t StoreSession::BlockSize = 1024 * 1024;
44
45 StoreSession::StoreSession(const std::string &file_name,
46         const SigSession &session) :
47         _file_name(file_name),
48         _session(session),
49         _units_stored(0),
50         _unit_count(0)
51 {
52 }
53
54 StoreSession::~StoreSession()
55 {
56         wait();
57 }
58
59 pair<uint64_t, uint64_t> StoreSession::progress() const
60 {
61         lock_guard<mutex> lock(_mutex);
62         return make_pair(_units_stored, _unit_count);
63 }
64
65 const QString& StoreSession::error() const
66 {
67         lock_guard<mutex> lock(_mutex);
68         return _error;
69 }
70
71 bool StoreSession::start()
72 {
73         set< shared_ptr<data::SignalData> > data_set =
74                 _session.get_data();
75         const vector< shared_ptr<view::Signal> > sigs =
76                 _session.get_signals();
77
78         // Check we have logic data
79         if (data_set.empty() || sigs.empty()) {
80                 _error = tr("No data to save.");
81                 return false;
82         }
83
84         if (data_set.size() > 1) {
85                 _error = tr("PulseView currently only has support for "
86                         "storing a single data stream.");
87                 return false;
88         }
89
90         // Get the logic data
91         //shared_ptr<data::SignalData
92         shared_ptr<data::Logic> data;
93         if (!(data = dynamic_pointer_cast<data::Logic>(*data_set.begin()))) {
94                 _error = tr("PulseView currently only has support for "
95                         "storing a logic data.");
96                 return false;
97         }
98
99         // Get the snapshot
100         const deque< shared_ptr<data::LogicSnapshot> > &snapshots =
101                 data->get_snapshots();
102
103         if (snapshots.empty()) {
104                 _error = tr("No snapshots to save.");
105                 return false;
106         }
107
108         const shared_ptr<data::LogicSnapshot> snapshot(snapshots.front());
109         assert(snapshot);
110
111         // Make a list of probes
112         char **const probes = new char*[sigs.size() + 1];
113         for (size_t i = 0; i < sigs.size(); i++) {
114                 shared_ptr<view::Signal> sig(sigs[i]);
115                 assert(sig);
116                 probes[i] = strdup(sig->get_name().toUtf8().constData());
117         }
118         probes[sigs.size()] = NULL;
119
120         // Begin storing
121         if (sr_session_save_init(_file_name.c_str(),
122                 data->samplerate(), probes) != SR_OK) {
123                 _error = tr("Error while saving.");
124                 return false;
125         }
126
127         // Delete the probes array
128         for (size_t i = 0; i <= sigs.size(); i++)
129                 free(probes[i]);
130         delete[] probes;
131
132         _thread = boost::thread(&StoreSession::store_proc, this, snapshot);
133         return true;
134 }
135
136 void StoreSession::wait()
137 {
138         if (_thread.joinable())
139                 _thread.join();
140 }
141
142 void StoreSession::cancel()
143 {
144         _thread.interrupt();
145 }
146
147 void StoreSession::store_proc(shared_ptr<data::LogicSnapshot> snapshot)
148 {
149         assert(snapshot);
150
151         uint64_t start_sample = 0;
152
153         /// TODO: Wrap this in a std::unique_ptr when we transition to C++11
154         uint8_t *const data = new uint8_t[BlockSize];
155         assert(data);
156
157         const int unit_size = snapshot->unit_size();
158         assert(unit_size != 0);
159
160         {
161                 lock_guard<mutex> lock(_mutex);
162                 _unit_count = snapshot->get_sample_count();
163         }
164
165         const unsigned int samples_per_block = BlockSize / unit_size;
166
167         while (!boost::this_thread::interruption_requested() &&
168                 start_sample < _unit_count)
169         {
170                 progress_updated();
171
172                 const uint64_t end_sample = min(
173                         start_sample + samples_per_block, _unit_count);
174                 snapshot->get_samples(data, start_sample, end_sample);
175
176                 if(sr_session_append(_file_name.c_str(), data, unit_size,
177                         end_sample - start_sample) != SR_OK)
178                 {
179                         _error = tr("Error while saving.");
180                         break;
181                 }
182
183                 start_sample = end_sample;
184
185                 {
186                         lock_guard<mutex> lock(_mutex);
187                         _units_stored = start_sample;
188                 }
189         }
190
191         progress_updated();
192
193         delete[] data;
194 }
195
196 } // pv