add config save and load

This commit is contained in:
168492376 2024-12-31 00:44:43 +08:00
parent 67d623638d
commit ced2785a3a
9 changed files with 3092 additions and 5 deletions

View File

@ -1,28 +1,40 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets concurrent
CONFIG += c++17
msvc{
QMAKE_CFLAGS += /utf-8
QMAKE_CXXFLAGS += /utf-8
}
# 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
INCLUDEPATH += \
$$PWD/3rdparty/uhd/include
$$PWD/3rdparty/uhd/include \
$$PWD/3rdparty/
SOURCES += \
gpssim.c \
main.cpp \
mainwindow.cpp
mainwindow.cpp \
uhd_device.cpp \
workThread.cpp
HEADERS += \
mainwindow.h
gpssim.h \
mainwindow.h \
uhd_device.h \
workThread.h
FORMS += \
mainwindow.ui
win32{
LIBS += -L$$PWD/3rdparty/uhd/lib -luhd
LIBS += -L$$PWD/3rdparty/uhd/lib -luhd -L$$PWD/3rdparty/lib64-msvc-14.3 -llibboost_thread-vc143-mt-gd-x64-1_86
}
# Default rules for deployment.

2488
gpssim.c Normal file

File diff suppressed because it is too large Load Diff

187
gpssim.h Normal file
View File

