#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 // 用于音频文件写入 #include // 用于音频播放 #include #include #include #include #include #define BUFFER_SIZE 512 // 缓冲区大小 Device_UHD* ys_radio; AM_Demod am_demod; snd_pcm_t *handle; int err; namespace { double clamp_to_axis_range(double value, renderive::Range range) { const double lower = std::min(range.origin, range.target); const double upper = std::max(range.origin, range.target); return std::clamp(value, lower, upper); } } void Back_End::play(const QString& fileName){ // ys_radio->YsSetFreq(value); } Back_End *Back_End::instance() { static Back_End temp; return &temp; } bool Back_End::match(QKeyEvent *e, const QString &function) { bool ok = function_map.contains(function); if(!ok){ qDebug() << "error Global::match 失败! 功能" << function << "不存在!" << e; } return e->key() == function_map[function]; } void Back_End::YsSetFreq(quint64 value) { ys_radio->setDevParam("RX0",UHD_ParamType::CenterFreq,value); ys_radio->setDevZDParam("RX0",0,value,150000,300000); } qint64 Back_End::YsGetFreq() { return (qint64)ys_radio->getDevParam("RX0",UHD_ParamType::CenterFreq); } // 获取到频率 void Back_End::YsReceiveFreq(quint64 freq) { qDebug() << "接收到频率:" << freq; Main_Widget::instance()->radio_widget->select_value_widget->set_frequent(freq); } // 音量设置 void Back_End::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 Back_End::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 Back_End::YsGetRfGain() { return 60; } // 增益设置 void Back_End::YsSetRfGain(int value) { ys_radio->setDevParam("RX0",UHD_ParamType::Gain,value); qDebug()<<"增益设置"<DataLen; //绘图用 if(pUHDData->DataType == UHD_Enum_DataType::kd_fft ) { std::vector 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()<radio_widget; auto iw = mw->intermediate_frequency_widget; rw->water_fall->give_data(QTime::currentTime(), data); // 中频瀑布图 rw->spectrogram_line->give_data(data); // 中频频谱图 iw->afterglow->give_data(data); // 余晖图 iw->spectrogram_line->give_data(data); // 瀑布图 // auto sl = Main_Widget::instance()->sweep_frequency_widget->sweep_frequency_line; // int n = sl->block_frequency_point_size(); // sl->give_data(data); } if(pUHDData->DataType == UHD_Enum_DataType::zd_ddc) { // qDebug()<<"收到zd_ddc数据包大小"<DataLen; short rbuf[512]; std::complex* cbuf_ptr = reinterpret_cast*>((char*)pData + 64); am_demod.step(cbuf_ptr, rbuf, 512); // 解调数据 //Main_Widget::instance()->radio_widget->giv auto main = Main_Widget::instance(); auto radio = main->radio_widget; if (radio && radio->audio_spectrogram_plot) { std::vector data(512); auto axis = radio->audio_spectrogram_plot->power_axis(); const auto range = axis ? axis->coord_range() : renderive::Range{-32768.0, 32767.0}; for(int i = 0; i < 512; ++i){ data[i] = clamp_to_axis_range(rbuf[i], range); } //qDebug() << data; radio->audio_spectrogram_plot->give_data(data); } //std::cout << "audio == " << rbuf[256] << std::endl; if (radio && radio->time_power) { auto axis = radio->time_power->value_axis(); const auto range = axis ? axis->coord_range() : renderive::Range{-32768.0, 32767.0}; radio->time_power->give_data(QTime::currentTime(), clamp_to_axis_range(rbuf[256], range)); } // 保存音频流 // 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); } } Back_End::Back_End() { function_map["主菜单"] = Qt::Key_F9; function_map["属性菜单"] = Qt::Key_F11; function_map["顶部菜单"] = Qt::Key_F10; function_map["退出"] = Qt::Key_Escape; function_map["确定"] = Qt::Key_F2; function_map["左移"] = Qt::Key_Left; function_map["右移"] = Qt::Key_Right; function_map["增加"] = Qt::Key_Up; function_map["减小"] = Qt::Key_Down; function_map["切换音量/RF Gain"] = Qt::Key_F1; function_map["特别增加"] = Qt::Key_PageUp; function_map["特别减小"] = Qt::Key_PageDown; ys_radio = new Device_UHD(); uhd::device_addrs_t tmp_add = ys_radio->findDevices(); while(ys_radio->openDevice(tmp_add[0]) != true) { qDebug()<<"9002连接失败,重试中..."; sleep(1); ys_radio->openDevice(tmp_add[0]); } qDebug()<<"9002设备连接成功"; quint64 value = 10125000; ys_radio->setDevParam("RX0",UHD_ParamType::CenterFreq,value); // 宽带设置 ys_radio->setDevParam("RX0",UHD_ParamType::BandWidth,100000); // 改带宽,频谱带宽不变 ys_radio->setDevParam("RX0",UHD_ParamType::SampleFreq,480000); // 改采样率,频谱带宽变化 ys_radio->setDevParam("RX0",UHD_ParamType::Gain,33); // ys_radio->setDevDataSwitch("RX0",KDDCSwitch,0,true); ys_radio->setDevFFTParam(UHD_FFTWin::blkmc,_1024,10); // FFT设置 ys_radio->setDevDataSwitch("RX0",KFFTSwitch,0,true); ys_radio->setDevZDParam("RX0",0,value,15000,30000); // 窄带设置 ys_radio->setDevDataSwitch("RX0",ZDDCSwitch,0, true); ys_radio->startDevRecv(0); //ys_radio->stopDevRecv(0); ys_radio->callBackData = std::bind(&Back_End::call_back_data_func, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); // ys_radio->hide(); // connect(ys_radio, &YsRadio::YsGetFreq, this, &Back_End::YsReceiveFreq); // connect(ys_radio,&YsRadio::YsReceiveSpectrumData,this, &Back_End::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(¶ms); // 初始化硬件参数结构 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 Back_End::get_audio_file_location() { return "./"; } QString Back_End::get_screenshot_save_file_name() { QDateTime currentDateTime = QDateTime::currentDateTime(); return "截屏_" + currentDateTime.toString() .replace(":", "_") .replace("/", "_") + ".png"; } QString Back_End::get_screenshot_save_dir_path() { return "/media/sdcard1/"; } #endif