/////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // // written by Christian Daniel // // // // This program is free software; you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation as version 3 of the License, or // // // // This program is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY; without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License V3 for more details. // // // // You should have received a copy of the GNU General Public License // // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// // FIXME: FCD is handled very badly! #include #include #include #include "dsp/dspcommands.h" #include "fcdproinput.h" #include "fcdprogui.h" #include "fcdproserializer.h" #include "fcdprothread.h" #include "fcdtraits.h" #include "fcdproconst.h" MESSAGE_CLASS_DEFINITION(FCDProInput::MsgConfigureFCD, Message) FCDProInput::Settings::Settings() { resetToDefaults(); } void FCDProInput::Settings::resetToDefaults() { centerFrequency = 435000000; LOppmTenths = 0; biasT = 0; lnaGainIndex = 0; rfFilterIndex = 0; lnaEnhanceIndex = 0; bandIndex = 0; mixerGainIndex = 0; mixerFilterIndex = 0; biasCurrentIndex = 0; modeIndex = 0; gain1Index = 0; rcFilterIndex = 0; gain2Index = 0; gain3Index = 0; gain4Index = 0; ifFilterIndex = 0; gain5Index = 0; gain6Index = 0; } QByteArray FCDProInput::Settings::serialize() const { FCDProSerializer::FCDData data; data.m_data.m_frequency = centerFrequency; data.m_LOppmTenths = LOppmTenths; data.m_biasT = biasT; data.m_lnaGainIndex = lnaGainIndex; data.m_rfFilterIndex = rfFilterIndex; data.m_lnaEnhanceIndex = lnaEnhanceIndex; data.m_bandIndex = bandIndex; data.m_mixerGainIndex = mixerGainIndex; data.m_mixerFilterIndex = mixerFilterIndex; data.m_biasCurrentIndex = biasCurrentIndex; data.m_modeIndex = modeIndex; data.m_gain1Index = gain1Index; data.m_rcFilterIndex = rcFilterIndex; data.m_gain2Index = gain2Index; data.m_gain3Index = gain3Index; data.m_gain4Index = gain4Index; data.m_ifFilterIndex = ifFilterIndex; data.m_gain5Index = gain5Index; data.m_gain6Index = gain6Index; QByteArray byteArray; FCDProSerializer::writeSerializedData(data, byteArray); return byteArray; } bool FCDProInput::Settings::deserialize(const QByteArray& serializedData) { FCDProSerializer::FCDData data; bool valid = FCDProSerializer::readSerializedData(serializedData, data); centerFrequency = data.m_data.m_frequency; LOppmTenths = data.m_LOppmTenths; biasT = data.m_biasT; lnaGainIndex = data.m_lnaGainIndex; rfFilterIndex = data.m_rfFilterIndex; lnaEnhanceIndex = data.m_lnaEnhanceIndex; bandIndex = data.m_bandIndex; mixerGainIndex = data.m_mixerGainIndex; biasCurrentIndex = data.m_biasCurrentIndex; modeIndex = data.m_modeIndex; gain1Index = data.m_gain1Index; rcFilterIndex = data.m_rcFilterIndex; gain2Index = data.m_gain2Index; gain3Index = data.m_gain3Index; gain4Index = data.m_gain4Index; ifFilterIndex = data.m_ifFilterIndex; gain5Index = data.m_gain5Index; gain6Index = data.m_gain6Index; return valid; } FCDProInput::FCDProInput() : m_dev(0), m_settings(), m_FCDThread(0), m_deviceDescription(fcd_traits::displayedName) { } FCDProInput::~FCDProInput() { stop(); } bool FCDProInput::init(const Message& cmd) { return false; } bool FCDProInput::start(int device) { qDebug() << "FCDProInput::start with device #" << device; QMutexLocker mutexLocker(&m_mutex); if (m_FCDThread) { return false; } m_dev = fcdOpen(fcd_traits::vendorId, fcd_traits::productId, device); if (m_dev == 0) { qCritical("FCDProInput::start: could not open FCD"); return false; } /* Apply settings before streaming to avoid bus contention; * there is very little spare bandwidth on a full speed USB device. * Failure is harmless if no device is found * ... This is rubbish...*/ //applySettings(m_settings, true); if(!m_sampleFifo.setSize(96000*4)) { qCritical("Could not allocate SampleFifo"); return false; } if ((m_FCDThread = new FCDProThread(&m_sampleFifo)) == NULL) { qFatal("out of memory"); return false; } m_FCDThread->startWork(); mutexLocker.unlock(); applySettings(m_settings, true); qDebug("FCDProInput::started"); return true; } void FCDProInput::stop() { QMutexLocker mutexLocker(&m_mutex); if (m_FCDThread) { m_FCDThread->stopWork(); // wait for thread to quit ? delete m_FCDThread; m_FCDThread = 0; } fcdClose(m_dev); m_dev = 0; } const QString& FCDProInput::getDeviceDescription() const { return m_deviceDescription; } int FCDProInput::getSampleRate() const { return fcd_traits::sampleRate; } quint64 FCDProInput::getCenterFrequency() const { return m_settings.centerFrequency; } bool FCDProInput::handleMessage(const Message& message) { if(MsgConfigureFCD::match(message)) { qDebug() << "FCDProInput::handleMessage: MsgConfigureFCD"; MsgConfigureFCD& conf = (MsgConfigureFCD&) message; applySettings(conf.getSettings(), false); return true; } else { return false; } } void FCDProInput::applySettings(const Settings& settings, bool force) { bool signalChange = false; if ((m_settings.centerFrequency != settings.centerFrequency) || force) { qDebug() << "FCDProInput::applySettings: fc: " << settings.centerFrequency; m_settings.centerFrequency = settings.centerFrequency; if (m_dev != 0) { set_center_freq((double) m_settings.centerFrequency); } signalChange = true; } if ((m_settings.biasT != settings.biasT) || force) { m_settings.biasT = settings.biasT; if (m_dev != 0) { set_bias_t(settings.biasT > 0); } } if ((m_settings.lnaGainIndex != settings.lnaGainIndex) || force) { m_settings.lnaGainIndex = settings.lnaGainIndex; if (m_dev != 0) { set_ifFilter(settings.lnaGainIndex); } } if ((m_settings.rfFilterIndex != settings.rfFilterIndex) || force) { m_settings.rfFilterIndex = settings.rfFilterIndex; if (m_dev != 0) { set_rfFilter(settings.rfFilterIndex); } } if ((m_settings.lnaEnhanceIndex != settings.lnaEnhanceIndex) || force) { m_settings.lnaEnhanceIndex = settings.lnaEnhanceIndex; if (m_dev != 0) { set_lnaEnhance(settings.lnaEnhanceIndex); } } if ((m_settings.bandIndex != settings.bandIndex) || force) { m_settings.bandIndex = settings.bandIndex; if (m_dev != 0) { set_band(settings.bandIndex); } } if ((m_settings.mixerGainIndex != settings.mixerGainIndex) || force) { m_settings.mixerGainIndex = settings.mixerGainIndex; if (m_dev != 0) { set_mixerGain(settings.mixerGainIndex); } } if ((m_settings.mixerFilterIndex != settings.mixerFilterIndex) || force) { m_settings.mixerFilterIndex = settings.mixerFilterIndex; if (m_dev != 0) { set_mixerFilter(settings.mixerFilterIndex); } } if ((m_settings.biasCurrentIndex != settings.biasCurrentIndex) || force) { m_settings.biasCurrentIndex = settings.biasCurrentIndex; if (m_dev != 0) { set_biasCurrent(settings.biasCurrentIndex); } } if ((m_settings.modeIndex != settings.modeIndex) || force) { m_settings.modeIndex = settings.modeIndex; if (m_dev != 0) { set_mode(settings.modeIndex); } } if ((m_settings.gain1Index != settings.gain1Index) || force) { m_settings.gain1Index = settings.gain1Index; if (m_dev != 0) { set_gain1(settings.gain1Index); } } if ((m_settings.rcFilterIndex != settings.rcFilterIndex) || force) { m_settings.rcFilterIndex = settings.rcFilterIndex; if (m_dev != 0) { set_rcFilter(settings.rcFilterIndex); } } if ((m_settings.gain2Index != settings.gain2Index) || force) { m_settings.gain2Index = settings.gain2Index; if (m_dev != 0) { set_gain2(settings.gain2Index); } } if ((m_settings.gain3Index != settings.gain3Index) || force) { m_settings.gain3Index = settings.gain3Index; if (m_dev != 0) { set_gain3(settings.gain3Index); } } if ((m_settings.gain4Index != settings.gain4Index) || force) { m_settings.gain4Index = settings.gain4Index; if (m_dev != 0) { set_gain4(settings.gain4Index); } } if ((m_settings.ifFilterIndex != settings.ifFilterIndex) || force) { m_settings.ifFilterIndex = settings.ifFilterIndex; if (m_dev != 0) { set_ifFilter(settings.ifFilterIndex); } } if ((m_settings.gain5Index != settings.gain5Index) || force) { m_settings.gain5Index = settings.gain5Index; if (m_dev != 0) { set_gain5(settings.gain5Index); } } if ((m_settings.gain6Index != settings.gain6Index) || force) { m_settings.gain6Index = settings.gain6Index; if (m_dev != 0) { set_gain6(settings.gain6Index); } } if (signalChange) { DSPSignalNotification *notif = new DSPSignalNotification(fcd_traits::sampleRate, m_settings.centerFrequency); getOutputMessageQueue()->push(notif); } } void FCDProInput::set_center_freq(double freq) { if (fcdAppSetFreq(m_dev, freq) == FCD_MODE_NONE) { qDebug("No FCD HID found for frquency change"); } } void FCDProInput::set_bias_t(bool on) { quint8 cmd = on ? 1 : 0; // TODO: use FCD Pro controls //fcdAppSetParam(m_dev, FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1); } void FCDProInput::set_lnaGain(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_lna_gain_nb_values())) { return; } quint8 cmd_value = FCDProConstants::lna_gains[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_LNA_GAIN, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_lnaGain: failed to set at " << cmd_value; } } void FCDProInput::set_rfFilter(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_rf_filter_nb_values())) { return; } quint8 cmd_value = FCDProConstants::rf_filters[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_RF_FILTER, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_rfFilter: failed to set at " << cmd_value; } } void FCDProInput::set_lnaEnhance(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_lna_enhance_nb_values())) { return; } quint8 cmd_value = FCDProConstants::lna_enhances[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_LNA_ENHANCE, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_lnaEnhance: failed to set at " << cmd_value; } } void FCDProInput::set_band(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_band_nb_values())) { return; } quint8 cmd_value = FCDProConstants::bands[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_BAND, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_band: failed to set at " << cmd_value; } } void FCDProInput::set_mixerGain(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_mixer_gain_nb_values())) { return; } quint8 cmd_value = FCDProConstants::mixer_gains[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_MIXER_GAIN, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_mixerGain: failed to set at " << cmd_value; } } void FCDProInput::set_mixerFilter(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_mixer_filter_nb_values())) { return; } quint8 cmd_value = FCDProConstants::mixer_filters[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_MIXER_FILTER, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_mixerFilter: failed to set at " << cmd_value; } } void FCDProInput::set_biasCurrent(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_bias_current_nb_values())) { return; } quint8 cmd_value = FCDProConstants::bias_currents[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_BIAS_CURRENT, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_biasCurrent: failed to set at " << cmd_value; } } void FCDProInput::set_mode(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_gain_mode_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_gain_modes[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_GAIN_MODE, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_mode: failed to set at " << cmd_value; } } void FCDProInput::set_gain1(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_gain1_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_gains1[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_GAIN1, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_gain1: failed to set at " << cmd_value; } } void FCDProInput::set_rcFilter(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_rc_filter_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_rc_filters[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_RC_FILTER, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_rcFilter: failed to set at " << cmd_value; } } void FCDProInput::set_gain2(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_gain2_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_gains2[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_GAIN2, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_gain2: failed to set at " << cmd_value; } } void FCDProInput::set_gain3(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_gain3_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_gains3[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_GAIN3, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_gain3: failed to set at " << cmd_value; } } void FCDProInput::set_gain4(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_gain4_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_gains4[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_GAIN4, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_gain4: failed to set at " << cmd_value; } } void FCDProInput::set_ifFilter(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_filter_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_filters[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_FILTER, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_ifFilter: failed to set at " << cmd_value; } } void FCDProInput::set_gain5(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_gain5_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_gains5[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_GAIN5, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_gain5: failed to set at " << cmd_value; } } void FCDProInput::set_gain6(int index) { if ((index < 0) || (index >= FCDProConstants::fcdpro_if_gain6_nb_values())) { return; } quint8 cmd_value = FCDProConstants::if_gains6[index].value; if (fcdAppSetParam(m_dev, FCDPRO_HID_CMD_SET_IF_GAIN6, &cmd_value, 1) != FCD_MODE_APP) { qWarning() << "FCDProPlusInput::set_gain6: failed to set at " << cmd_value; } }