@ -0,0 +1,187 @@
#ifndef GPSSIM_H
#define GPSSIM_H
//#define FLOAT_CARR_PHASE // For RKT simulation. Higher computational load, but smoother carrier phase.
#define TRUE (1)
#define FALSE (0)
/*! \brief Maximum length of a line in a text file (RINEX, motion) */
#define MAX_CHAR (100)
/*! \brief Maximum number of satellites in RINEX file */
#define MAX_SAT (32)
/*! \brief Maximum number of channels we simulate */
#define MAX_CHAN (16)
/*! \brief Maximum number of user motion points */
#ifndef USER_MOTION_SIZE
#define USER_MOTION_SIZE (3000) // max duration at 10Hz
#endif
/*! \brief Maximum duration for static mode*/
#define STATIC_MAX_DURATION (86400) // second
/*! \brief Number of subframes */
#define N_SBF (5) // 5 subframes per frame
/*! \brief Number of words per subframe */
#define N_DWRD_SBF (10) // 10 word per subframe
/*! \brief Number of words */
#define N_DWRD ((N_SBF+1)*N_DWRD_SBF) // Subframe word buffer size
/*! \brief C/A code sequence length */
#define CA_SEQ_LEN (1023)
#define SECONDS_IN_WEEK 604800.0
#define SECONDS_IN_HALF_WEEK 302400.0
#define SECONDS_IN_DAY 86400.0
#define SECONDS_IN_HOUR 3600.0
#define SECONDS_IN_MINUTE 60.0
#define POW2_M5 0.03125
#define POW2_M19 1.907348632812500e-6
#define POW2_M29 1.862645149230957e-9
#define POW2_M31 4.656612873077393e-10
#define POW2_M33 1.164153218269348e-10
#define POW2_M43 1.136868377216160e-13
#define POW2_M55 2.775557561562891e-17
#define POW2_M50 8.881784197001252e-016
#define POW2_M30 9.313225746154785e-010
#define POW2_M27 7.450580596923828e-009
#define POW2_M24 5.960464477539063e-008
// Conventional values employed in GPS ephemeris model (ICD-GPS-200)
#define GM_EARTH 3.986005e14
#define OMEGA_EARTH 7.2921151467e-5
#define PI 3.1415926535898
#define WGS84_RADIUS 6378137.0
#define WGS84_ECCENTRICITY 0.0818191908426
#define R2D 57.2957795131
#define SPEED_OF_LIGHT 2.99792458e8
#define LAMBDA_L1 0.190293672798365
/*! \brief GPS L1 Carrier frequency */
#define CARR_FREQ (1575.42e6)
/*! \brief C/A code frequency */
#define CODE_FREQ (1.023e6)
#define CARR_TO_CODE (1.0/1540.0)
// Sampling data format
#define SC01 (1)
#define SC08 (8)
#define SC16 (16)
#define EPHEM_ARRAY_SIZE (15) // for daily GPS broadcast ephemers file (brdc)
/*! \brief Structure representing GPS time */
typedef struct
{
int week; /*!< GPS week number (since January 1980) */
double sec; /*!< second inside the GPS \a week */
} gpstime_t;
/*! \brief Structure repreenting UTC time */
typedef struct
{
int y; /*!< Calendar year */
int m; /*!< Calendar month */
int d; /*!< Calendar day */
int hh; /*!< Calendar hour */
int mm; /*!< Calendar minutes */
double sec; /*!< Calendar seconds */
} datetime_t;
/*! \brief Structure representing ephemeris of a single satellite */
typedef struct
{
int vflg; /*!< Valid Flag */
datetime_t t;
gpstime_t toc; /*!< Time of Clock */
gpstime_t toe; /*!< Time of Ephemeris */
int iodc; /*!< Issue of Data, Clock */
int iode; /*!< Isuse of Data, Ephemeris */
double deltan; /*!< Delta-N (radians/sec) */
double cuc; /*!< Cuc (radians) */
double cus; /*!< Cus (radians) */
double cic; /*!< Correction to inclination cos (radians) */
double cis; /*!< Correction to inclination sin (radians) */
double crc; /*!< Correction to radius cos (meters) */
double crs; /*!< Correction to radius sin (meters) */
double ecc; /*!< e Eccentricity */
double sqrta; /*!< sqrt(A) (sqrt(m)) */
double m0; /*!< Mean anamoly (radians) */
double omg0; /*!< Longitude of the ascending node (radians) */
double inc0; /*!< Inclination (radians) */
double aop;
double omgdot; /*!< Omega dot (radians/s) */
double idot; /*!< IDOT (radians/s) */
double af0; /*!< Clock offset (seconds) */
double af1; /*!< rate (sec/sec) */
double af2; /*!< acceleration (sec/sec^2) */
double tgd; /*!< Group delay L2 bias */
int svhlth;
int codeL2;
// Working variables follow
double n; /*!< Mean motion (Average angular velocity) */
double sq1e2; /*!< sqrt(1-e^2) */
double A; /*!< Semi-major axis */
double omgkdot; /*!< OmegaDot-OmegaEdot */
} ephem_t;
typedef struct
{
int enable;
int vflg;
double alpha0,alpha1,alpha2,alpha3;
double beta0,beta1,beta2,beta3;
double A0,A1;
int dtls,tot,wnt;
int dtlsf,dn,wnlsf;
// enable custom leap event
int leapen;
} ionoutc_t;
typedef struct
{
gpstime_t g;
double range; // pseudorange
double rate;
double d; // geometric distance
double azel[2];
double iono_delay;
} range_t;
/*! \brief Structure representing a Channel */
typedef struct
{
int prn; /*< PRN Number */
int ca[CA_SEQ_LEN]; /*< C/A Sequence */
double f_carr; /*< Carrier frequency */
double f_code; /*< Code frequency */
#ifdef FLOAT_CARR_PHASE
double carr_phase;
#else
unsigned int carr_phase; /*< Carrier phase */
int carr_phasestep; /*< Carrier phasestep */
#endif
double code_phase; /*< Code phase */
gpstime_t g0; /*!< GPS time at start */
unsigned long sbf[5][N_DWRD_SBF]; /*!< current subframe */
unsigned long dwrd[N_DWRD]; /*!< Data words of sub-frame */
int iword; /*!< initial word */
int ibit; /*!< initial bit */
int icode; /*!< initial code */
int dataBit; /*!< current data bit */
int codeCA; /*!< current C/A code */
double azel[2];
range_t rho0;
} channel_t;
#endif

View File

