1 /* -*- c++ -*- */
2 #ifndef PLOTTER_H
3 #define PLOTTER_H
4 
5 #include <QtGui>
6 #include <QFont>
7 #include <QFrame>
8 #include <QImage>
9 #include <vector>
10 #include <QMap>
11 
12 #define HORZ_DIVS_MAX 12    //50
13 #define VERT_DIVS_MIN 5
14 #define MAX_SCREENSIZE 16384
15 
16 #define PEAK_CLICK_MAX_H_DISTANCE 10 //Maximum horizontal distance of clicked point from peak
17 #define PEAK_CLICK_MAX_V_DISTANCE 20 //Maximum vertical distance of clicked point from peak
18 #define PEAK_H_TOLERANCE 2
19 
20 
21 class CPlotter : public QFrame
22 {
23     Q_OBJECT
24 
25 public:
26     explicit CPlotter(QWidget *parent = nullptr);
27     ~CPlotter() override;
28 
29     QSize minimumSizeHint() const override;
30     QSize sizeHint() const override;
31 
32     //void SetSdrInterface(CSdrInterface* ptr){m_pSdrInterface = ptr;}
33     void draw(); //call to draw new fft data onto screen plot
setRunningState(bool running)34     void setRunningState(bool running) { m_Running = running; }
setClickResolution(int clickres)35     void setClickResolution(int clickres) { m_ClickResolution = clickres; }
setFilterClickResolution(int clickres)36     void setFilterClickResolution(int clickres) { m_FilterClickResolution = clickres; }
setFilterBoxEnabled(bool enabled)37     void setFilterBoxEnabled(bool enabled) { m_FilterBoxEnabled = enabled; }
setCenterLineEnabled(bool enabled)38     void setCenterLineEnabled(bool enabled) { m_CenterLineEnabled = enabled; }
setTooltipsEnabled(bool enabled)39     void setTooltipsEnabled(bool enabled) { m_TooltipsEnabled = enabled; }
setBookmarksEnabled(bool enabled)40     void setBookmarksEnabled(bool enabled) { m_BookmarksEnabled = enabled; }
setInvertScrolling(bool enabled)41     void setInvertScrolling(bool enabled) { m_InvertScrolling = enabled; }
setBandPlanEnabled(bool enabled)42     void setBandPlanEnabled(bool enabled) { m_BandPlanEnabled = enabled; }
setDXCSpotsEnabled(bool enabled)43     void setDXCSpotsEnabled(bool enabled) { m_DXCSpotsEnabled = enabled; }
44 
45     void setNewFftData(float *fftData, int size);
46     void setNewFftData(float *fftData, float *wfData, int size);
47 
48     void setCenterFreq(quint64 f);
setFreqUnits(qint32 unit)49     void setFreqUnits(qint32 unit) { m_FreqUnits = unit; }
50 
setDemodCenterFreq(quint64 f)51     void setDemodCenterFreq(quint64 f) { m_DemodCenterFreq = f; }
52 
53     /*! \brief Move the filter to freq_hz from center. */
setFilterOffset(qint64 freq_hz)54     void setFilterOffset(qint64 freq_hz)
55     {
56         m_DemodCenterFreq = m_CenterFreq + freq_hz;
57         drawOverlay();
58     }
getFilterOffset()59     qint64 getFilterOffset() const
60     {
61         return m_DemodCenterFreq - m_CenterFreq;
62     }
63 
getFilterBw()64     int getFilterBw() const
65     {
66         return m_DemodHiCutFreq - m_DemodLowCutFreq;
67     }
68 
setHiLowCutFrequencies(int LowCut,int HiCut)69     void setHiLowCutFrequencies(int LowCut, int HiCut)
70     {
71         m_DemodLowCutFreq = LowCut;
72         m_DemodHiCutFreq = HiCut;
73         drawOverlay();
74     }
75 
getHiLowCutFrequencies(int * LowCut,int * HiCut)76     void getHiLowCutFrequencies(int *LowCut, int *HiCut) const
77     {
78         *LowCut = m_DemodLowCutFreq;
79         *HiCut = m_DemodHiCutFreq;
80     }
81 
82     void setDemodRanges(int FLowCmin, int FLowCmax, int FHiCmin, int FHiCmax, bool symetric);
83 
84     /* Shown bandwidth around SetCenterFreq() */
setSpanFreq(quint32 s)85     void setSpanFreq(quint32 s)
86     {
87         if (s > 0 && s < INT_MAX) {
88             m_Span = (qint32)s;
89             setFftCenterFreq(m_FftCenter);
90         }
91         drawOverlay();
92     }
93 
setHdivDelta(int delta)94     void setHdivDelta(int delta) { m_HdivDelta = delta; }
setVdivDelta(int delta)95     void setVdivDelta(int delta) { m_VdivDelta = delta; }
96 
setFreqDigits(int digits)97     void setFreqDigits(int digits) { m_FreqDigits = digits>=0 ? digits : 0; }
98 
99     /* Determines full bandwidth. */
setSampleRate(float rate)100     void setSampleRate(float rate)
101     {
102         if (rate > 0.0)
103         {
104             m_SampleFreq = rate;
105             drawOverlay();
106         }
107     }
108 
getSampleRate()109     float getSampleRate() const
110     {
111         return m_SampleFreq;
112     }
113 
setFftCenterFreq(qint64 f)114     void setFftCenterFreq(qint64 f) {
115         qint64 limit = ((qint64)m_SampleFreq + m_Span) / 2 - 1;
116         m_FftCenter = qBound(-limit, f, limit);
117     }
118 
119     int     getNearestPeak(QPoint pt);
120     void    setWaterfallSpan(quint64 span_ms);
121     quint64 getWfTimeRes() const;
122     void    setFftRate(int rate_hz);
123     void    clearWaterfall();
124     bool    saveWaterfall(const QString & filename) const;
125 
126 signals:
127     void newDemodFreq(qint64 freq, qint64 delta); /* delta is the offset from the center */
128     void newLowCutFreq(int f);
129     void newHighCutFreq(int f);
130     void newFilterFreq(int low, int high);  /* substitute for NewLow / NewHigh */
131     void pandapterRangeChanged(float min, float max);
132     void newZoomLevel(float level);
133     void newSize();
134 
135 public slots:
136     // zoom functions
137     void resetHorizontalZoom();
138     void moveToCenterFreq();
139     void moveToDemodFreq();
140     void zoomOnXAxis(float level);
141 
142     // other FFT slots
143     void setFftPlotColor(const QColor& color);
144     void setFftFill(bool enabled);
145     void setPeakHold(bool enabled);
146     void setFftRange(float min, float max);
147     void setWfColormap(const QString &cmap);
148     void setPandapterRange(float min, float max);
149     void setWaterfallRange(float min, float max);
150     void setPeakDetection(bool enabled, float c);
151     void toggleBandPlan(bool state);
152     void updateOverlay();
153 
setPercent2DScreen(int percent)154     void setPercent2DScreen(int percent)
155     {
156         m_Percent2DScreen = percent;
157         m_Size = QSize(0,0);
158         resizeEvent(nullptr);
159     }
160 
161 protected:
162     //re-implemented widget event handlers
163     void paintEvent(QPaintEvent *event) override;
164     void resizeEvent(QResizeEvent* event) override;
165     void mouseMoveEvent(QMouseEvent * event) override;
166     void mousePressEvent(QMouseEvent * event) override;
167     void mouseReleaseEvent(QMouseEvent * event) override;
168     void wheelEvent( QWheelEvent * event ) override;
169 
170 private:
171     enum eCapturetype {
172         NOCAP,
173         LEFT,
174         CENTER,
175         RIGHT,
176         YAXIS,
177         XAXIS,
178         TAG
179     };
180 
181     void        drawOverlay();
182     void        makeFrequencyStrs();
183     int         xFromFreq(qint64 freq);
184     qint64      freqFromX(int x);
185     void        zoomStepX(float factor, int x);
186     static qint64      roundFreq(qint64 freq, int resolution);
187     quint64     msecFromY(int y);
188     void        clampDemodParameters();
isPointCloseTo(int x,int xr,int delta)189     static bool        isPointCloseTo(int x, int xr, int delta)
190     {
191         return ((x > (xr - delta)) && (x < (xr + delta)));
192     }
193     void getScreenIntegerFFTData(qint32 plotHeight, qint32 plotWidth,
194                                  float maxdB, float mindB,
195                                  qint64 startFreq, qint64 stopFreq,
196                                  float *inBuf, qint32 *outBuf,
197                                  qint32 *maxbin, qint32 *minbin) const;
198     static void calcDivSize (qint64 low, qint64 high, int divswanted, qint64 &adjlow, qint64 &step, int& divs);
199 
200     bool        m_PeakHoldActive;
201     bool        m_PeakHoldValid;
202     qint32      m_fftbuf[MAX_SCREENSIZE]{};
203     quint8      m_wfbuf[MAX_SCREENSIZE]{}; // used for accumulating waterfall data at high time spans
204     qint32      m_fftPeakHoldBuf[MAX_SCREENSIZE]{};
205     float      *m_fftData{};     /*! pointer to incoming FFT data */
206     float      *m_wfData{};
207     int         m_fftDataSize{};
208 
209     int         m_XAxisYCenter{};
210     int         m_YAxisWidth{};
211 
212     eCapturetype    m_CursorCaptured;
213     QPixmap     m_2DPixmap;
214     QPixmap     m_OverlayPixmap;
215     QPixmap     m_WaterfallPixmap;
216     QColor      m_ColorTbl[256];
217     QSize       m_Size;
218     qreal       m_DPR{};
219     QString     m_HDivText[HORZ_DIVS_MAX+1];
220     bool        m_Running;
221     bool        m_DrawOverlay;
222     qint64      m_CenterFreq;       // The HW frequency
223     qint64      m_FftCenter;        // Center freq in the -span ... +span range
224     qint64      m_DemodCenterFreq;
225     qint64      m_StartFreqAdj{};
226     qint64      m_FreqPerDiv{};
227     bool        m_CenterLineEnabled;  /*!< Distinguish center line. */
228     bool        m_FilterBoxEnabled;   /*!< Draw filter box. */
229     bool        m_TooltipsEnabled{};  /*!< Tooltips enabled */
230     bool        m_BandPlanEnabled;    /*!< Show/hide band plan on spectrum */
231     bool        m_BookmarksEnabled;   /*!< Show/hide bookmarks on spectrum */
232     bool        m_InvertScrolling;
233     bool        m_DXCSpotsEnabled;    /*!< Show/hide DXC Spots on spectrum */
234     int         m_DemodHiCutFreq;
235     int         m_DemodLowCutFreq;
236     int         m_DemodFreqX{};       //screen coordinate x position
237     int         m_DemodHiCutFreqX{};  //screen coordinate x position
238     int         m_DemodLowCutFreqX{}; //screen coordinate x position
239     int         m_CursorCaptureDelta;
240     int         m_GrabPosition;
241     int         m_Percent2DScreen;
242 
243     int         m_FLowCmin;
244     int         m_FLowCmax;
245     int         m_FHiCmin;
246     int         m_FHiCmax;
247     bool        m_symetric;
248 
249     int         m_HorDivs;   /*!< Current number of horizontal divisions. Calculated from width. */
250     int         m_VerDivs;   /*!< Current number of vertical divisions. Calculated from height. */
251 
252     float       m_PandMindB;
253     float       m_PandMaxdB;
254     float       m_WfMindB;
255     float       m_WfMaxdB;
256 
257     qint64      m_Span;
258     float       m_SampleFreq;    /*!< Sample rate. */
259     qint32      m_FreqUnits;
260     int         m_ClickResolution;
261     int         m_FilterClickResolution;
262 
263     int         m_Xzero{};
264     int         m_Yzero{};  /*!< Used to measure mouse drag direction. */
265     int         m_FreqDigits;  /*!< Number of decimal digits in frequency strings. */
266 
267     QFont       m_Font;      /*!< Font used for plotter (system font) */
268     int         m_HdivDelta; /*!< Minimum distance in pixels between two horizontal grid lines (vertical division). */
269     int         m_VdivDelta; /*!< Minimum distance in pixels between two vertical grid lines (horizontal division). */
270     int         m_BandPlanHeight; /*!< Height in pixels of band plan (if enabled) */
271 
272     quint32     m_LastSampleRate{};
273 
274     QColor      m_FftColor, m_FftFillCol, m_PeakHoldColor;
275     bool        m_FftFill{};
276 
277     float       m_PeakDetection{};
278     QMap<int,int>   m_Peaks;
279 
280     QList< QPair<QRect, qint64> >     m_Taglist;
281 
282     // Waterfall averaging
283     quint64     tlast_wf_ms;        // last time waterfall has been updated
284     quint64     msec_per_wfline;    // milliseconds between waterfall updates
285     quint64     wf_span;            // waterfall span in milliseconds (0 = auto)
286     int         fft_rate;           // expected FFT rate (needed when WF span is auto)
287 };
288 
289 #endif // PLOTTER_H
290