Files
Radio/module/radio/BackEnd/BackEnd_True.cpp
T
2026-07-23 17:06:07 +08:00

337 lines
11 KiB
C++

#ifndef MockBackEnd
#include "BackEnd.h"
#include "./MainWidget.h"
#include "../component/FrequentShower.h"
#include "../component/ProgressBar.h"
#include "IntermediateFrequencyWidget.h"
#include "RadioWidget.h"
#include "SweepFrequencyWidget.h"
#include "am_fm_cw_modem.hpp"
#include "device_uhd.h"
#include <sndfile.h> // 用于音频文件写入
#include <portaudio.h> // 用于音频播放
#include <QVector> // Qt 的 QVector
#include <QAudioFormat>
#include <QAudioOutput>
#include <alsa/asoundlib.h>
#define BUFFER_SIZE 512 // 缓冲区大小
Device_UHD* mYsRadio;
AM_Demod am_demod;
snd_pcm_t *handle;
int err;
void BackEnd::play(const QString& fileName){
// mYsRadio->YsSetFreq(value);
}
BackEnd *BackEnd::instance() {
static BackEnd temp;
return &temp;
}
bool BackEnd::match(QKeyEvent *e, const QString &function) {
bool ok = mFunctionMap.contains(function);
if(!ok){
qDebug() << "error Global::match 失败! 功能" << function << "不存在!" << e;
}
return e->key() == mFunctionMap[function];
}
void BackEnd::YsSetFreq(quint64 value)
{
mYsRadio->setDevParam("RX0",UHD_ParamType::CenterFreq,value);
mYsRadio->setDevZDParam("RX0",0,value,150000,300000);
}
qint64 BackEnd::YsGetFreq() {
return (qint64)mYsRadio->getDevParam("RX0",UHD_ParamType::CenterFreq);
}
// 获取到频率
void BackEnd::YsReceiveFreq(quint64 freq) {
qDebug() << "接收到频率:" << freq;
MainWidget::instance()->mRadioWidget->mSelectValueWidget->set_frequent(freq);
}
// 音量设置
void BackEnd::YsSetAfGain(int value) {
std::string command = "amixer sset Master " + std::to_string(value) + "%";
int result = system(command.c_str());
if (result != 0) {
std::cerr << "Failed to set volume: " << result << std::endl;
}
}
int BackEnd::YsGetAfGain() {
FILE *pipe = popen("amixer sget Master | grep 'Left:' | awk -F'[][]' '{ print $2 }'", "r");
if (!pipe) {
std::cerr << "Failed to run command" << std::endl;
return -1;
}
char buffer[128];
std::string result = "";
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
// Remove newline character if present
result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
// Convert string to integer
int volume = std::stoi(result);
return volume;
}
int BackEnd::YsGetRfGain() {
return 60;
}
// 增益设置
void BackEnd::YsSetRfGain(int value)
{
mYsRadio->setDevParam("RX0",UHD_ParamType::Gain,value);
qDebug()<<"增益设置"<<value;
}
void BackEnd::callBackData_Func(int channel, void *pData, int iLength)
{
UHD_Struct_KFFT *pUHDData = (UHD_Struct_KFFT *)pData;
// qDebug()<<"收到数据包大小"<<pUHDData->DataLen;
//绘图用
if(pUHDData->DataType == UHD_Enum_DataType::kd_fft ) {
QVector<double> data;
data.clear();
for(int i = 0; i < 1024; i++)
{
unsigned short ts = *((unsigned short *)pUHDData+32+i);
//qDebug()<<(double) (ts/256);
data.push_back((double) (ts/256));
// if(i==512)
// {qDebug()<<ts;}
}
// qDebug()<< "data.size ==" << data.size() << "data == "<< data;
auto mw = MainWidget::instance();
auto rw = mw->mRadioWidget;
auto iw = mw->mIntermediateFrequencyWidget;
int tick = rw->mWaterFall->time_axis()->give_data(QTime::currentTime());
rw->mWaterFall->give_data(tick, data); // 中频瀑布图
rw->mSpectrogramLine->give_data(data); // 中频频谱图
iw->mAfterglow->give_data(data); // 余晖图
iw->mSpectrogramLine->give_data(data); // 瀑布图
// auto sl = MainWidget::instance()->mSweepFrequencyWidget->mSweepFrequencyLine;
// int n = sl->block_frequent_point_size();
// sl->give_data(data);
}
if(pUHDData->DataType == UHD_Enum_DataType::zd_ddc)
{
// qDebug()<<"收到zd_ddc数据包大小"<<pUHDData->DataLen;
short rbuf[512];
std::complex<short>* cbuf_ptr = reinterpret_cast<std::complex<short>*>((char*)pData + 64);
am_demod.step(cbuf_ptr, rbuf, 512); // 解调数据
//MainWidget::instance()->mRadioWidget->giv
QVector<double> data(512);
for(int i = 0; i < 512; ++i){
data[i] = rbuf[i];
}
auto main = MainWidget::instance();
auto radio = main->mRadioWidget;
//qDebug() << data;
radio->mAudioSpectrogramPlot->give_data(data);
//std::cout << "audio == " << rbuf[256] << std::endl;
int tick = radio->mTimePower->time_axis()->give_data(QTime::currentTime());
radio->mTimePower->give_data(tick, rbuf[256]);
// 保存音频流
// ofstream fp_dst;
// fp_dst.open("FM_DeMod.dat", ios::out | ios::binary | ios::app);
// fp_dst.write((char *)rbuf, 512 * 2ll);
// fp_dst.close();
// snd_pcm_writei 是ALSA库提供的函数,用于将音频数据写入PCM设备。
// handle:指向已打开的PCM设备句柄。
// buffer:指向包含音频数据的缓冲区。
// BUFFER_SIZE:要写入的数据帧数。
// err:存储 snd_pcm_writei 函数的返回值。
// == -EPIPE:检查返回值是否为 -EPIPE,这表示发生了XRUN(欠载)错误。XRUN发生在音频缓冲区为空时,即音频设备没有足够的数据进行播放。
// 播放数据
if ((err = snd_pcm_writei(handle, rbuf, BUFFER_SIZE)) == -EPIPE) {
fprintf(stderr, "XRUN occurred\n");
// 重新准备PCM设备
if ((err = snd_pcm_prepare(handle)) < 0) {
fprintf(stderr, "无法重新准备PCM设备: %s\n", snd_strerror(err));
}
} else if (err < 0) {
fprintf(stderr, "无法写入音频数据: %s\n", snd_strerror(err));
}
// // 关闭音频设备
// snd_pcm_close(handle);
}
}
BackEnd::BackEnd() {
mFunctionMap["主菜单"] = Qt::Key_F9;
mFunctionMap["属性菜单"] = Qt::Key_F11;
mFunctionMap["顶部菜单"] = Qt::Key_F10;
mFunctionMap["退出"] = Qt::Key_Escape;
mFunctionMap["确定"] = Qt::Key_F2;
mFunctionMap["左移"] = Qt::Key_Left;
mFunctionMap["右移"] = Qt::Key_Right;
mFunctionMap["增加"] = Qt::Key_Up;
mFunctionMap["减小"] = Qt::Key_Down;
mFunctionMap["切换音量/RF Gain"] = Qt::Key_F1;
mFunctionMap["特别增加"] = Qt::Key_PageUp;
mFunctionMap["特别减小"] = Qt::Key_PageDown;
mYsRadio = new Device_UHD();
uhd::device_addrs_t tmp_add = mYsRadio->findDevices();
while(mYsRadio->openDevice(tmp_add[0]) != true)
{
qDebug()<<"9002连接失败,重试中...";
sleep(1);
mYsRadio->openDevice(tmp_add[0]);
}
qDebug()<<"9002设备连接成功";
quint64 value = 10125000;
mYsRadio->setDevParam("RX0",UHD_ParamType::CenterFreq,value); // 宽带设置
mYsRadio->setDevParam("RX0",UHD_ParamType::BandWidth,100000); // 改带宽,频谱带宽不变
mYsRadio->setDevParam("RX0",UHD_ParamType::SampleFreq,480000); // 改采样率,频谱带宽变化
mYsRadio->setDevParam("RX0",UHD_ParamType::Gain,33);
// mYsRadio->setDevDataSwitch("RX0",KDDCSwitch,0,true);
mYsRadio->setDevFFTParam(UHD_FFTWin::blkmc,_1024,10); // FFT设置
mYsRadio->setDevDataSwitch("RX0",KFFTSwitch,0,true);
mYsRadio->setDevZDParam("RX0",0,value,15000,30000); // 窄带设置
mYsRadio->setDevDataSwitch("RX0",ZDDCSwitch,0, true);
mYsRadio->startDevRecv(0);
//mYsRadio->stopDevRecv(0);
mYsRadio->callBackData = std::bind(&BackEnd::callBackData_Func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
// mYsRadio->hide();
// connect(mYsRadio, &YsRadio::YsGetFreq, this, &BackEnd::YsReceiveFreq);
// connect(mYsRadio,&YsRadio::YsReceiveSpectrumData,this, &BackEnd::YsReceiveSpectrumData);
// 打开音频设备
if ((err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
fprintf(stderr, "无法打开音频设备: %s\n", snd_strerror(err));
exit(1);
} else{
qDebug()<<"打开音频设备成功";
}
// 设置音频参数
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(&params);
// 初始化硬件参数结构
if ((err = snd_pcm_hw_params_any(handle, params)) < 0) {
fprintf(stderr, "无法初始化硬件参数结构: %s\n", snd_strerror(err));
// goto close_device;
}else{
qDebug()<<"初始化硬件参数结构成功";
}
// 设置访问类型
if ((err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
fprintf(stderr, "无法设置访问类型: %s\n", snd_strerror(err));
// goto close_device;
}else{
qDebug()<<"设置访问类型";
}
// 设置样本格式
if ((err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE)) < 0) {
fprintf(stderr, "无法设置样本格式: %s\n", snd_strerror(err));
// goto close_device;
}else{
qDebug()<<"设置样本格式";
}
// 设置采样率
unsigned int rate = 30000;//44100
if ((err = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0)) < 0) {
fprintf(stderr, "无法设置采样率: %s\n", snd_strerror(err));
// goto close_device;
}else{
qDebug()<<"设置采样率";
}
// 设置声道数
if ((err = snd_pcm_hw_params_set_channels(handle, params, 1)) < 0) {
fprintf(stderr, "无法设置声道数: %s\n", snd_strerror(err));
// goto close_device;
}else{
qDebug()<<"设置声道数";
}
// 应用硬件参数
if ((err = snd_pcm_hw_params(handle, params)) < 0) {
fprintf(stderr, "无法应用硬件参数: %s\n", snd_strerror(err));
// goto close_device;
}else{
qDebug()<<"应用硬件参数";
}
// 准备播放
if ((err = snd_pcm_prepare(handle)) < 0) {
fprintf(stderr, "无法准备播放: %s\n", snd_strerror(err));
// goto close_device;
} else{
qDebug()<<"准备播放";
}
//close_device:
// // 关闭音频设备
// snd_pcm_close(handle);
}
QString BackEnd::getAudioFileLocation() {
return "./";
}
QString BackEnd::get_screenshot_save_file_name() {
QDateTime currentDateTime = QDateTime::currentDateTime();
return "截屏_" +
currentDateTime.toString()
.replace(":", "_")
.replace("/", "_") + ".png";
}
QString BackEnd::get_screenshot_save_dir_path() {
return "/media/sdcard1/";
}
#endif