@ -1,5 +1,9 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "uhd_device.h"
#include <QMessageBox>
#include <QFile>
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@ -7,9 +11,143 @@ MainWindow::MainWindow(QWidget *parent)
{
ui->setupUi(this);
this->setWindowTitle(tr("gnss sim V1.0"));
psettings = new QSettings("settings.ini", QSettings::IniFormat);
loadSetting();
}
MainWindow::~MainWindow()
{
saveSetting();
psettings->sync();
delete ui;
}
void MainWindow::on_pushButton_start_clicked()
{
if(ui->lineEdit_gpsfile->text().length() == 0)
{
QMessageBox::warning(NULL,tr("星历文件错误"),tr("请设置星历文件"),QMessageBox::Ok,QMessageBox::Ok);
return;
}
if(!QFile(ui->lineEdit_gpsfile->text()).exists())
{
QMessageBox::warning(NULL, tr("星历文件路径错误"), tr("没有这个文件,请确认路径是否正确。"), QMessageBox::Ok, QMessageBox::Ok);
return;
}
if(ui->lineEdit_motionfile->text().length() == 0)
{
QMessageBox::warning(NULL, tr("轨迹文件错误"), tr("请设置轨迹文件。"), QMessageBox::Ok, QMessageBox::Ok);
return;
}
if(!QFile(ui->lineEdit_motionfile->text()).exists())
{
QMessageBox::warning(NULL, tr("轨迹文件路径错误"), tr("没有这个文件,请确认路径是否正确。"), QMessageBox::Ok, QMessageBox::Ok);
return;
}
if(ui->lineEdit_gain->text().length() == 0)
{
QMessageBox::warning(NULL, tr("增益错误"), tr("请设置增益。"), QMessageBox::Ok, QMessageBox::Ok);
return;
}
float radio_gain = ui->lineEdit_gain->text().toFloat();
workThread.setGain(radio_gain);
workThread.setNavFilePath(ui->lineEdit_gpsfile->text());
workThread.setUmfile(ui->lineEdit_motionfile->text());
if(ui->lineEdit_motionfile->text().endsWith(".csv")){
workThread.useNmeaGGA(0);
}else{
workThread.useNmeaGGA(1);
}
if(ui->checkBox_currentTime->isChecked()){
workThread.useCurrentTime(true);
}else{
workThread.useCurrentTime(false);
}
workThread.start();
}
void MainWindow::on_pushButton_stop_clicked()
{
workThread.stop();
}
void MainWindow::on_pushButton_browsegps_clicked()
{
QString path = ui->lineEdit_gpsfile->text();
QString fileName = QFileDialog::getOpenFileName(
this,
"",
path,
"(brdc*)");
if (!fileName.isEmpty()) {
ui->lineEdit_gpsfile->setText(fileName);
}
}
void MainWindow::on_pushButton_browsemotion_clicked()
{
QString path = ui->lineEdit_motionfile->text();
QString fileName = QFileDialog::getOpenFileName(
this,
"",
path,
"*.csv *.txt");
if (!fileName.isEmpty()) {
ui->lineEdit_motionfile->setText(fileName);
}
}
void MainWindow::loadSetting()
{
QDir dir = QDir::current();
QStringList files;
if(psettings->contains("/setting/gps_file"))
{
QVariant gpsfile = psettings->value("/setting/gps_file");
ui->lineEdit_gpsfile->setText(gpsfile.toString());
}
if(psettings->contains("/setting/motion_file"))
{
QVariant motionfile = psettings->value("/setting/motion_file");
ui->lineEdit_motionfile->setText(motionfile.toString());
}
if(psettings->contains("/setting/radio_gain"))
{
QVariant radio_gain = psettings->value("/setting/radio_gain");
ui->lineEdit_gain->setText(radio_gain.toString());
}
if(psettings->contains("/setting/use_timenow"))
{
bool ok;
QVariant external_clock = psettings->value("/setting/use_timenow");
int val = external_clock.toInt(&ok);
if(ok && val == 1){
ui->checkBox_currentTime->setCheckState(Qt::Checked);
}else{
ui->checkBox_currentTime->setCheckState(Qt::Unchecked);
}
}
}
void MainWindow::saveSetting()
{
int val;
psettings->setValue("/setting/gps_file", ui->lineEdit_gpsfile->text());
psettings->setValue("/setting/motion_file", ui->lineEdit_motionfile->text());
psettings->setValue("/setting/radio_gain", ui->lineEdit_gain->text());
if(ui->checkBox_currentTime->isChecked()){
val = 1;
}else{
val = 0;
}
psettings->setValue("/setting/use_timenow", val);
}

