From 228fc3ab24e376b8f9aba864aec944daffd12f17 Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 6 Jun 2021 00:10:20 +0200 Subject: [PATCH] Forgot about version control, here's the whole code at once --- LivePow.pro | 25 +++++++++ README.md | 13 +++++ displayarea.cpp | 47 +++++++++++++++++ displayarea.h | 29 +++++++++++ inputparser.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++++++++ inputparser.h | 63 +++++++++++++++++++++++ main.cpp | 11 ++++ mainwindow.cpp | 82 ++++++++++++++++++++++++++++++ mainwindow.h | 39 ++++++++++++++ 9 files changed, 441 insertions(+) create mode 100644 LivePow.pro create mode 100644 README.md create mode 100644 displayarea.cpp create mode 100644 displayarea.h create mode 100644 inputparser.cpp create mode 100644 inputparser.h create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h diff --git a/LivePow.pro b/LivePow.pro new file mode 100644 index 0000000..c022d9e --- /dev/null +++ b/LivePow.pro @@ -0,0 +1,25 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + displayarea.cpp \ + inputparser.cpp \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + displayarea.h \ + inputparser.h \ + mainwindow.h + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/README.md b/README.md new file mode 100644 index 0000000..fc6ffc3 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# LivePow +An reader for making heatmap from soapy_power output + +## Building +``` +mkdir build +qmake .. +make -j4 +``` + +## Usage +### Example scanning the FM radio band +`soapy_power -f 80M:110M -n 10 -e 30 -B 30k -k 30 --pow2 -F rtl_power -R | ./Livepow` diff --git a/displayarea.cpp b/displayarea.cpp new file mode 100644 index 0000000..9b6239b --- /dev/null +++ b/displayarea.cpp @@ -0,0 +1,47 @@ +#include "displayarea.h" +#include +#include +#include + +DisplayArea::DisplayArea(QWidget *parent) : QWidget(parent) +{ + setAttribute(Qt::WA_StaticContents); + + QTimer* timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),this,SLOT(updateDisp())); + timer->start(100); +} + +void DisplayArea::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + QRect rect=event->rect(); + painter.drawImage(rect,image,rect); +} + +void DisplayArea::setPixel(int x, int y, unsigned int col) +{ + if(x>=image.width()||y>=image.height()) resizeImage(&image,QSize(qMax(x+255,image.width()),qMax(y+255,image.height()))); + image.setPixel(x,y,col); +} + +void DisplayArea::resizeImage(QImage *image, const QSize &newSize) +{ + if(image->size()==newSize) return; + + QImage newImage(newSize,QImage::Format_ARGB32); + newImage.fill(qRgba(255,255,255,0)); + QPainter painter(&newImage); + painter.drawImage(QPoint(0,0),*image); + *image=newImage; +} + +void DisplayArea::updateDisp() +{ + update(); +} + +bool DisplayArea::saveImage(const QString &fileName, const char *fileFormat) +{ + return image.save(fileName, fileFormat); +} diff --git a/displayarea.h b/displayarea.h new file mode 100644 index 0000000..03e9322 --- /dev/null +++ b/displayarea.h @@ -0,0 +1,29 @@ +#ifndef DISPLAYAREA_H +#define DISPLAYAREA_H + +#include + +class DisplayArea : public QWidget +{ + Q_OBJECT +public: + DisplayArea(QWidget *parent = nullptr); + void setPixel(int x,int y,unsigned int col); + bool saveImage(const QString &fileName, const char *fileFormat); + +protected: + void paintEvent(QPaintEvent *event) override; + +private: + void resizeImage(QImage *image, const QSize &newSize); + + QImage image; + +public slots: + void updateDisp(); + +signals: + +}; + +#endif // DISPLAYAREA_H diff --git a/inputparser.cpp b/inputparser.cpp new file mode 100644 index 0000000..b69fc3b --- /dev/null +++ b/inputparser.cpp @@ -0,0 +1,132 @@ +#include "inputparser.h" +#include +#include "displayarea.h" +#include +#include + +InputParser::InputParser(FILE* input,DisplayArea* display) +{ + InputParser::input=input; + + InputParser::display=display; + + random=new QRandomGenerator(); + + /*QTimer* timer = new QTimer(this); + connect(timer,SIGNAL(timeout()),this,SLOT(process())); + timer->start(0);*/ +} + + +void InputParser::process() +{ + while(1){ + int c=fgetc(input); + if(c==EOF) continue; + + switch(c){ + case ',': + switch(index){ + case 1: + computeEpochDate(); + break; + default: + if(index>5){ + sendPixel(); + } + break; + } + index++; + decimal=false; + break; + case '\n': + index=0; + minFreq=qMin(minFreq,currentLine.minFreq); + maxFreq=qMax(maxFreq,currentLine.maxFreq); + + sendPixel(); + + if(currentLine.maxFreq<=lastMaxFreq){ + currentY++; + currentX=0; + } + lastMaxFreq=currentLine.maxFreq; + + currentLine=line(); + decimal=false; + break; + case '.': + decimal=true; + break; + default: + switch(index){ + case 0: + addToString(c,¤tLine.firstDate); + break; + case 1: + addToString(c,¤tLine.secondDate); + break; + case 2: + addToInt(c,¤tLine.minFreq); + break; + case 3: + addToInt(c,¤tLine.maxFreq); + break; + case 4: + addToInt(c,¤tLine.freqStep); + break; + default: + if(index>5) addToFloat(c,¤tPowerValue); + break; + } + break; + } + } + //printf("%c aaa"); +} + +void InputParser::addToString(char c, QString* str) +{ + str->append(c); +} + +void InputParser::addToInt(char c, unsigned long* nb) +{ + if(decimal||c<'0'||c>'9') return; + *nb*=10; + *nb+=(c-'0'); +} + +void InputParser::addToFloat(char c, float* nb) +{ + if(c<'0'||c>'9') return; + if(!decimal){ + *nb*=10; + *nb+=(c-'0'); + } + else{ + float inc=((c-'0')/pow(10,decimalIndex)); + *nb+=inc; + decimalIndex++; + } +} + +void InputParser::computeEpochDate() +{ + QString dateMerged=QString(); + dateMerged.append(currentLine.firstDate); + dateMerged.append(currentLine.secondDate); + //2021-05-28 23:20:36 + currentLine.parsedDate=QDateTime::fromString(dateMerged,"yyyy-MM-dd hh:mm:ss"); +} + +void InputParser::sendPixel() +{ + currentPowerValue*=sign; + int col=qRound((80-currentPowerValue)*6); + display->setPixel(currentX,currentY,qRgba(col,col,col,255)); + currentX++; + currentPowerValue=0; + decimalIndex=1; + sign=1; +} diff --git a/inputparser.h b/inputparser.h new file mode 100644 index 0000000..a01fd23 --- /dev/null +++ b/inputparser.h @@ -0,0 +1,63 @@ +#ifndef INPUTPARSER_H +#define INPUTPARSER_H + +#include +#include +#include +#include +#include + +class DisplayArea; + +struct line{ + QString firstDate; + QString secondDate; + QDateTime parsedDate; + unsigned long minFreq=0; + unsigned long maxFreq=0; + unsigned long freqStep=0; +}; + +class InputParser : public QObject +{ + Q_OBJECT +public: + InputParser(FILE* input,DisplayArea* display); + +private: + unsigned long minFreq=-1; + unsigned long maxFreq=0; + + unsigned long lastMaxFreq=0; + + unsigned long index=0; + + line currentLine; + + FILE* input; + + bool decimal=false; + int decimalIndex=1; + int sign=1; + + unsigned int currentX=0; + unsigned int currentY=0; + + DisplayArea* display; + + QRandomGenerator* random; + + float currentPowerValue=0; + + void addToString(char c,QString* str); + void addToInt(char c,unsigned long* nb); + void addToFloat(char c,float* nb); + void computeEpochDate(); + + void sendPixel(); + +public slots: + void process(); +}; + +#endif // INPUTPARSER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..fd3e533 --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..ab7ec70 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,82 @@ +#include +#include "mainwindow.h" +#include "displayarea.h" +#include "inputparser.h" +#include +#include +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent),displayArea(new DisplayArea(this)) +{ + setCentralWidget(displayArea); + + FILE* input=stdin; + + parser=new InputParser(input,displayArea); + + QThread* workerThread=new QThread(); + + parser->moveToThread(workerThread); + connect(workerThread, &QThread::started, parser, &InputParser::process); + connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); + workerThread->start(); + + createActions(); + createMenus(); + + setWindowTitle(tr("LivePow")); +} + +MainWindow::~MainWindow() +{ +} + +void MainWindow::save(){ + QAction *action = qobject_cast(sender()); + QByteArray fileFormat = action->data().toByteArray(); + saveFile(fileFormat); +} + +bool MainWindow::saveFile(const QByteArray &fileFormat) +{ + QString initialPath = QDir::currentPath() + "/untitled." + fileFormat; + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), + initialPath, + tr("%1 Files (*.%2);;All Files (*)") + .arg(QString::fromLatin1(fileFormat.toUpper()),QString::fromLatin1(fileFormat))); + if (fileName.isEmpty()) + return false; + return displayArea->saveImage(fileName, fileFormat.constData()); +} + +void MainWindow::createActions() +{ + const QList imageFormats = QImageWriter::supportedImageFormats(); + for (const QByteArray &format : imageFormats) { + QString text = tr("%1...").arg(QString::fromLatin1(format).toUpper()); + + QAction *action = new QAction(text, this); + action->setData(format); + connect(action, &QAction::triggered, this, &MainWindow::save); + saveAsActs.append(action); + } +} + +void MainWindow::createMenus() +{ + saveAsMenu = new QMenu(tr("&Save As"), this); + for (QAction *action : qAsConst(saveAsActs)) + saveAsMenu->addAction(action); + + fileMenu = new QMenu(tr("&File"), this); + fileMenu->addMenu(saveAsMenu); + + menuBar()->addMenu(fileMenu); +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..0d88a3a --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,39 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +class DisplayArea; +class InputParser; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + + static void tick(); + + InputParser *parser; + +private: + DisplayArea *displayArea; + void createActions(); + void createMenus(); + + QMenu *saveAsMenu; + QMenu *fileMenu; + + QList saveAsActs; + + bool saveFile(const QByteArray &fileFormat); + +private slots: + void save(); + +signals: + void operate(const QString &); +}; +#endif // MAINWINDOW_H