mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-06-02 14:04:46 -04:00
git clone git://git.osmocom.org/sdrangelove.git
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
#ifndef INCLUDE_CHANNELMARKER_H
|
||||
#define INCLUDE_CHANNELMARKER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QColor>
|
||||
#include "util/export.h"
|
||||
|
||||
class SDRANGELOVE_API ChannelMarker : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChannelMarker(QObject* parent = NULL);
|
||||
|
||||
void setTitle(const QString& title);
|
||||
const QString& getTitle() const { return m_title; }
|
||||
|
||||
void setCenterFrequency(int centerFrequency);
|
||||
int getCenterFrequency() const { return m_centerFrequency; }
|
||||
|
||||
void setBandwidth(int bandwidth);
|
||||
int getBandwidth() const { return m_bandwidth; }
|
||||
|
||||
void setVisible(bool visible);
|
||||
bool getVisible() const { return m_visible; }
|
||||
|
||||
void setColor(const QColor& color);
|
||||
const QColor& getColor() const { return m_color; }
|
||||
|
||||
protected:
|
||||
static QRgb m_colorTable[];
|
||||
static int m_nextColor;
|
||||
|
||||
QString m_title;
|
||||
int m_centerFrequency;
|
||||
int m_bandwidth;
|
||||
bool m_visible;
|
||||
QColor m_color;
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_CHANNELMARKER_H
|
||||
@@ -0,0 +1,54 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// 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 as version 3 of the License, or //
|
||||
// //
|
||||
// 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 V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_DSPTYPES_H
|
||||
#define INCLUDE_DSPTYPES_H
|
||||
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
#include <QtGlobal>
|
||||
|
||||
typedef float Real;
|
||||
typedef std::complex<Real> Complex;
|
||||
|
||||
typedef qint16 FixReal;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Sample {
|
||||
Sample() {}
|
||||
Sample(FixReal real) : m_real(real), m_imag(0) {}
|
||||
Sample(FixReal real, FixReal imag) : m_real(real), m_imag(imag) {}
|
||||
Sample(const Sample& other) : m_real(other.m_real), m_imag(other.m_imag) {}
|
||||
Sample& operator=(const Sample& other) { m_real = other.m_real; m_imag = other.m_imag; return *this; }
|
||||
|
||||
Sample& operator+=(const Sample& other) { m_real += other.m_real; m_imag += other.m_imag; return *this; }
|
||||
Sample& operator-=(const Sample& other) { m_real -= other.m_real; m_imag -= other.m_imag; return *this; }
|
||||
|
||||
void setReal(FixReal v) { m_real = v; }
|
||||
void setImag(FixReal v) { m_imag = v; }
|
||||
|
||||
FixReal real() const { return m_real; }
|
||||
FixReal imag() const { return m_imag; }
|
||||
|
||||
FixReal m_real;
|
||||
FixReal m_imag;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef std::vector<Sample> SampleVector;
|
||||
|
||||
#endif // INCLUDE_DSPTYPES_H
|
||||
@@ -0,0 +1,391 @@
|
||||
#ifndef INCLUDE_KISSFFT_H
|
||||
#define INCLUDE_KISSFFT_H
|
||||
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
Copyright (c) 2003-2010 Mark Borgerding
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the author nor the names of any contributors may be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace kissfft_utils {
|
||||
|
||||
template<typename T_scalar, typename T_complex>
|
||||
struct traits {
|
||||
typedef T_scalar scalar_type;
|
||||
typedef T_complex cpx_type;
|
||||
void fill_twiddles(std::complex<T_scalar>* dst, int nfft, bool inverse)
|
||||
{
|
||||
T_scalar phinc = (inverse ? 2 : -2) * acos((T_scalar)-1) / nfft;
|
||||
for(int i = 0; i < nfft; ++i)
|
||||
dst[i] = exp(std::complex<T_scalar>(0, i * phinc));
|
||||
}
|
||||
|
||||
void prepare(std::vector<std::complex<T_scalar> >& dst, int nfft, bool inverse, std::vector<int>& stageRadix, std::vector<int>& stageRemainder)
|
||||
{
|
||||
_twiddles.resize(nfft);
|
||||
fill_twiddles(&_twiddles[0], nfft, inverse);
|
||||
dst = _twiddles;
|
||||
|
||||
//factorize
|
||||
//start factoring out 4's, then 2's, then 3,5,7,9,...
|
||||
int n = nfft;
|
||||
int p = 4;
|
||||
do {
|
||||
while(n % p) {
|
||||
switch(p) {
|
||||
case 4:
|
||||
p = 2;
|
||||
break;
|
||||
case 2:
|
||||
p = 3;
|
||||
break;
|
||||
default:
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
if(p * p > n)
|
||||
p = n;// no more factors
|
||||
}
|
||||
n /= p;
|
||||
stageRadix.push_back(p);
|
||||
stageRemainder.push_back(n);
|
||||
} while(n > 1);
|
||||
}
|
||||
std::vector<cpx_type> _twiddles;
|
||||
|
||||
const cpx_type twiddle(int i)
|
||||
{
|
||||
return _twiddles[i];
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
template<typename T_Scalar, typename T_Complex, typename T_traits = kissfft_utils::traits<T_Scalar, T_Complex> >
|
||||
class kissfft {
|
||||
public:
|
||||
typedef T_traits traits_type;
|
||||
typedef typename traits_type::scalar_type scalar_type;
|
||||
typedef typename traits_type::cpx_type cpx_type;
|
||||
|
||||
kissfft()
|
||||
{
|
||||
}
|
||||
|
||||
kissfft(int nfft, bool inverse, const traits_type & traits = traits_type()) :
|
||||
_nfft(nfft), _inverse(inverse), _traits(traits)
|
||||
{
|
||||
_traits.prepare(_twiddles, _nfft, _inverse, _stageRadix, _stageRemainder);
|
||||
}
|
||||
|
||||
void configure(int nfft, bool inverse, const traits_type & traits = traits_type())
|
||||
{
|
||||
_twiddles.clear();
|
||||
_stageRadix.clear();
|
||||
_stageRemainder.clear();
|
||||
|
||||
_nfft = nfft;
|
||||
_inverse = inverse;
|
||||
_traits = traits;
|
||||
_traits.prepare(_twiddles, _nfft, _inverse, _stageRadix, _stageRemainder);
|
||||
}
|
||||
|
||||
void transform(const cpx_type* src, cpx_type* dst)
|
||||
{
|
||||
kf_work(0, dst, src, 1, 1);
|
||||
}
|
||||
|
||||
private:
|
||||
void kf_work(int stage, cpx_type* Fout, const cpx_type* f, size_t fstride, size_t in_stride)
|
||||
{
|
||||
int p = _stageRadix[stage];
|
||||
int m = _stageRemainder[stage];
|
||||
cpx_type * Fout_beg = Fout;
|
||||
cpx_type * Fout_end = Fout + p * m;
|
||||
|
||||
if(m == 1) {
|
||||
do {
|
||||
*Fout = *f;
|
||||
f += fstride * in_stride;
|
||||
} while(++Fout != Fout_end);
|
||||
} else {
|
||||
do {
|
||||
// recursive call:
|
||||
// DFT of size m*p performed by doing
|
||||
// p instances of smaller DFTs of size m,
|
||||
// each one takes a decimated version of the input
|
||||
kf_work(stage + 1, Fout, f, fstride * p, in_stride);
|
||||
f += fstride * in_stride;
|
||||
} while((Fout += m) != Fout_end);
|
||||
}
|
||||
|
||||
Fout = Fout_beg;
|
||||
|
||||
// recombine the p smaller DFTs
|
||||
switch(p) {
|
||||
case 2:
|
||||
kf_bfly2(Fout, fstride, m);
|
||||
break;
|
||||
case 3:
|
||||
kf_bfly3(Fout, fstride, m);
|
||||
break;
|
||||
case 4:
|
||||
kf_bfly4(Fout, fstride, m);
|
||||
break;
|
||||
case 5:
|
||||
kf_bfly5(Fout, fstride, m);
|
||||
break;
|
||||
default:
|
||||
kf_bfly_generic(Fout, fstride, m, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// these were #define macros in the original kiss_fft
|
||||
void C_ADD(cpx_type& c, const cpx_type& a, const cpx_type& b)
|
||||
{
|
||||
c = a + b;
|
||||
}
|
||||
void C_MUL(cpx_type& c, const cpx_type& a, const cpx_type& b)
|
||||
{
|
||||
//c = a * b;
|
||||
c = cpx_type(a.real() * b.real() - a.imag() * b.imag(), a.real() * b.imag() + a.imag() * b.real());
|
||||
}
|
||||
void C_SUB(cpx_type& c, const cpx_type& a, const cpx_type& b)
|
||||
{
|
||||
c = a - b;
|
||||
}
|
||||
void C_ADDTO(cpx_type& c, const cpx_type& a)
|
||||
{
|
||||
c += a;
|
||||
}
|
||||
void C_FIXDIV(cpx_type&, int)
|
||||
{
|
||||
} // NO-OP for float types
|
||||
scalar_type S_MUL(const scalar_type& a, const scalar_type& b)
|
||||
{
|
||||
return a * b;
|
||||
}
|
||||
scalar_type HALF_OF(const scalar_type& a)
|
||||
{
|
||||
return a * .5;
|
||||
}
|
||||
void C_MULBYSCALAR(cpx_type& c, const scalar_type& a)
|
||||
{
|
||||
c *= a;
|
||||
}
|
||||
|
||||
void kf_bfly2(cpx_type* Fout, const size_t fstride, int m)
|
||||
{
|
||||
for(int k = 0; k < m; ++k) {
|
||||
//cpx_type t = Fout[m + k] * _traits.twiddle(k * fstride);
|
||||
cpx_type t;
|
||||
C_MUL(t, Fout[m + k], _traits.twiddle(k * fstride));
|
||||
Fout[m + k] = Fout[k] - t;
|
||||
Fout[k] += t;
|
||||
}
|
||||
}
|
||||
|
||||
void kf_bfly4(cpx_type* Fout, const size_t fstride, const size_t m)
|
||||
{
|
||||
cpx_type scratch[7];
|
||||
int negative_if_inverse = _inverse * -2 + 1;
|
||||
for(size_t k = 0; k < m; ++k) {
|
||||
//scratch[0] = Fout[k + m] * _traits.twiddle(k * fstride);
|
||||
C_MUL(scratch[0], Fout[k + m], _traits.twiddle(k * fstride));
|
||||
C_MUL(scratch[1], Fout[k + 2 * m], _traits.twiddle(k * fstride * 2));
|
||||
C_MUL(scratch[2], Fout[k + 3 * m], _traits.twiddle(k * fstride * 3));
|
||||
scratch[5] = Fout[k] - scratch[1];
|
||||
|
||||
Fout[k] += scratch[1];
|
||||
scratch[3] = scratch[0] + scratch[2];
|
||||
scratch[4] = scratch[0] - scratch[2];
|
||||
scratch[4] = cpx_type(scratch[4].imag() * negative_if_inverse, -scratch[4].real() * negative_if_inverse);
|
||||
|
||||
Fout[k + 2 * m] = Fout[k] - scratch[3];
|
||||
Fout[k] += scratch[3];
|
||||
Fout[k + m] = scratch[5] + scratch[4];
|
||||
Fout[k + 3 * m] = scratch[5] - scratch[4];
|
||||
}
|
||||
}
|
||||
|
||||
void kf_bfly3(cpx_type* Fout, const size_t fstride, const size_t m)
|
||||
{
|
||||
size_t k = m;
|
||||
const size_t m2 = 2 * m;
|
||||
cpx_type* tw1;
|
||||
cpx_type* tw2;
|
||||
cpx_type scratch[5];
|
||||
cpx_type epi3;
|
||||
epi3 = _twiddles[fstride * m];
|
||||
tw1 = tw2 = &_twiddles[0];
|
||||
|
||||
do {
|
||||
C_FIXDIV(*Fout, 3);
|
||||
C_FIXDIV(Fout[m], 3);
|
||||
C_FIXDIV(Fout[m2], 3);
|
||||
|
||||
C_MUL(scratch[1], Fout[m], *tw1);
|
||||
C_MUL(scratch[2], Fout[m2], *tw2);
|
||||
|
||||
C_ADD(scratch[3], scratch[1], scratch[2]);
|
||||
C_SUB(scratch[0], scratch[1], scratch[2]);
|
||||
tw1 += fstride;
|
||||
tw2 += fstride * 2;
|
||||
|
||||
Fout[m] = cpx_type(Fout->real() - HALF_OF(scratch[3].real()), Fout->imag() - HALF_OF(scratch[3].imag()));
|
||||
|
||||
C_MULBYSCALAR(scratch[0], epi3.imag());
|
||||
|
||||
C_ADDTO(*Fout, scratch[3]);
|
||||
|
||||
Fout[m2] = cpx_type(Fout[m].real() + scratch[0].imag(), Fout[m].imag() - scratch[0].real());
|
||||
|
||||
C_ADDTO(Fout[m], cpx_type(-scratch[0].imag(), scratch[0].real()));
|
||||
++Fout;
|
||||
} while(--k);
|
||||
}
|
||||
|
||||
void kf_bfly5(cpx_type* Fout, const size_t fstride, const size_t m)
|
||||
{
|
||||
cpx_type* Fout0;
|
||||
cpx_type* Fout1;
|
||||
cpx_type* Fout2;
|
||||
cpx_type* Fout3;
|
||||
cpx_type* Fout4;
|
||||
size_t u;
|
||||
cpx_type scratch[13];
|
||||
cpx_type* twiddles = &_twiddles[0];
|
||||
cpx_type* tw;
|
||||
cpx_type ya, yb;
|
||||
ya = twiddles[fstride * m];
|
||||
yb = twiddles[fstride * 2 * m];
|
||||
|
||||
Fout0 = Fout;
|
||||
Fout1 = Fout0 + m;
|
||||
Fout2 = Fout0 + 2 * m;
|
||||
Fout3 = Fout0 + 3 * m;
|
||||
Fout4 = Fout0 + 4 * m;
|
||||
|
||||
tw = twiddles;
|
||||
for(u = 0; u < m; ++u) {
|
||||
C_FIXDIV(*Fout0, 5);
|
||||
C_FIXDIV(*Fout1, 5);
|
||||
C_FIXDIV(*Fout2, 5);
|
||||
C_FIXDIV(*Fout3, 5);
|
||||
C_FIXDIV(*Fout4, 5);
|
||||
scratch[0] = *Fout0;
|
||||
|
||||
C_MUL(scratch[1], *Fout1, tw[u * fstride]);
|
||||
C_MUL(scratch[2], *Fout2, tw[2 * u * fstride]);
|
||||
C_MUL(scratch[3], *Fout3, tw[3 * u * fstride]);
|
||||
C_MUL(scratch[4], *Fout4, tw[4 * u * fstride]);
|
||||
|
||||
C_ADD(scratch[7], scratch[1], scratch[4]);
|
||||
C_SUB(scratch[10], scratch[1], scratch[4]);
|
||||
C_ADD(scratch[8], scratch[2], scratch[3]);
|
||||
C_SUB(scratch[9], scratch[2], scratch[3]);
|
||||
|
||||
C_ADDTO(*Fout0, scratch[7]);
|
||||
C_ADDTO(*Fout0, scratch[8]);
|
||||
|
||||
scratch[5] = scratch[0] + cpx_type(S_MUL(scratch[7].real(), ya.real()) + S_MUL(scratch[8].real(), yb.real()), S_MUL(scratch[7].imag(), ya.real())
|
||||
+ S_MUL(scratch[8].imag(), yb.real()));
|
||||
|
||||
scratch[6] = cpx_type(S_MUL(scratch[10].imag(), ya.imag()) + S_MUL(scratch[9].imag(), yb.imag()), -S_MUL(scratch[10].real(), ya.imag()) - S_MUL(
|
||||
scratch[9].real(), yb.imag()));
|
||||
|
||||
C_SUB(*Fout1, scratch[5], scratch[6]);
|
||||
C_ADD(*Fout4, scratch[5], scratch[6]);
|
||||
|
||||
scratch[11] = scratch[0] + cpx_type(S_MUL(scratch[7].real(), yb.real()) + S_MUL(scratch[8].real(), ya.real()), S_MUL(scratch[7].imag(), yb.real())
|
||||
+ S_MUL(scratch[8].imag(), ya.real()));
|
||||
|
||||
scratch[12] = cpx_type(-S_MUL(scratch[10].imag(), yb.imag()) + S_MUL(scratch[9].imag(), ya.imag()), S_MUL(scratch[10].real(), yb.imag()) - S_MUL(
|
||||
scratch[9].real(), ya.imag()));
|
||||
|
||||
C_ADD(*Fout2, scratch[11], scratch[12]);
|
||||
C_SUB(*Fout3, scratch[11], scratch[12]);
|
||||
|
||||
++Fout0;
|
||||
++Fout1;
|
||||
++Fout2;
|
||||
++Fout3;
|
||||
++Fout4;
|
||||
}
|
||||
}
|
||||
|
||||
/* perform the butterfly for one stage of a mixed radix FFT */
|
||||
void kf_bfly_generic(cpx_type* Fout, const size_t fstride, int m, int p)
|
||||
{
|
||||
int u;
|
||||
int k;
|
||||
int q1;
|
||||
int q;
|
||||
cpx_type* twiddles = &_twiddles[0];
|
||||
cpx_type t;
|
||||
int Norig = _nfft;
|
||||
cpx_type* scratchbuf = new cpx_type[p];
|
||||
|
||||
for(u = 0; u < m; ++u) {
|
||||
k = u;
|
||||
for(q1 = 0; q1 < p; ++q1) {
|
||||
scratchbuf[q1] = Fout[k];
|
||||
C_FIXDIV(scratchbuf[q1], p);
|
||||
k += m;
|
||||
}
|
||||
|
||||
k = u;
|
||||
for(q1 = 0; q1 < p; ++q1) {
|
||||
int twidx = 0;
|
||||
Fout[k] = scratchbuf[0];
|
||||
for(q = 1; q < p; ++q) {
|
||||
twidx += fstride * k;
|
||||
if(twidx >= Norig)
|
||||
twidx -= Norig;
|
||||
C_MUL(t, scratchbuf[q], twiddles[twidx]);
|
||||
C_ADDTO(Fout[k], t);
|
||||
}
|
||||
k += m;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] scratchbuf;
|
||||
}
|
||||
|
||||
int _nfft;
|
||||
bool _inverse;
|
||||
std::vector<cpx_type> _twiddles;
|
||||
std::vector<int> _stageRadix;
|
||||
std::vector<int> _stageRemainder;
|
||||
traits_type _traits;
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// 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 as version 3 of the License, or //
|
||||
// //
|
||||
// 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 V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_SAMPLEFIFO_H
|
||||
#define INCLUDE_SAMPLEFIFO_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QTime>
|
||||
#include "dsp/dsptypes.h"
|
||||
#include "util/export.h"
|
||||
|
||||
class SDRANGELOVE_API SampleFifo : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QMutex m_mutex;
|
||||
QTime m_msgRateTimer;
|
||||
int m_suppressed;
|
||||
|
||||
SampleVector m_data;
|
||||
|
||||
uint m_size;
|
||||
uint m_fill;
|
||||
uint m_head;
|
||||
uint m_tail;
|
||||
|
||||
void create(uint s);
|
||||
|
||||
public:
|
||||
SampleFifo(QObject* parent = NULL);
|
||||
SampleFifo(int size, QObject* parent = NULL);
|
||||
~SampleFifo();
|
||||
|
||||
bool setSize(int size);
|
||||
inline uint fill() const { return m_fill; }
|
||||
|
||||
uint write(const quint8* data, uint count);
|
||||
uint write(SampleVector::const_iterator begin, SampleVector::const_iterator end);
|
||||
|
||||
uint read(SampleVector::iterator begin, SampleVector::iterator end);
|
||||
|
||||
uint readBegin(uint count,
|
||||
SampleVector::iterator* part1Begin, SampleVector::iterator* part1End,
|
||||
SampleVector::iterator* part2Begin, SampleVector::iterator* part2End);
|
||||
uint readCommit(uint count);
|
||||
|
||||
signals:
|
||||
void dataReady();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SAMPLEFIFO_H
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef INCLUDE_SAMPLESINK_H
|
||||
#define INCLUDE_SAMPLESINK_H
|
||||
|
||||
#include <QObject>
|
||||
#include "dsptypes.h"
|
||||
#include "util/export.h"
|
||||
|
||||
class Message;
|
||||
|
||||
class SDRANGELOVE_API SampleSink : public QObject {
|
||||
public:
|
||||
SampleSink();
|
||||
virtual ~SampleSink();
|
||||
|
||||
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst) = 0;
|
||||
virtual void start() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual bool handleMessage(Message* cmd) = 0;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SAMPLESINK_H
|
||||
@@ -0,0 +1,61 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||
// written by Christian Daniel //
|
||||
// //
|
||||
// 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 as version 3 of the License, or //
|
||||
// //
|
||||
// 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 V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDE_SAMPLESOURCE_H
|
||||
#define INCLUDE_SAMPLESOURCE_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include "dsp/samplefifo.h"
|
||||
#include "util/message.h"
|
||||
#include "util/export.h"
|
||||
|
||||
class PluginGUI;
|
||||
class MessageQueue;
|
||||
|
||||
class SDRANGELOVE_API SampleSource {
|
||||
public:
|
||||
struct SDRANGELOVE_API GeneralSettings {
|
||||
quint64 m_centerFrequency;
|
||||
|
||||
GeneralSettings();
|
||||
void resetToDefaults();
|
||||
QByteArray serialize() const;
|
||||
bool deserialize(const QByteArray& data);
|
||||
};
|
||||
|
||||
SampleSource(MessageQueue* guiMessageQueue);
|
||||
virtual ~SampleSource();
|
||||
|
||||
virtual bool startInput(int device) = 0;
|
||||
virtual void stopInput() = 0;
|
||||
|
||||
virtual const QString& getDeviceDescription() const = 0;
|
||||
virtual int getSampleRate() const = 0;
|
||||
virtual quint64 getCenterFrequency() const = 0;
|
||||
|
||||
virtual bool handleMessage(Message* message) = 0;
|
||||
|
||||
SampleFifo* getSampleFifo() { return &m_sampleFifo; }
|
||||
|
||||
protected:
|
||||
SampleFifo m_sampleFifo;
|
||||
MessageQueue* m_guiMessageQueue;
|
||||
|
||||
GeneralSettings m_generalSettings;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SAMPLESOURCE_H
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef INCLUDE_THREADEDSAMPLESINK_H
|
||||
#define INCLUDE_THREADEDSAMPLESINK_H
|
||||
|
||||
#include <QMutex>
|
||||
#include "samplesink.h"
|
||||
#include "dsp/samplefifo.h"
|
||||
#include "util/messagequeue.h"
|
||||
#include "util/export.h"
|
||||
|
||||
class QThread;
|
||||
class SampleSink;
|
||||
|
||||
class SDRANGELOVE_API ThreadedSampleSink : public SampleSink {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ThreadedSampleSink(SampleSink* sampleSink);
|
||||
virtual ~ThreadedSampleSink();
|
||||
|
||||
MessageQueue* getMessageQueue() { return &m_messageQueue; }
|
||||
|
||||
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst);
|
||||
void start();
|
||||
void stop();
|
||||
bool handleMessage(Message* cmd);
|
||||
|
||||
protected:
|
||||
QMutex m_mutex;
|
||||
QThread* m_thread;
|
||||
MessageQueue m_messageQueue;
|
||||
SampleFifo m_sampleFifo;
|
||||
SampleSink* m_sampleSink;
|
||||
|
||||
protected slots:
|
||||
void handleData();
|
||||
void handleMessages();
|
||||
void threadStarted();
|
||||
void threadFinished();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_THREADEDSAMPLESINK_H
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef INCLUDE_BASICCHANNELSETTINGSWIDGET_H
|
||||
#define INCLUDE_BASICCHANNELSETTINGSWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "util/export.h"
|
||||
|
||||
namespace Ui {
|
||||
class BasicChannelSettingsWidget;
|
||||
}
|
||||
|
||||
class ChannelMarker;
|
||||
|
||||
class SDRANGELOVE_API BasicChannelSettingsWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BasicChannelSettingsWidget(ChannelMarker* marker, QWidget* parent = NULL);
|
||||
~BasicChannelSettingsWidget();
|
||||
|
||||
private slots:
|
||||
void on_title_textChanged(const QString& text);
|
||||
void on_colorBtn_clicked();
|
||||
void on_red_valueChanged(int value);
|
||||
void on_green_valueChanged(int value);
|
||||
void on_blue_valueChanged(int value);
|
||||
|
||||
private:
|
||||
Ui::BasicChannelSettingsWidget* ui;
|
||||
ChannelMarker* m_channelMarker;
|
||||
|
||||
void paintColor();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_BASICCHANNELSETTINGSWIDGET_H
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef INCLUDE_ROLLUPWIDGET_H
|
||||
#define INCLUDE_ROLLUPWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "util/export.h"
|
||||
|
||||
class SDRANGELOVE_API RollupWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RollupWidget(QWidget* parent = NULL);
|
||||
|
||||
QByteArray saveState(int version = 0) const;
|
||||
bool restoreState(const QByteArray& state, int version = 0);
|
||||
|
||||
void setTitleColor(const QColor& c);
|
||||
|
||||
signals:
|
||||
void widgetRolled(QWidget* widget, bool rollDown);
|
||||
void menuDoubleClickEvent();
|
||||
|
||||
protected:
|
||||
enum {
|
||||
VersionMarker = 0xff
|
||||
};
|
||||
|
||||
QColor m_titleColor;
|
||||
|
||||
int arrangeRollups();
|
||||
|
||||
void paintEvent(QPaintEvent*);
|
||||
int paintRollup(QWidget* rollup, int pos, QPainter* p, bool last, const QColor& frame);
|
||||
|
||||
void resizeEvent(QResizeEvent* size);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
|
||||
bool event(QEvent* event);
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
};
|
||||
|
||||
#endif // INCLUDE_ROLLUPWIDGET_H
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef INCLUDE_PLUGINAPI_H
|
||||
#define INCLUDE_PLUGINAPI_H
|
||||
|
||||
#include <QObject>
|
||||
#include "util/export.h"
|
||||
|
||||
class QDockWidget;
|
||||
class QAction;
|
||||
|
||||
class PluginManager;
|
||||
class PluginInterface;
|
||||
class SampleSource;
|
||||
class SampleSink;
|
||||
class DSPEngine;
|
||||
class AudioFifo;
|
||||
class MessageQueue;
|
||||
class MainWindow;
|
||||
class ChannelMarker;
|
||||
class PluginGUI;
|
||||
|
||||
class SDRANGELOVE_API PluginAPI : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// MainWindow access
|
||||
QDockWidget* createMainWindowDock(Qt::DockWidgetArea dockWidgetArea, const QString& title);
|
||||
MessageQueue* getMainWindowMessageQueue();
|
||||
void setInputGUI(QWidget* inputGUI);
|
||||
|
||||
// Channel stuff
|
||||
void registerChannel(const QString& channelName, PluginInterface* plugin, QAction* action);
|
||||
void registerChannelInstance(const QString& channelName, PluginGUI* pluginGUI);
|
||||
void addChannelRollup(QWidget* pluginGUI);
|
||||
void removeChannelInstance(PluginGUI* pluginGUI);
|
||||
|
||||
void addChannelMarker(ChannelMarker* channelMarker);
|
||||
void removeChannelMarker(ChannelMarker* channelMarker);
|
||||
|
||||
// DSPEngine access
|
||||
void setSampleSource(SampleSource* sampleSource);
|
||||
void addSampleSink(SampleSink* sampleSink);
|
||||
void removeSampleSink(SampleSink* sampleSink);
|
||||
MessageQueue* getDSPEngineMessageQueue();
|
||||
void addAudioSource(AudioFifo* audioFifo);
|
||||
void removeAudioSource(AudioFifo* audioFifo);
|
||||
|
||||
// Sample Source stuff
|
||||
void registerSampleSource(const QString& sourceName, PluginInterface* plugin);
|
||||
|
||||
protected:
|
||||
PluginManager* m_pluginManager;
|
||||
MainWindow* m_mainWindow;
|
||||
DSPEngine* m_dspEngine;
|
||||
|
||||
PluginAPI(PluginManager* pluginManager, MainWindow* mainWindow, DSPEngine* dspEngine);
|
||||
|
||||
friend class PluginManager;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_PLUGINAPI_H
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef INCLUDE_PLUGINGUI_H
|
||||
#define INCLUDE_PLUGINGUI_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "util/export.h"
|
||||
|
||||
class Message;
|
||||
|
||||
class SDRANGELOVE_API PluginGUI {
|
||||
public:
|
||||
PluginGUI() { };
|
||||
virtual void destroy() = 0;
|
||||
|
||||
virtual void setName(const QString& name) = 0;
|
||||
|
||||
virtual void resetToDefaults() = 0;
|
||||
|
||||
virtual QByteArray serializeGeneral() const;
|
||||
virtual bool deserializeGeneral(const QByteArray& data);
|
||||
virtual quint64 getCenterFrequency() const;
|
||||
|
||||
virtual QByteArray serialize() const = 0;
|
||||
virtual bool deserialize(const QByteArray& data) = 0;
|
||||
|
||||
virtual bool handleMessage(Message* message) = 0;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_PLUGINGUI_H
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef INCLUDE_PLUGININTERFACE_H
|
||||
#define INCLUDE_PLUGININTERFACE_H
|
||||
|
||||
#include <QtPlugin>
|
||||
#include <QString>
|
||||
|
||||
struct PluginDescriptor {
|
||||
// general plugin description
|
||||
const QString displayedName;
|
||||
const QString version;
|
||||
const QString copyright;
|
||||
const QString website;
|
||||
bool licenseIsGPL;
|
||||
const QString sourceCodeURL;
|
||||
};
|
||||
|
||||
class PluginAPI;
|
||||
class PluginGUI;
|
||||
|
||||
class PluginInterface {
|
||||
public:
|
||||
struct SampleSourceDevice {
|
||||
QString displayedName;
|
||||
QString name;
|
||||
QByteArray address;
|
||||
|
||||
SampleSourceDevice(const QString& _displayedName, const QString& _name, const QByteArray& _address) :
|
||||
displayedName(_displayedName),
|
||||
name(_name),
|
||||
address(_address)
|
||||
{ }
|
||||
};
|
||||
typedef QList<SampleSourceDevice> SampleSourceDevices;
|
||||
|
||||
virtual ~PluginInterface() { };
|
||||
|
||||
virtual const PluginDescriptor& getPluginDescriptor() const = 0;
|
||||
virtual void initPlugin(PluginAPI* pluginAPI) = 0;
|
||||
|
||||
virtual PluginGUI* createChannel(const QString& channelName) { return NULL; }
|
||||
|
||||
virtual SampleSourceDevices enumSampleSources() { return SampleSourceDevices(); }
|
||||
virtual PluginGUI* createSampleSource(const QString& sourceName, const QByteArray& address) { return NULL; }
|
||||
};
|
||||
|
||||
Q_DECLARE_INTERFACE(PluginInterface, "de.maintech.SDRangelove.PluginInterface/0.1");
|
||||
|
||||
#endif // INCLUDE_PLUGININTERFACE_H
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SDRANGELOVE_EXPORT_H
|
||||
#define __SDRANGELOVE_EXPORT_H
|
||||
|
||||
#if defined __GNUC__
|
||||
# if __GNUC__ >= 4
|
||||
# define __SDR_EXPORT __attribute__((visibility("default")))
|
||||
# define __SDR_IMPORT __attribute__((visibility("default")))
|
||||
# else
|
||||
# define __SDR_EXPORT
|
||||
# define __SDR_IMPORT
|
||||
# endif
|
||||
#elif _MSC_VER
|
||||
# define __SDR_EXPORT __declspec(dllexport)
|
||||
# define __SDR_IMPORT __declspec(dllimport)
|
||||
#else
|
||||
# define __SDR_EXPORT
|
||||
# define __SDR_IMPORT
|
||||
#endif
|
||||
|
||||
#ifndef sdrangelove_STATIC
|
||||
# ifdef sdrangelove_EXPORTS
|
||||
# define SDRANGELOVE_API __SDR_EXPORT
|
||||
# else
|
||||
# define SDRANGELOVE_API __SDR_IMPORT
|
||||
# endif
|
||||
#else
|
||||
#define SDRANGELOVE_API
|
||||
#endif
|
||||
#endif /* __SDRANGELOVE_EXPORT_H */
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef INCLUDE_MESSAGE_H
|
||||
#define INCLUDE_MESSAGE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <QAtomicInt>
|
||||
#include "util/export.h"
|
||||
|
||||
class MessageQueue;
|
||||
class QWaitCondition;
|
||||
class QMutex;
|
||||
|
||||
class SDRANGELOVE_API Message {
|
||||
public:
|
||||
Message();
|
||||
virtual ~Message();
|
||||
|
||||
virtual const char* getIdentifier() const;
|
||||
virtual bool matchIdentifier(const char* identifier) const;
|
||||
static bool match(Message* message);
|
||||
|
||||
void* getDestination() const { return m_destination; }
|
||||
|
||||
void submit(MessageQueue* queue, void* destination = NULL);
|
||||
int execute(MessageQueue* queue, void* destination = NULL);
|
||||
|
||||
void completed(int result = 0);
|
||||
|
||||
protected:
|
||||
// addressing
|
||||
static const char* m_identifier;
|
||||
void* m_destination;
|
||||
|
||||
// stuff for synchronous messages
|
||||
bool m_synchronous;
|
||||
QWaitCondition* m_waitCondition;
|
||||
QMutex* m_mutex;
|
||||
QAtomicInt m_complete;
|
||||
int m_result;
|
||||
};
|
||||
|
||||
#define MESSAGE_CLASS_DECLARATION \
|
||||
public: \
|
||||
const char* getIdentifier() const; \
|
||||
bool matchIdentifier(const char* identifier) const; \
|
||||
static bool match(Message* message); \
|
||||
protected: \
|
||||
static const char* m_identifier; \
|
||||
private:
|
||||
|
||||
#define MESSAGE_CLASS_DEFINITION(Name, BaseClass) \
|
||||
const char* Name::m_identifier = #Name; \
|
||||
const char* Name::getIdentifier() const { return m_identifier; } \
|
||||
bool Name::matchIdentifier(const char* identifier) const {\
|
||||
return (m_identifier == identifier) ? true : BaseClass::matchIdentifier(identifier); \
|
||||
} \
|
||||
bool Name::match(Message* message) { return message->matchIdentifier(m_identifier); }
|
||||
|
||||
#endif // INCLUDE_MESSAGE_H
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef INCLUDE_MESSAGEQUEUE_H
|
||||
#define INCLUDE_MESSAGEQUEUE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QQueue>
|
||||
#include "spinlock.h"
|
||||
#include "util/export.h"
|
||||
|
||||
class Message;
|
||||
|
||||
class SDRANGELOVE_API MessageQueue : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MessageQueue(QObject* parent = NULL);
|
||||
~MessageQueue();
|
||||
|
||||
void submit(Message* message);
|
||||
Message* accept();
|
||||
|
||||
int countPending();
|
||||
|
||||
signals:
|
||||
void messageEnqueued();
|
||||
|
||||
private:
|
||||
Spinlock m_lock;
|
||||
QQueue<Message*> m_queue;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_MESSAGEQUEUE_H
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef INCLUDE_MINIZ_H
|
||||
#define INCLUDE_MINIZ_H
|
||||
|
||||
#define MINIZ_HEADER_FILE_ONLY
|
||||
#include "../../sdrapp/util/miniz.cpp"
|
||||
|
||||
#endif // INCLUDE_MINIZ_H
|
||||
@@ -0,0 +1,112 @@
|
||||
#ifndef INCLUDE_SIMPLESERIALIZER_H
|
||||
#define INCLUDE_SIMPLESERIALIZER_H
|
||||
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include "dsp/dsptypes.h"
|
||||
#include "util/export.h"
|
||||
|
||||
class SDRANGELOVE_API SimpleSerializer {
|
||||
public:
|
||||
SimpleSerializer(quint32 version);
|
||||
|
||||
void writeS32(quint32 id, qint32 value);
|
||||
void writeU32(quint32 id, quint32 value);
|
||||
void writeS64(quint32 id, qint64 value);
|
||||
void writeU64(quint32 id, quint64 value);
|
||||
void writeFloat(quint32 id, float value);
|
||||
void writeDouble(quint32 id, double value);
|
||||
void writeReal(quint32 id, Real value)
|
||||
{
|
||||
if(sizeof(Real) == 4)
|
||||
writeFloat(id, value);
|
||||
else writeDouble(id, value);
|
||||
}
|
||||
void writeBool(quint32 id, bool value);
|
||||
void writeString(quint32 id, const QString& value);
|
||||
void writeBlob(quint32 id, const QByteArray& value);
|
||||
|
||||
const QByteArray& final();
|
||||
|
||||
protected:
|
||||
enum Type {
|
||||
TSigned32 = 0,
|
||||
TUnsigned32 = 1,
|
||||
TSigned64 = 2,
|
||||
TUnsigned64 = 3,
|
||||
TFloat = 4,
|
||||
TDouble = 5,
|
||||
TBool = 6,
|
||||
TString = 7,
|
||||
TBlob = 8,
|
||||
TVersion = 9
|
||||
};
|
||||
|
||||
QByteArray m_data;
|
||||
bool m_finalized;
|
||||
|
||||
bool writeTag(Type type, quint32 id, quint32 length);
|
||||
};
|
||||
|
||||
class SDRANGELOVE_API SimpleDeserializer {
|
||||
public:
|
||||
SimpleDeserializer(const QByteArray& data);
|
||||
|
||||
bool readS32(quint32 id, qint32* result, qint32 def = 0) const;
|
||||
bool readU32(quint32 id, quint32* result, quint32 def = 0) const;
|
||||
bool readS64(quint32 id, qint64* result, qint64 def = 0) const;
|
||||
bool readU64(quint32 id, quint64* result, quint64 def = 0) const;
|
||||
bool readFloat(quint32 id, float* result, float def = 0) const;
|
||||
bool readDouble(quint32 id, double* result, double def = 0) const;
|
||||
bool readReal(quint32 id, Real* result, Real def = 0) const;
|
||||
bool readBool(quint32 id, bool* result, bool def = false) const;
|
||||
bool readString(quint32 id, QString* result, const QString& def = QString::null) const;
|
||||
bool readBlob(quint32 id, QByteArray* result, const QByteArray& def = QByteArray()) const;
|
||||
|
||||
bool isValid() const { return m_valid; }
|
||||
quint32 getVersion() const { return m_version; }
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
enum Type {
|
||||
TSigned32 = 0,
|
||||
TUnsigned32 = 1,
|
||||
TSigned64 = 2,
|
||||
TUnsigned64 = 3,
|
||||
TFloat = 4,
|
||||
TDouble = 5,
|
||||
TBool = 6,
|
||||
TString = 7,
|
||||
TBlob = 8,
|
||||
TVersion = 9
|
||||
};
|
||||
|
||||
struct Element {
|
||||
Type type;
|
||||
quint32 ofs;
|
||||
quint32 length;
|
||||
|
||||
Element(Type _type, quint32 _ofs, quint32 _length) :
|
||||
type(_type),
|
||||
ofs(_ofs),
|
||||
length(_length)
|
||||
{ }
|
||||
};
|
||||
typedef QMap<quint32, Element> Elements;
|
||||
|
||||
QByteArray m_data;
|
||||
bool m_valid;
|
||||
Elements m_elements;
|
||||
quint32 m_version;
|
||||
|
||||
bool parseAll();
|
||||
bool readTag(uint* readOfs, uint readEnd, Type* type, quint32* id, quint32* length) const;
|
||||
quint8 readByte(uint* readOfs) const
|
||||
{
|
||||
quint8 res = m_data[*readOfs];
|
||||
(*readOfs)++;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SIMPLESERIALIZER_H
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef INCLUDE_SPINLOCK_H
|
||||
#define INCLUDE_SPINLOCK_H
|
||||
|
||||
#include <QAtomicInt>
|
||||
|
||||
class Spinlock {
|
||||
public:
|
||||
void lock()
|
||||
{
|
||||
while(!m_atomic.testAndSetAcquire(0, 1)) ;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
while(!m_atomic.testAndSetRelease(1, 0)) ;
|
||||
}
|
||||
|
||||
protected:
|
||||
QAtomicInt m_atomic;
|
||||
};
|
||||
|
||||
class SpinlockHolder {
|
||||
public:
|
||||
SpinlockHolder(Spinlock* spinlock) :
|
||||
m_spinlock(spinlock)
|
||||
{
|
||||
m_spinlock->lock();
|
||||
}
|
||||
|
||||
~SpinlockHolder()
|
||||
{
|
||||
m_spinlock->unlock();
|
||||
}
|
||||
|
||||
protected:
|
||||
Spinlock* m_spinlock;
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SPINLOCK_H
|
||||
Reference in New Issue
Block a user