View File

@ -2,6 +2,8 @@
#define MAINWINDOW_H
#include <QMainWindow>
#include "workThread.h"
#include <QSettings>
QT_BEGIN_NAMESPACE
namespace Ui {
@ -17,7 +19,17 @@ public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_start_clicked();
void on_pushButton_stop_clicked();
void on_pushButton_browsegps_clicked();
void on_pushButton_browsemotion_clicked();
private:
Ui::MainWindow *ui;
WorkThread workThread;
QSettings *psettings;
void loadSetting();
void saveSetting();
};
#endif // MAINWINDOW_H

82
uhd_device.cpp Normal file
View File

@ -0,0 +1,82 @@
#include "uhd_device.h"
#include <uhd/types/tune_request.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/thread.hpp>
#include <uhd/exception.hpp>
#include <QEventLoop>
#include <QTimer>
static uhd::usrp::multi_usrp::sptr usrp = nullptr;
static uhd::tx_streamer::sptr tx_stream;
bool start;
int init_device(double rate, double freq, double gain)
{
try {
usrp = uhd::usrp::multi_usrp::make("master_clock_rate=52e6");
} catch (uhd::key_error e) {
std::cout<<e.what()<<std::endl;
}
if(!usrp){
return false;
}
printf("Using Device: %s\n",usrp->get_pp_string().c_str());
printf("Setting TX Rate: %f Msps...\n",rate/1e6);
usrp->set_tx_rate(rate);
printf("Actual TX Rate: %f Msps...\n",usrp->get_tx_rate()/1e6);
double lo_offset = 0.0;
printf("Setting TX LO Offset: %f MHz...\n",lo_offset/1e6);
uhd::tune_request_t tune_request;
tune_request = uhd::tune_request_t(freq, lo_offset);
usrp->set_tx_freq(tune_request);
printf("Actual TX Freq: %f MHz...\n",usrp->get_tx_freq() / 1e6);
// set the rf gain
printf("Setting TX Gain: %f dB...\n",gain);
usrp->set_tx_gain(gain);
printf("Actual TX Gain: %f dB...\n",usrp->get_tx_gain());
QEventLoop loop;
QTimer::singleShot(1000,&loop,SLOT(quit()));
loop.exec();
std::vector<std::string> sensor_names;
sensor_names = usrp->get_tx_sensor_names(0);
if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked")
!= sensor_names.end()) {
uhd::sensor_value_t lo_locked = usrp->get_tx_sensor("lo_locked", 0);
printf("Checking TX: %s ...\n",lo_locked.to_pp_string().c_str());
UHD_ASSERT_THROW(lo_locked.to_bool());
}
// create a transmit streamer
std::string cpu_format = "sc16";
std::vector<size_t> channel_nums;
std::string wirefmt = "sc16";
uhd::stream_args_t stream_args(cpu_format, wirefmt);
channel_nums.push_back(0);
stream_args.channels = channel_nums;
tx_stream = usrp->get_tx_stream(stream_args);
start = true;
return true;
}
int device_transmit(short* sample, size_t samps_count)
{
uhd::tx_metadata_t md;
md.start_of_burst = start;
if(start)
start = false;
md.end_of_burst = false;
return tx_stream->send(sample, samps_count, md);
}
void close_device()
{
if(usrp){
usrp.reset();
}
}

