Files
Radio/module/radio/BackEnd/BackEnd_True.cpp
T
2026-07-30 18:09:03 +08:00

336 lines
10 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 <QAudioFormat>
#include <QAudioOutput>
#include <alsa/asoundlib.h>
#include <vector>
#define BUFFER_SIZE 512 // 缓冲区大小
Device_UHD* ys_radio;
AM_Demod am_demod;
snd_pcm_t *handle;
int err;
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()<<"增益设置"<<value;
}
void Back_End::call_back_data_func(int channel, void *pData, int i_length)
{
UHD_Struct_KFFT *pUHDData = (UHD_Struct_KFFT *)pData;
// qDebug()<<"收到数据包大小"<<pUHDData->DataLen;
//绘图用
if(pUHDData->DataType == UHD_Enum_DataType::kd_fft ) {
std::vector<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 = Main_Widget::instance();
auto rw = mw->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数据包大小"<<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); // 解调数据
//Main_Widget::instance()->radio_widget->giv
std::vector<double> data(512);
for(int i = 0; i < 512; ++i){
data[i] = rbuf[i];
}
auto main = Main_Widget::instance();
auto radio = main->radio_widget;
//qDebug() << data;
radio->audio_spectrogram_plot->give_data(data);
//std::cout << "audio == " << rbuf[256] << std::endl;
radio->time_power->give_data(QTime::currentTime(), 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);
}
}
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(&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 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