8
uhd_device.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef UHD_DEVICE_H
#define UHD_DEVICE_H
int init_device(double rate,double freq,double gain);
void close_device();
int device_transmit(short* sample, size_t samps_count);
#endif // UHD_DEVICE_H

115
workThread.cpp Normal file
View File

@ -0,0 +1,115 @@
#include "workThread.h"
#include "uhd_device.h"
#include "gpssim.h"
#include <uhd/utils/thread.hpp>
#include <QtConcurrent/QtConcurrent>
#include <QMessageBox>
#include <QDebug>
WorkThread::WorkThread()
{
read_buff_pos = 0;
write_buff_pos = 0;
iq_buff_size = 260000;
for (int i=0; i<BUFFER_COUNT; i++) {
sample_buffers[i].buff_ptr = (short*)calloc(2 * iq_buff_size, 2);
if (sample_buffers[i].buff_ptr==NULL)
{
fprintf(stderr, "ERROR: Faild to allocate 16-bit I/Q buffer.\n");
exit(1);
}else{
sample_buffers[i].full = 0;
}
}
}
WorkThread::~WorkThread()
{
for (int i=0; i<BUFFER_COUNT; i++) {
if (sample_buffers[i].buff_ptr!=NULL)
{
free(sample_buffers[i].buff_ptr);
}
}
}
void WorkThread::transmit()
{
uhd::set_thread_priority_safe();
while(1)
{
if(bstop){
break;
}
if(sample_buffers[read_buff_pos].full)
{
int size = device_transmit(sample_buffers[read_buff_pos].buff_ptr, iq_buff_size);
qDebug()<<"tx size:"<<size;
sample_buffers[read_buff_pos].full=0;
read_buff_pos=(read_buff_pos+1) % BUFFER_COUNT;
wait_buffer_empty.wakeAll();
}
}
}
void WorkThread::stop()
{
bstop = true;
wait_buffer_empty.wakeAll();
}
void WorkThread::setGain(int g)
{
gain = g;
}
void WorkThread::setNavFilePath(QString path)
{
navfile = path;
}
void WorkThread::setUmfile(QString path)
{
umfile = path;
}
void WorkThread::useNmeaGGA(int use)
{
nmeaGGA = use;
}
void WorkThread::useCurrentTime(int use)
{
useCurTime = use;
}
void WorkThread::run()
{
if(!init_device(2.6e6, 1575420000, gain))
{
QMessageBox::warning(NULL, tr("警告"), tr("设备初始化失败!"), QMessageBox::Ok, QMessageBox::Ok);
bstop = true;
return;
}
bstop = false;
read_buff_pos=0;
write_buff_pos=0;
for (int i=0; i<BUFFER_COUNT; i++) {
sample_buffers[i].full = 0;
}
QFuture<void> future = QtConcurrent::run(this,&WorkThread::transmit);
/*while(!bstop){
m_lock.lock();
wait_buffer_empty.wait(&m_lock);
read_buff_pos++;
m_lock.unlock();
}*/
future.waitForFinished();
close_device();
}

45
workThread.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef WORKTHREAD_H
#define WORKTHREAD_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#define BUFFER_COUNT 32
typedef struct
{
short* buff_ptr;
volatile int full;
}sample_buffer_t;
class WorkThread : public QThread
{
Q_OBJECT
public:
WorkThread();
~WorkThread();
void run() override;
void transmit();
void stop();
void setGain(int g);
void setNavFilePath(QString path);
void setUmfile(QString path);
void useNmeaGGA(int use);
void useCurrentTime(int use);
private:
int read_buff_pos=0;
int write_buff_pos=0;
int iq_buff_size=260000;
bool bstop = true;
QMutex m_lock;
QWaitCondition wait_buffer_empty;
sample_buffer_t sample_buffers[BUFFER_COUNT];
QString navfile;
QString umfile;
int gain=0;
int nmeaGGA;
bool useCurTime;
};
#endif // WORKTHREAD_H