From f10da647178b13f8153b91cca75a98e31bdeea4f Mon Sep 17 00:00:00 2001 From: f4exb <f4exb06@gmail.com> Date: Sun, 12 Jun 2022 22:51:18 +0200 Subject: [PATCH] M17 modulator: SMS packet + --- modems/m17/M17Modulator.h | 100 ++- plugins/channeltx/modm17/CMakeLists.txt | 10 + plugins/channeltx/modm17/m17mod.cpp | 43 +- plugins/channeltx/modm17/m17mod.h | 1 + plugins/channeltx/modm17/m17modbaseband.cpp | 4 +- plugins/channeltx/modm17/m17modbaseband.h | 1 + plugins/channeltx/modm17/m17modgui.cpp | 228 +++++- plugins/channeltx/modm17/m17modgui.h | 17 +- plugins/channeltx/modm17/m17modgui.ui | 679 +++++++++++++++++- plugins/channeltx/modm17/m17modprocessor.cpp | 99 +++ plugins/channeltx/modm17/m17modprocessor.h | 21 +- plugins/channeltx/modm17/m17modsettings.cpp | 60 +- plugins/channeltx/modm17/m17modsettings.h | 43 +- plugins/channeltx/modm17/m17modsource.cpp | 151 ++-- plugins/channeltx/modm17/m17modsource.h | 7 +- sdrbase/resources/webapi/doc/html2/index.html | 15 +- .../webapi/doc/swagger/include/M17Mod.yaml | 9 +- sdrgui/resources/res.qrc | 2 + sdrgui/resources/sms.png | Bin 0 -> 821 bytes sdrgui/resources/world.png | Bin 0 -> 7828 bytes .../sdrangel/api/swagger/include/M17Mod.yaml | 9 +- swagger/sdrangel/code/html2/index.html | 15 +- .../code/qt5/client/SWGM17ModSettings.cpp | 72 +- .../code/qt5/client/SWGM17ModSettings.h | 20 +- 24 files changed, 1432 insertions(+), 174 deletions(-) create mode 100644 plugins/channeltx/modm17/m17modprocessor.cpp create mode 100644 sdrgui/resources/sms.png create mode 100644 sdrgui/resources/world.png diff --git a/modems/m17/M17Modulator.h b/modems/m17/M17Modulator.h index 0d4e1a5c8..12fbd16af 100644 --- a/modems/m17/M17Modulator.h +++ b/modems/m17/M17Modulator.h @@ -39,6 +39,7 @@ public: using codec_frame_t = std::array<uint8_t, 16>; using payload_t = std::array<uint8_t, 34>; // Bytes in the payload of a data frame. using frame_t = std::array<uint8_t, 46>; // M17 frame (without sync word). + using packet_t = std::array<uint8_t, 25>; // Packet payload static constexpr std::array<uint8_t, 2> SYNC_WORD = {0x32, 0x43}; static constexpr std::array<uint8_t, 2> LSF_SYNC_WORD = {0x55, 0xF7}; @@ -57,6 +58,31 @@ public: return 0; } + template <typename T, size_t N> + static std::array<int8_t, N * 4> bytes_to_symbols(const std::array<T, N>& bytes) + { + std::array<int8_t, N * 4> result; + size_t index = 0; + + for (auto b : bytes) + { + for (size_t i = 0; i != 4; ++i) + { + result[index++] = bits_to_symbol(b >> 6); + b <<= 2; + } + } + + return result; + } + + static + void make_preamble(std::array<uint8_t, 48>& preamble_bytes) + { + // Preamble is simple... bytes -> symbols. + preamble_bytes.fill(0x77); + } + /** * Encode each LSF segment into a Golay-encoded LICH segment bitstream. */ @@ -109,7 +135,7 @@ public: /** * Construct the link setup frame and split into LICH segments. */ - void make_link_setup(lich_t& lich, mobilinkd::M17Modulator::frame_t lsf) + void make_link_setup(lich_t& lich, mobilinkd::M17Modulator::frame_t lsf_frame) { using namespace mobilinkd; @@ -141,12 +167,14 @@ public: } auto encoded = conv_encode(lsf); + auto size = puncture_bytes(encoded, lsf_frame, P1); - auto size = puncture_bytes(encoded, lsf, P1); - assert(size == 368); + if (size != 368) { + std::cerr << "make_link_setup: incorrect size (not 368)" << size; + } - interleaver_.interleave(lsf); - randomizer_(lsf); + interleaver_.interleave(lsf_frame); + randomizer_(lsf_frame); } /** @@ -168,7 +196,7 @@ public: * Assemble the audio frame payload by appending the frame number, encoded audio, * and CRC, then convolutionally coding and puncturing the data. */ - payload_t make_payload(uint16_t frame_number, const codec_frame_t& payload) + payload_t make_audio_payload(uint16_t frame_number, const codec_frame_t& payload) { std::array<uint8_t, 20> data; // FN, Audio, CRC = 2 + 16 + 2; data[0] = uint8_t((frame_number >> 8) & 0xFF); @@ -188,7 +216,47 @@ public: payload_t punctured; auto size = puncture_bytes(encoded, punctured, mobilinkd::P2); - assert(size == 272); + + if (size != 272) { + std::cerr << "mobilinkd::M17Modulator::make_audio_payload: incorrect size (not 272)" << size; + } + + return punctured; + } + + frame_t make_packet_frame(uint8_t packet_number, bool last_packet, packet_t packet, int packet_size) + { + std::array<uint8_t, 26> packet_assembly; + packet_assembly.fill(0); + std::copy(packet.begin(), packet.begin() + packet_size, packet_assembly.begin()); + + if (packet_number == 0) { + crc_.reset(); + } + + for (int i = 0; i < packet_size; i++) { + crc_(packet[i]); + } + + if (last_packet) + { + packet_assembly[25] = 0x80 | (packet_size<<2); + packet_assembly[packet_size] = crc_.get_bytes()[1]; + packet_assembly[packet_size+1] = crc_.get_bytes()[0]; + } + else + { + packet_assembly[25] = (packet_number<<2); + } + + std::array<uint8_t, 2*26+1> encoded = conv_encode(packet_assembly); + frame_t punctured; + auto size = puncture_bytes(encoded, punctured, mobilinkd::P3); + + if (size != 368) { + std::cerr << "mobilinkd::M17Modulator::make_packet_frame: incorrect size (not 368)" << size; + } + return punctured; } @@ -280,24 +348,6 @@ private: return encoded_call; } - template <typename T, size_t N> - static std::array<int8_t, N * 4> bytes_to_symbols(const std::array<T, N>& bytes) - { - std::array<int8_t, N * 4> result; - size_t index = 0; - - for (auto b : bytes) - { - for (size_t i = 0; i != 4; ++i) - { - result[index++] = bits_to_symbol(b >> 6); - b <<= 2; - } - } - - return result; - } - template <typename T, size_t N> static std::array<T, N * 2 + 1> conv_encode(std::array<T, N> data) { diff --git a/plugins/channeltx/modm17/CMakeLists.txt b/plugins/channeltx/modm17/CMakeLists.txt index bf11c0d73..82d0a789a 100644 --- a/plugins/channeltx/modm17/CMakeLists.txt +++ b/plugins/channeltx/modm17/CMakeLists.txt @@ -4,6 +4,7 @@ set(modm17_SOURCES m17mod.cpp m17modbaseband.cpp m17modsource.cpp + m17modprocessor.cpp m17modplugin.cpp m17modsettings.cpp m17modwebapiadapter.cpp @@ -13,6 +14,7 @@ set(modm17_HEADERS m17mod.h m17modbaseband.h m17modsource.h + m17modprocessor.h m17modplugin.h m17modsettings.h m17modwebapiadapter.h @@ -20,6 +22,8 @@ set(modm17_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${CODEC2_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/modems ) if(NOT SERVER_MODE) @@ -48,12 +52,18 @@ add_library(${TARGET_NAME} SHARED ${modm17_SOURCES} ) +if(CODEC2_EXTERNAL) + add_dependencies(${TARGET_NAME} codec2) +endif() + target_link_libraries(${TARGET_NAME} Qt5::Core ${TARGET_LIB} sdrbase ${TARGET_LIB_GUI} swagger + ${CODEC2_LIBRARIES} + modems ) install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/channeltx/modm17/m17mod.cpp b/plugins/channeltx/modm17/m17mod.cpp index c79ddd73f..47fc16675 100644 --- a/plugins/channeltx/modm17/m17mod.cpp +++ b/plugins/channeltx/modm17/m17mod.cpp @@ -294,7 +294,9 @@ void M17Mod::applySettings(const M17ModSettings& settings, bool force) << " m_toneFrequency: " << settings.m_toneFrequency << " m_channelMute: " << settings.m_channelMute << " m_playLoop: " << settings.m_playLoop - << " m_modAFInput " << settings.m_modAFInput + << " m_m17Mode " << settings.m_m17Mode + << " m_audioType " << settings.m_audioType + << " m_packetType " << settings.m_packetType << " m_audioDeviceName: " << settings.m_audioDeviceName << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress @@ -320,8 +322,14 @@ void M17Mod::applySettings(const M17ModSettings& settings, bool force) if ((settings.m_playLoop != m_settings.m_playLoop) || force) { reverseAPIKeys.append("playLoop"); } - if ((settings.m_modAFInput != m_settings.m_modAFInput) || force) { - reverseAPIKeys.append("modAFInput"); + if ((settings.m_audioType != m_settings.m_audioType) || force) { + reverseAPIKeys.append("audioType"); + } + if ((settings.m_packetType != m_settings.m_packetType) || force) { + reverseAPIKeys.append("packetType"); + } + if ((settings.m_m17Mode != m_settings.m_m17Mode) || force) { + reverseAPIKeys.append("m17Mode"); } if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) { reverseAPIKeys.append("rfBandwidth"); @@ -470,8 +478,14 @@ void M17Mod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("inputFrequencyOffset")) { settings.m_inputFrequencyOffset = response.getM17ModSettings()->getInputFrequencyOffset(); } - if (channelSettingsKeys.contains("modAFInput")) { - settings.m_modAFInput = (M17ModSettings::M17ModInputAF) response.getM17ModSettings()->getModAfInput(); + if (channelSettingsKeys.contains("m17Mode")) { + settings.m_m17Mode = (M17ModSettings::M17Mode) response.getM17ModSettings()->getM17Mode(); + } + if (channelSettingsKeys.contains("audioType")) { + settings.m_audioType = (M17ModSettings::AudioType) response.getM17ModSettings()->getAudioType(); + } + if (channelSettingsKeys.contains("packetType")) { + settings.m_packetType = (M17ModSettings::PacketType) response.getM17ModSettings()->getPacketType(); } if (channelSettingsKeys.contains("playLoop")) { settings.m_playLoop = response.getM17ModSettings()->getPlayLoop() != 0; @@ -533,7 +547,9 @@ void M17Mod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respon response.getM17ModSettings()->setChannelMute(settings.m_channelMute ? 1 : 0); response.getM17ModSettings()->setFmDeviation(settings.m_fmDeviation); response.getM17ModSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset); - response.getM17ModSettings()->setModAfInput((int) settings.m_modAFInput); + response.getM17ModSettings()->setM17Mode((int) settings.m_m17Mode); + response.getM17ModSettings()->setAudioType((int) settings.m_audioType); + response.getM17ModSettings()->setPacketType((int) settings.m_packetType); response.getM17ModSettings()->setPlayLoop(settings.m_playLoop ? 1 : 0); response.getM17ModSettings()->setRfBandwidth(settings.m_rfBandwidth); response.getM17ModSettings()->setRgbColor(settings.m_rgbColor); @@ -673,8 +689,14 @@ void M17Mod::webapiFormatChannelSettings( if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { swgM17ModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); } - if (channelSettingsKeys.contains("modAFInput") || force) { - swgM17ModSettings->setModAfInput((int) settings.m_modAFInput); + if (channelSettingsKeys.contains("m17Mode") || force) { + swgM17ModSettings->setM17Mode((int) settings.m_m17Mode); + } + if (channelSettingsKeys.contains("audioType") || force) { + swgM17ModSettings->setAudioType((int) settings.m_audioType); + } + if (channelSettingsKeys.contains("packetType") || force) { + swgM17ModSettings->setPacketType((int) settings.m_packetType); } if (channelSettingsKeys.contains("audioDeviceName") || force) { swgM17ModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); @@ -764,3 +786,8 @@ int M17Mod::getFeedbackAudioSampleRate() const { return m_basebandSource->getFeedbackAudioSampleRate(); } + +void M17Mod::sendPacket() +{ + m_basebandSource->sendPacket(); +} diff --git a/plugins/channeltx/modm17/m17mod.h b/plugins/channeltx/modm17/m17mod.h index 0f68030e3..a2924332b 100644 --- a/plugins/channeltx/modm17/m17mod.h +++ b/plugins/channeltx/modm17/m17mod.h @@ -233,6 +233,7 @@ public: uint32_t getNumberOfDeviceStreams() const; int getAudioSampleRate() const; int getFeedbackAudioSampleRate() const; + void sendPacket(); static const char* const m_channelIdURI; static const char* const m_channelId; diff --git a/plugins/channeltx/modm17/m17modbaseband.cpp b/plugins/channeltx/modm17/m17modbaseband.cpp index 685900f17..6962fc9ea 100644 --- a/plugins/channeltx/modm17/m17modbaseband.cpp +++ b/plugins/channeltx/modm17/m17modbaseband.cpp @@ -196,12 +196,12 @@ void M17ModBaseband::applySettings(const M17ModSettings& settings, bool force) } } - if ((settings.m_modAFInput != m_settings.m_modAFInput) || force) + if ((settings.m_audioType != m_settings.m_audioType) || force) { AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); int audioDeviceIndex = audioDeviceManager->getInputDeviceIndex(settings.m_audioDeviceName); - if (settings.m_modAFInput == M17ModSettings::M17ModInputAudio) { + if (settings.m_audioType == M17ModSettings::AudioInput) { audioDeviceManager->addAudioSource(getAudioFifo(), getInputMessageQueue(), audioDeviceIndex); } else { audioDeviceManager->removeAudioSource(getAudioFifo()); diff --git a/plugins/channeltx/modm17/m17modbaseband.h b/plugins/channeltx/modm17/m17modbaseband.h index 43724cf29..9e8f2d129 100644 --- a/plugins/channeltx/modm17/m17modbaseband.h +++ b/plugins/channeltx/modm17/m17modbaseband.h @@ -70,6 +70,7 @@ public: AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); } AudioFifo *getFeedbackAudioFifo() { return m_source.getFeedbackAudioFifo(); } void setChannel(ChannelAPI *channel); + void sendPacket() { m_source.sendPacket(); } signals: /** diff --git a/plugins/channeltx/modm17/m17modgui.cpp b/plugins/channeltx/modm17/m17modgui.cpp index 7c7dea247..cd0492cd1 100644 --- a/plugins/channeltx/modm17/m17modgui.cpp +++ b/plugins/channeltx/modm17/m17modgui.cpp @@ -182,6 +182,22 @@ void M17ModGUI::on_toneFrequency_valueChanged(int value) applySettings(); } +void M17ModGUI::on_fmAudio_toggled(bool checked) +{ + m_fmAudioMode = checked; + + if ((checked) && (m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeM17Audio)) + { + m_settings.m_m17Mode = M17ModSettings::M17Mode::M17ModeFMAudio; + applySettings(); + } + else if ((!checked) && (m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeFMAudio)) + { + m_settings.m_m17Mode = M17ModSettings::M17Mode::M17ModeM17Audio; + applySettings(); + } +} + void M17ModGUI::on_channelMute_toggled(bool checked) { m_settings.m_channelMute = checked; @@ -196,9 +212,13 @@ void M17ModGUI::on_playLoop_toggled(bool checked) void M17ModGUI::on_play_toggled(bool checked) { - ui->tone->setEnabled(!checked); // release other source inputs - ui->mic->setEnabled(!checked); - m_settings.m_modAFInput = checked ? M17ModSettings::M17ModInputFile : M17ModSettings::M17ModInputNone; + m_settings.m_audioType = checked ? M17ModSettings::AudioFile : M17ModSettings::AudioNone; + m_settings.m_m17Mode = checked ? + m_fmAudioMode ? + M17ModSettings::M17Mode::M17ModeFMAudio + : M17ModSettings::M17Mode::M17ModeM17Audio + : M17ModSettings::M17ModeNone; + displayModes(); applySettings(); ui->navTimeSlider->setEnabled(!checked); m_enableNavTime = !checked; @@ -206,17 +226,20 @@ void M17ModGUI::on_play_toggled(bool checked) void M17ModGUI::on_tone_toggled(bool checked) { - ui->play->setEnabled(!checked); // release other source inputs - ui->mic->setEnabled(!checked); - m_settings.m_modAFInput = checked ? M17ModSettings::M17ModInputTone : M17ModSettings::M17ModInputNone; + m_settings.m_m17Mode = checked ? M17ModSettings::M17ModeFMTone : M17ModSettings::M17ModeNone; + displayModes(); applySettings(); } void M17ModGUI::on_mic_toggled(bool checked) { - ui->play->setEnabled(!checked); // release other source inputs - ui->tone->setEnabled(!checked); // release other source inputs - m_settings.m_modAFInput = checked ? M17ModSettings::M17ModInputAudio : M17ModSettings::M17ModInputNone; + m_settings.m_audioType = checked ? M17ModSettings::AudioInput : M17ModSettings::AudioNone; + m_settings.m_m17Mode = checked ? + m_fmAudioMode ? + M17ModSettings::M17Mode::M17ModeFMAudio + : M17ModSettings::M17Mode::M17ModeM17Audio + : M17ModSettings::M17ModeNone; + displayModes(); applySettings(); } @@ -261,6 +284,66 @@ void M17ModGUI::on_showFileDialog_clicked(bool checked) } } +void M17ModGUI::on_packetMode_toggled(bool checked) +{ + m_settings.m_m17Mode = checked ? M17ModSettings::M17ModeM17Packet : M17ModSettings::M17ModeNone; + displayModes(); + applySettings(); +} + +void M17ModGUI::on_sendPacket_clicked(bool) +{ + m_m17Mod->sendPacket(); +} + +void M17ModGUI::on_loopPacket_toggled(bool checked) +{ + (void) checked; + // TODO +} + +void M17ModGUI::on_loopPacketInterval_valueChanged(int value) +{ + (void) value; + // TODO +} + +void M17ModGUI::on_packetDataWidget_currentChanged(int index) +{ + m_settings.m_packetType = indexToPacketType(index); + applySettings(); +} + +void M17ModGUI::on_source_editingFinished() +{ + m_settings.m_sourceCall = ui->source->text(); + applySettings(); +} + +void M17ModGUI::on_destination_editingFinished() +{ + m_settings.m_destCall = ui->destination->text(); + applySettings(); +} + +void M17ModGUI::on_insertPosition_toggled(bool checked) +{ + m_settings.m_insertPosition = checked; + applySettings(); +} + +void M17ModGUI::on_can_valueChanged(int value) +{ + m_settings.m_can = value; + applySettings(); +} + +void M17ModGUI::on_smsText_editingFinished() +{ + m_settings.m_smsText = ui->smsText->toPlainText(); + applySettings(); +} + void M17ModGUI::configureFileName() { qDebug() << "M17ModGUI::configureFileName: " << m_fileName.toStdString().c_str(); @@ -333,6 +416,7 @@ M17ModGUI::M17ModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_deviceCenterFrequency(0), m_basebandSampleRate(1), m_doApplySettings(true), + m_fmAudioMode(false), m_recordLength(0), m_recordSampleRate(48000), m_samplesCount(0), @@ -447,23 +531,101 @@ void M17ModGUI::displaySettings() ui->channelMute->setChecked(m_settings.m_channelMute); ui->playLoop->setChecked(m_settings.m_playLoop); - ui->tone->setEnabled((m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputTone) || (m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputNone)); - ui->mic->setEnabled((m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputAudio) || (m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputNone)); - ui->play->setEnabled((m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputFile) || (m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputNone)); - - ui->tone->setChecked(m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputTone); - ui->mic->setChecked(m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputAudio); - ui->play->setChecked(m_settings.m_modAFInput == M17ModSettings::M17ModInputAF::M17ModInputFile); + displayModes(); + ui->fmAudio->setChecked(m_fmAudioMode); + ui->packetDataWidget->setCurrentIndex(packetTypeToIndex(m_settings.m_packetType)); ui->feedbackEnable->setChecked(m_settings.m_feedbackAudioEnable); ui->feedbackVolume->setValue(roundf(m_settings.m_feedbackVolumeFactor * 100.0)); ui->feedbackVolumeText->setText(QString("%1").arg(m_settings.m_feedbackVolumeFactor, 0, 'f', 2)); + ui->source->setText(m_settings.m_sourceCall); + ui->destination->setText(m_settings.m_destCall); + ui->insertPosition->setChecked(m_settings.m_insertPosition); + ui->can->setValue(m_settings.m_can); + + ui->smsText->setText(m_settings.m_smsText); + + ui->aprsFromText->setText(m_settings.m_aprsCallsign); + ui->aprsData->setText(m_settings.m_aprsData); + ui->aprsTo->lineEdit()->setText(m_settings.m_aprsTo); + ui->aprsVia->lineEdit()->setText(m_settings.m_aprsVia); + getRollupContents()->restoreState(m_rollupState); updateAbsoluteCenterFrequency(); blockApplySettings(false); } +void M17ModGUI::displayModes() +{ + qDebug("M17ModGUI::displayModes: m_m17Mode: %d m_audioType: %d", + (int) m_settings.m_m17Mode, (int) m_settings.m_audioType); + + if (m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeM17Packet) + { + ui->packetMode->setChecked(true); + ui->packetMode->setEnabled(true); + ui->tone->setChecked(false); + ui->mic->setChecked(false); + ui->play->setChecked(false); + ui->tone->setEnabled(false); + ui->mic->setEnabled(false); + ui->play->setEnabled(false); + } + else if (m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeFMTone) + { + ui->tone->setChecked(true); + ui->tone->setEnabled(true); + ui->packetMode->setChecked(false); + ui->mic->setChecked(false); + ui->play->setChecked(false); + ui->packetMode->setEnabled(false); + ui->mic->setEnabled(false); + ui->play->setEnabled(false); + } + else if ((m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeFMAudio) || + (m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeM17Audio)) + { + ui->tone->setChecked(false); + ui->packetMode->setChecked(false); + ui->tone->setEnabled(false); + ui->packetMode->setEnabled(false); + + if (m_settings.m_audioType == M17ModSettings::AudioType::AudioInput) + { + ui->mic->setChecked(true); + ui->mic->setEnabled(true); + ui->play->setChecked(false); + ui->play->setEnabled(false); + } + else if (m_settings.m_audioType == M17ModSettings::AudioType::AudioFile) + { + ui->play->setChecked(true); + ui->play->setEnabled(true); + ui->mic->setChecked(false); + ui->mic->setEnabled(false); + } + else if (m_settings.m_audioType == M17ModSettings::AudioType::AudioNone) + { + ui->mic->setChecked(false); + ui->play->setChecked(false); + ui->mic->setEnabled(true); + ui->play->setEnabled(true); + } + } + else if (m_settings.m_m17Mode == M17ModSettings::M17Mode::M17ModeNone) + { + ui->packetMode->setChecked(false); + ui->tone->setChecked(false); + ui->mic->setChecked(false); + ui->play->setChecked(false); + ui->packetMode->setEnabled(true); + ui->tone->setEnabled(true); + ui->mic->setEnabled(true); + ui->play->setEnabled(true); + } +} + void M17ModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); @@ -534,7 +696,7 @@ void M17ModGUI::tick() m_feedbackAudioSampleRate = feedbackAudioSampleRate; } - if (((++m_tickCount & 0xf) == 0) && (m_settings.m_modAFInput == M17ModSettings::M17ModInputFile)) + if (((++m_tickCount & 0xf) == 0) && (m_settings.m_audioType == M17ModSettings::AudioFile)) { M17Mod::MsgConfigureFileSourceStreamTiming* message = M17Mod::MsgConfigureFileSourceStreamTiming::create(); m_m17Mod->getInputMessageQueue()->push(message); @@ -591,9 +753,41 @@ void M17ModGUI::makeUIConnections() QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &M17ModGUI::on_showFileDialog_clicked); QObject::connect(ui->feedbackEnable, &QToolButton::toggled, this, &M17ModGUI::on_feedbackEnable_toggled); QObject::connect(ui->feedbackVolume, &QDial::valueChanged, this, &M17ModGUI::on_feedbackVolume_valueChanged); + QObject::connect(ui->fmAudio, &ButtonSwitch::toggled, this, &M17ModGUI::on_fmAudio_toggled); + QObject::connect(ui->packetMode, &ButtonSwitch::toggled, this, &M17ModGUI::on_packetMode_toggled); + QObject::connect(ui->sendPacket, &QPushButton::clicked, this, &M17ModGUI::on_sendPacket_clicked); + QObject::connect(ui->loopPacket, &ButtonSwitch::toggled, this, &M17ModGUI::on_loopPacket_toggled); + QObject::connect(ui->loopPacketInterval, &QDial::valueChanged, this, &M17ModGUI::on_loopPacketInterval_valueChanged); + QObject::connect(ui->smsText, &CustomTextEdit::editingFinished, this, &M17ModGUI::on_smsText_editingFinished); } void M17ModGUI::updateAbsoluteCenterFrequency() { setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); } + +M17ModSettings::PacketType M17ModGUI::indexToPacketType(int index) +{ + switch(index) + { + case 0: + return M17ModSettings::PacketType::PacketSMS; + case 1: + return M17ModSettings::PacketType::PacketAPRS; + default: + return M17ModSettings::PacketType::PacketNone; + } +} + +int M17ModGUI::packetTypeToIndex(M17ModSettings::PacketType type) +{ + switch(type) + { + case M17ModSettings::PacketType::PacketSMS: + return 0; + case M17ModSettings::PacketType::PacketAPRS: + return 1; + default: + return -1; + } +} diff --git a/plugins/channeltx/modm17/m17modgui.h b/plugins/channeltx/modm17/m17modgui.h index a32b8a4bf..04b0e1cff 100644 --- a/plugins/channeltx/modm17/m17modgui.h +++ b/plugins/channeltx/modm17/m17modgui.h @@ -76,6 +76,7 @@ private: qint64 m_deviceCenterFrequency; int m_basebandSampleRate; bool m_doApplySettings; + bool m_fmAudioMode; M17Mod* m_m17Mod; MovingAverageUtil<double, double, 20> m_channelPowerDbAvg; @@ -88,7 +89,6 @@ private: int m_feedbackAudioSampleRate; std::size_t m_tickCount; bool m_enableNavTime; - M17ModSettings::M17ModInputAF m_modAFInput; MessageQueue m_inputMessageQueue; QRegExpValidator m_dcsCodeValidator; @@ -98,11 +98,14 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); + void displayModes(); void updateWithStreamData(); void updateWithStreamTime(); bool handleMessage(const Message& message); void makeUIConnections(); void updateAbsoluteCenterFrequency(); + M17ModSettings::PacketType indexToPacketType(int index); + int packetTypeToIndex(M17ModSettings::PacketType type); void leaveEvent(QEvent*); void enterEvent(QEvent*); @@ -115,6 +118,7 @@ private slots: void on_rfBW_valueChanged(int value); void on_fmDev_valueChanged(int value); void on_toneFrequency_valueChanged(int value); + void on_fmAudio_toggled(bool checked); void on_volume_valueChanged(int value); void on_channelMute_toggled(bool checked); void on_tone_toggled(bool checked); @@ -128,6 +132,17 @@ private slots: void on_feedbackEnable_toggled(bool checked); void on_feedbackVolume_valueChanged(int value); + void on_packetMode_toggled(bool checked); + void on_sendPacket_clicked(bool checked); + void on_loopPacket_toggled(bool checked); + void on_loopPacketInterval_valueChanged(int value); + void on_packetDataWidget_currentChanged(int index); + void on_source_editingFinished(); + void on_destination_editingFinished(); + void on_insertPosition_toggled(bool checked); + void on_can_valueChanged(int value); + void on_smsText_editingFinished(); + void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); diff --git a/plugins/channeltx/modm17/m17modgui.ui b/plugins/channeltx/modm17/m17modgui.ui index 9d9241ebd..e7a3adeaa 100644 --- a/plugins/channeltx/modm17/m17modgui.ui +++ b/plugins/channeltx/modm17/m17modgui.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>360</width> - <height>278</height> + <height>568</height> </rect> </property> <property name="sizePolicy"> @@ -40,13 +40,13 @@ <property name="windowTitle"> <string>M17 Modulator</string> </property> - <widget class="QWidget" name="settingsContainer" native="true"> + <widget class="QWidget" name="aSettingsContainer" native="true"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>358</width> - <height>271</height> + <height>105</height> </rect> </property> <property name="minimumSize"> @@ -286,13 +286,6 @@ </item> </layout> </item> - <item> - <widget class="Line" name="line_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> <item> <layout class="QHBoxLayout" name="volumeLayout"> <item> @@ -364,12 +357,42 @@ </item> </layout> </item> + </layout> + </widget> + <widget class="QWidget" name="bAudioContainer" native="true"> + <property name="geometry"> + <rect> + <x>0</x> + <y>107</y> + <width>361</width> + <height>140</height> + </rect> + </property> + <property name="windowTitle"> + <string>Audio</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>2</number> + </property> + <property name="topMargin"> + <number>2</number> + </property> + <property name="rightMargin"> + <number>2</number> + </property> + <property name="bottomMargin"> + <number>2</number> + </property> <item> <layout class="QHBoxLayout" name="recordFileSelectLayout"> <item> <widget class="ButtonSwitch" name="tone"> <property name="toolTip"> - <string>FM tone modulation</string> + <string>Analog FM tone modulation</string> </property> <property name="text"> <string>...</string> @@ -424,6 +447,22 @@ </property> </widget> </item> + <item> + <widget class="ButtonSwitch" name="fmAudio"> + <property name="maximumSize"> + <size> + <width>35</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string>Modulate audio as analog FM (for testing)</string> + </property> + <property name="text"> + <string>FM</string> + </property> + </widget> + </item> <item> <widget class="ButtonSwitch" name="mic"> <property name="toolTip"> @@ -532,13 +571,6 @@ </item> </layout> </item> - <item> - <widget class="Line" name="line_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> <item> <layout class="QHBoxLayout" name="fileNameLayout"> <item> @@ -704,6 +736,606 @@ </item> </layout> </widget> + <widget class="QWidget" name="cPacketContainer" native="true"> + <property name="geometry"> + <rect> + <x>0</x> + <y>247</y> + <width>358</width> + <height>193</height> + </rect> + </property> + <property name="windowTitle"> + <string>Packet</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>2</number> + </property> + <property name="topMargin"> + <number>2</number> + </property> + <property name="rightMargin"> + <number>2</number> + </property> + <property name="bottomMargin"> + <number>2</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="ButtonSwitch" name="packetMode"> + <property name="toolTip"> + <string>Packet mode</string> + </property> + <property name="text"> + <string>PKT</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="sendPacket"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Send packet</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../../../sdrgui/resources/res.qrc"> + <normaloff>:/stream.png</normaloff>:/stream.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="ButtonSwitch" name="loopPacket"> + <property name="toolTip"> + <string>Send packets in a loop</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../../../sdrgui/resources/res.qrc"> + <normaloff>:/playloop.png</normaloff>:/playloop.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="QDial" name="loopPacketInterval"> + <property name="maximumSize"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + <property name="toolTip"> + <string>Interval between packets (s)</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>600</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="value"> + <number>60</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="loopPacketIntervalText"> + <property name="toolTip"> + <string>Interval between packets (s)</string> + </property> + <property name="text"> + <string>600</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QTabWidget" name="packetDataWidget"> + <property name="toolTip"> + <string>Packet data</string> + </property> + <property name="tabPosition"> + <enum>QTabWidget::East</enum> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="pktSMS"> + <property name="toolTip"> + <string>SMS data</string> + </property> + <attribute name="icon"> + <iconset resource="../../../sdrgui/resources/res.qrc"> + <normaloff>:/sms.png</normaloff>:/sms.png</iconset> + </attribute> + <attribute name="title"> + <string/> + </attribute> + <attribute name="toolTip"> + <string>SMS</string> + </attribute> + <widget class="CustomTextEdit" name="smsText"> + <property name="geometry"> + <rect> + <x>0</x> + <y>10</y> + <width>307</width> + <height>120</height> + </rect> + </property> + <property name="toolTip"> + <string>SMS text</string> + </property> + </widget> + </widget> + <widget class="QWidget" name="pktAPRS"> + <property name="toolTip"> + <string>APRS data</string> + </property> + <attribute name="icon"> + <iconset resource="../../../sdrgui/resources/res.qrc"> + <normaloff>:/world.png</normaloff>:/world.png</iconset> + </attribute> + <attribute name="title"> + <string/> + </attribute> + <attribute name="toolTip"> + <string>APRS</string> + </attribute> + <widget class="QWidget" name="horizontalLayoutWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>40</y> + <width>301</width> + <height>34</height> + </rect> + </property> + <layout class="QHBoxLayout" name="toLayout"> + <item> + <widget class="QLabel" name="aprsToLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>To</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="aprsTo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Enter destination</string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <property name="currentText"> + <string>APRS</string> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <item> + <property name="text"> + <string>APRS</string> + </property> + </item> + <item> + <property name="text"> + <string>APZ</string> + </property> + </item> + <item> + <property name="text"> + <string>CQ</string> + </property> + </item> + <item> + <property name="text"> + <string>BEACON</string> + </property> + </item> + <item> + <property name="text"> + <string>CALLSIGN-SSID</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QLabel" name="aprsViaLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Via</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="aprsVia"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Enter routing</string> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <item> + <property name="text"> + <string>WIDE2-2</string> + </property> + </item> + <item> + <property name="text"> + <string>ARISS</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="horizontalLayoutWidget_2"> + <property name="geometry"> + <rect> + <x>0</x> + <y>80</y> + <width>301</width> + <height>34</height> + </rect> + </property> + <layout class="QHBoxLayout" name="aprsDataLayout"> + <item> + <widget class="QLabel" name="aprsDataLabel"> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="text"> + <string>Data</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="aprsData"> + <property name="toolTip"> + <string>Enter data to transmit. + </string> + </property> + <property name="text"> + <string>>Using SDRangel</string> + </property> + <property name="maxLength"> + <number>256</number> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="horizontalLayoutWidget_3"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>301</width> + <height>34</height> + </rect> + </property> + <layout class="QHBoxLayout" name="fromLayout"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>From</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="aprsFromText"> + <property name="toolTip"> + <string>Enter your amateur radio callsign and optionally a SSID. E.g. M7RCE or M7RCE-1</string> + </property> + <property name="text"> + <string>MYCALL</string> + </property> + <property name="maxLength"> + <number>10</number> + </property> + </widget> + </item> + <item> + <widget class="ButtonSwitch" name="aprsInsertPosition"> + <property name="toolTip"> + <string>Insert position (latitude and longitude)</string> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="icon"> + <iconset> + <normalon>:/gps.png</normalon> + </iconset> + </property> + </widget> + </item> + <item> + <spacer name="aprsFromLabel"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="dDigitalContainer" native="true"> + <property name="geometry"> + <rect> + <x>0</x> + <y>442</y> + <width>358</width> + <height>120</height> + </rect> + </property> + <property name="windowTitle"> + <string>Digital</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4" stretch="0"> + <property name="spacing"> + <number>3</number> + </property> + <property name="leftMargin"> + <number>2</number> + </property> + <property name="topMargin"> + <number>2</number> + </property> + <property name="rightMargin"> + <number>2</number> + </property> + <property name="bottomMargin"> + <number>2</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="TVScreen" name="screenTV" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>100</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <widget class="QComboBox" name="baudRate"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>60</width> + <height>24</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>35</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string>Baud rate: 2.4k: NXDN48, dPMR 4.8k: DMR, D-Star, YSF, NXDN96</string> + </property> + <item> + <property name="text"> + <string>4.8k</string> + </property> + </item> + </widget> + <widget class="QLabel" name="sourceLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>40</y> + <width>21</width> + <height>28</height> + </rect> + </property> + <property name="text"> + <string>Src</string> + </property> + </widget> + <widget class="QLineEdit" name="source"> + <property name="geometry"> + <rect> + <x>40</x> + <y>40</y> + <width>100</width> + <height>24</height> + </rect> + </property> + </widget> + <widget class="QLabel" name="destinationLabel"> + <property name="geometry"> + <rect> + <x>10</x> + <y>70</y> + <width>21</width> + <height>28</height> + </rect> + </property> + <property name="text"> + <string>Dst</string> + </property> + </widget> + <widget class="QLineEdit" name="destination"> + <property name="geometry"> + <rect> + <x>40</x> + <y>70</y> + <width>100</width> + <height>24</height> + </rect> + </property> + </widget> + <widget class="ButtonSwitch" name="insertPosition"> + <property name="geometry"> + <rect> + <x>150</x> + <y>40</y> + <width>24</width> + <height>24</height> + </rect> + </property> + <property name="toolTip"> + <string>Insert position (latitude and longitude)</string> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="icon"> + <iconset> + <normalon>:/gps.png</normalon> + </iconset> + </property> + </widget> + <widget class="QLabel" name="destinationLabel_2"> + <property name="geometry"> + <rect> + <x>150</x> + <y>70</y> + <width>30</width> + <height>28</height> + </rect> + </property> + <property name="text"> + <string>CAN</string> + </property> + </widget> + <widget class="QSpinBox" name="can"> + <property name="geometry"> + <rect> + <x>180</x> + <y>70</y> + <width>56</width> + <height>28</height> + </rect> + </property> + <property name="maximum"> + <number>255</number> + </property> + <property name="value"> + <number>10</number> + </property> + </widget> + </widget> + </item> + </layout> + </item> + </layout> + </widget> </widget> <customwidgets> <customwidget> @@ -723,12 +1355,23 @@ <extends>QToolButton</extends> <header>gui/buttonswitch.h</header> </customwidget> + <customwidget> + <class>TVScreen</class> + <extends>QWidget</extends> + <header>gui/tvscreen.h</header> + <container>1</container> + </customwidget> <customwidget> <class>LevelMeterVU</class> <extends>QWidget</extends> <header>gui/levelmeter.h</header> <container>1</container> </customwidget> + <customwidget> + <class>CustomTextEdit</class> + <extends>QTextEdit</extends> + <header>gui/customtextedit.h</header> + </customwidget> </customwidgets> <resources> <include location="../../../sdrgui/resources/res.qrc"/> diff --git a/plugins/channeltx/modm17/m17modprocessor.cpp b/plugins/channeltx/modm17/m17modprocessor.cpp new file mode 100644 index 000000000..5933106a9 --- /dev/null +++ b/plugins/channeltx/modm17/m17modprocessor.cpp @@ -0,0 +1,99 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// 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 <http://www.gnu.org/licenses/>. // +/////////////////////////////////////////////////////////////////////////////////// + +#include "m17/M17Modulator.h" + +#include "m17modprocessor.h" + +M17ModProcessor::M17ModProcessor() +{ + m_basebandFifo.setSampleSize(sizeof(int16_t), 48000); + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); +} + +M17ModProcessor::~M17ModProcessor() +{} + +bool M17ModProcessor::handleMessage(const Message& cmd) +{ + if (MsgSendSMS::match(cmd)) + { + const MsgSendSMS& notif = (const MsgSendSMS&) cmd; + QByteArray packetBytes = notif.getSMSText().toUtf8(); + packetBytes.prepend(0x05); // SMS standard type + packetBytes.truncate(798); // Maximum packet size is 798 payload + 2 bytes CRC = 800 bytes (32*25) + processPacket(notif.getSourceCall(), notif.getDestCall(), packetBytes); + return true; + } + + return false; +} + + +void M17ModProcessor::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +void M17ModProcessor::processPacket(const QString& sourceCall, const QString& destCall, const QByteArray& packetBytes) +{ + mobilinkd::M17Modulator modulator(sourceCall.toStdString(), destCall.toStdString()); + // preamble + std::array<uint8_t, 48> preamble_bytes; + mobilinkd::M17Modulator::make_preamble(preamble_bytes); + std::array<int8_t, 48 * 4> fullframe_symbols = mobilinkd::M17Modulator::bytes_to_symbols(preamble_bytes); + std::array<int16_t, 1920> baseband = mobilinkd::M17Modulator::symbols_to_baseband(fullframe_symbols); + m_basebandFifo.write((const quint8*) baseband.data(), 1920); + // LSF + mobilinkd::M17Modulator::lich_t lichSegments; // Not used for packet + mobilinkd::M17Modulator::frame_t frame; + modulator.make_link_setup(lichSegments, frame); + std::array<int8_t, 46 * 4> frame_symbols = mobilinkd::M17Modulator::bytes_to_symbols(frame); + std::copy(mobilinkd::M17Modulator::LSF_SYNC_WORD.begin(), mobilinkd::M17Modulator::LSF_SYNC_WORD.end(), fullframe_symbols.begin()); + std::copy(frame_symbols.begin(), frame_symbols.end(), fullframe_symbols.begin()+2); + baseband = mobilinkd::M17Modulator::symbols_to_baseband(fullframe_symbols); + m_basebandFifo.write((const quint8*) baseband.data(), 1920); + // Packets + std::copy(mobilinkd::M17Modulator::DATA_SYNC_WORD.begin(), mobilinkd::M17Modulator::DATA_SYNC_WORD.end(), fullframe_symbols.begin()); + mobilinkd::M17Modulator::packet_t packet; + int remainderCount = packetBytes.size(); + int packetCount = 0; + + while (remainderCount > 25) + { + std::copy(packetBytes.begin() + (packetCount*25), packetBytes.begin() + ((packetCount+1)*25), packet.begin()); + frame = modulator.make_packet_frame(packetCount, false, packet, 25); + std::copy(frame_symbols.begin(), frame_symbols.end(), fullframe_symbols.begin()+2); + baseband = mobilinkd::M17Modulator::symbols_to_baseband(fullframe_symbols); + m_basebandFifo.write((const quint8*) baseband.data(), 1920); + remainderCount -= 25; + packetCount++; + } + + std::copy(packetBytes.begin() + (packetCount*25), packetBytes.begin() + (packetCount*25) + remainderCount, packet.begin()); + frame = modulator.make_packet_frame(packetCount, true, packet, remainderCount); + std::copy(frame_symbols.begin(), frame_symbols.end(), fullframe_symbols.begin()+2); + baseband = mobilinkd::M17Modulator::symbols_to_baseband(fullframe_symbols); + m_basebandFifo.write((const quint8*) baseband.data(), 1920); +} diff --git a/plugins/channeltx/modm17/m17modprocessor.h b/plugins/channeltx/modm17/m17modprocessor.h index 891fc0390..8a2ba7f32 100644 --- a/plugins/channeltx/modm17/m17modprocessor.h +++ b/plugins/channeltx/modm17/m17modprocessor.h @@ -29,22 +29,28 @@ class M17ModProcessor : public QObject { Q_OBJECT public: - class MsgSendPacket : public Message { + class MsgSendSMS : public Message { MESSAGE_CLASS_DECLARATION public: - const QByteArray& getPacket() const { return m_packet; } + const QString& getSourceCall() const { return m_sourceCall; } + const QString& getDestCall() const { return m_destCall; } + const QString& getSMSText() const { return m_smsText; } - static MsgSendPacket* create(const QByteArray& packet) { - return new MsgSendPacket(packet); + static MsgSendSMS* create(const QString& sourceCall, const QString& destCall, const QString& smsText) { + return new MsgSendSMS(sourceCall, destCall, smsText); } private: - QByteArray m_packet; + QString m_sourceCall; + QString m_destCall; + QString m_smsText; - MsgSendPacket(const QByteArray& bytes) : + MsgSendSMS(const QString& sourceCall, const QString& destCall, const QString& smsText) : Message(), - m_packet(bytes) + m_sourceCall(sourceCall), + m_destCall(destCall), + m_smsText(smsText) { } }; @@ -59,6 +65,7 @@ private: AudioFifo m_basebandFifo; //!< Samples are 16 bit integer baseband 48 kS/s samples bool handleMessage(const Message& cmd); + void processPacket(const QString& sourceCall, const QString& destCall, const QByteArray& packetBytes); private slots: void handleInputMessages(); diff --git a/plugins/channeltx/modm17/m17modsettings.cpp b/plugins/channeltx/modm17/m17modsettings.cpp index 2eea4748d..b5062e2e2 100644 --- a/plugins/channeltx/modm17/m17modsettings.cpp +++ b/plugins/channeltx/modm17/m17modsettings.cpp @@ -42,7 +42,9 @@ void M17ModSettings::resetToDefaults() m_playLoop = false; m_rgbColor = QColor(255, 0, 255).rgb(); m_title = "M17 Modulator"; - m_modAFInput = M17ModInputAF::M17ModInputNone; + m_m17Mode = M17Mode::M17ModeNone; + m_audioType = AudioType::AudioNone; + m_packetType = PacketType::PacketNone; m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; m_feedbackAudioDeviceName = AudioDeviceManager::m_defaultDeviceName; m_feedbackVolumeFactor = 0.5f; @@ -55,6 +57,16 @@ void M17ModSettings::resetToDefaults() m_reverseAPIChannelIndex = 0; m_workspaceIndex = 0; m_hidden = false; + m_sourceCall = ""; + m_destCall = ""; + m_insertPosition = false; + m_can = 10; + m_smsText = ""; + m_aprsCallsign = "MYCALL"; + m_aprsTo = "APRS"; + m_aprsVia = "WIDE2-2"; + m_aprsData = ">Using SDRangel"; + m_aprsInsertPosition = 0; } QByteArray M17ModSettings::serialize() const @@ -67,13 +79,15 @@ QByteArray M17ModSettings::serialize() const s.writeU32(5, m_rgbColor); s.writeReal(6, m_toneFrequency); s.writeReal(7, m_volumeFactor); + s.writeS32(8, (int) m_m17Mode); + s.writeS32(9, (int) m_audioType); + s.writeS32(10, (int) m_packetType); if (m_channelMarker) { s.writeBlob(11, m_channelMarker->serialize()); } s.writeString(12, m_title); - s.writeS32(13, (int) m_modAFInput); s.writeString(14, m_audioDeviceName); s.writeBool(15, m_useReverseAPI); s.writeString(16, m_reverseAPIAddress); @@ -93,6 +107,19 @@ QByteArray M17ModSettings::serialize() const s.writeBlob(29, m_geometryBytes); s.writeBool(30, m_hidden); + s.writeString(40, m_sourceCall); + s.writeString(41, m_destCall); + s.writeBool(42, m_insertPosition); + s.writeU32(43, m_can); + + s.writeString(50, m_smsText); + + s.writeString(60, m_aprsCallsign); + s.writeString(61, m_aprsTo); + s.writeString(62, m_aprsVia); + s.writeString(63, m_aprsData); + s.writeBool(64, m_aprsInsertPosition); + return s.final(); } @@ -119,7 +146,13 @@ bool M17ModSettings::deserialize(const QByteArray& data) d.readU32(5, &m_rgbColor); d.readReal(6, &m_toneFrequency, 1000.0); d.readReal(7, &m_volumeFactor, 1.0); - d.readBlob(8, &bytetmp); + d.readS32(8, &tmp, 0); + m_m17Mode = tmp < 0 ? M17ModeNone : tmp > (int) M17ModeM17BERT ? M17ModeM17BERT : (M17Mode) tmp; + d.readS32(9, &tmp, 0); + m_audioType = tmp < 0 ? AudioNone : tmp > (int) AudioInput ? AudioInput : (AudioType) tmp; + m_packetType = tmp < 0 ? PacketNone : tmp > (int) PacketSMS ? PacketSMS : (PacketType) tmp; + + d.readBlob(11, &bytetmp); if (m_channelMarker) { @@ -129,13 +162,6 @@ bool M17ModSettings::deserialize(const QByteArray& data) d.readString(12, &m_title, "M17 Modulator"); - d.readS32(13, &tmp, 0); - if ((tmp < 0) || (tmp > (int) M17ModInputAF::M17ModInputTone)) { - m_modAFInput = M17ModInputNone; - } else { - m_modAFInput = (M17ModInputAF) tmp; - } - d.readString(14, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName); d.readBool(15, &m_useReverseAPI, false); d.readString(16, &m_reverseAPIAddress, "127.0.0.1"); @@ -167,6 +193,20 @@ bool M17ModSettings::deserialize(const QByteArray& data) d.readBlob(29, &m_geometryBytes); d.readBool(30, &m_hidden, false); + d.readString(40, &m_sourceCall, ""); + d.readString(41, &m_destCall, ""); + d.readBool(42, &m_insertPosition, false); + d.readU32(43, &utmp); + m_can = utmp < 255 ? utmp : 255; + + d.readString(50, &m_smsText, ""); + + d.readString(60, &m_aprsCallsign, "MYCALL"); + d.readString(61, &m_aprsTo, ""); + d.readString(62, &m_aprsVia, ""); + d.readString(63, &m_aprsData, ""); + d.readBool(64, &m_aprsInsertPosition, false); + return true; } else diff --git a/plugins/channeltx/modm17/m17modsettings.h b/plugins/channeltx/modm17/m17modsettings.h index d0509620e..bb0ede7d2 100644 --- a/plugins/channeltx/modm17/m17modsettings.h +++ b/plugins/channeltx/modm17/m17modsettings.h @@ -26,12 +26,28 @@ class Serializable; struct M17ModSettings { - enum M17ModInputAF + enum M17Mode { - M17ModInputNone, - M17ModInputFile, - M17ModInputAudio, - M17ModInputTone + M17ModeNone, + M17ModeFMTone, + M17ModeFMAudio, + M17ModeM17Audio, + M17ModeM17Packet, + M17ModeM17BERT + }; + + enum AudioType + { + AudioNone, + AudioFile, + AudioInput + }; + + enum PacketType + { + PacketNone, + PacketSMS, + PacketAPRS }; qint64 m_inputFrequencyOffset; @@ -43,7 +59,9 @@ struct M17ModSettings bool m_playLoop; quint32 m_rgbColor; QString m_title; - M17ModInputAF m_modAFInput; + M17Mode m_m17Mode; + AudioType m_audioType; + PacketType m_packetType; QString m_audioDeviceName; //!< This is the audio device you get the audio samples from QString m_feedbackAudioDeviceName; //!< This is the audio device you send the audio samples to for audio feedback float m_feedbackVolumeFactor; @@ -58,6 +76,19 @@ struct M17ModSettings QByteArray m_geometryBytes; bool m_hidden; + QString m_sourceCall; + QString m_destCall; + bool m_insertPosition; + uint8_t m_can; + + QString m_smsText; + + QString m_aprsCallsign; + QString m_aprsTo; + QString m_aprsVia; + QString m_aprsData; + bool m_aprsInsertPosition; + Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channeltx/modm17/m17modsource.cpp b/plugins/channeltx/modm17/m17modsource.cpp index b124fe143..a52ad489c 100644 --- a/plugins/channeltx/modm17/m17modsource.cpp +++ b/plugins/channeltx/modm17/m17modsource.cpp @@ -21,6 +21,7 @@ #include "util/messagequeue.h" #include "maincore.h" +#include "m17modprocessor.h" #include "m17modsource.h" const int M17ModSource::m_levelNbSamples = 480; // every 10ms @@ -53,12 +54,15 @@ M17ModSource::M17ModSource() : m_magsq = 0.0; + m_processor = new M17ModProcessor(); + applySettings(m_settings, true); applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); } M17ModSource::~M17ModSource() { + delete m_processor; } void M17ModSource::pull(SampleVector::iterator begin, unsigned int nbSamples) @@ -140,25 +144,40 @@ void M17ModSource::pullAudio(unsigned int nbSamplesAudio) void M17ModSource::modulateSample() { Real t1, t; + bool carrier; - pullAF(t); + if ((m_settings.m_m17Mode == M17ModSettings::M17ModeFMTone) || (m_settings.m_m17Mode == M17ModSettings::M17ModeFMAudio)) { + pullAF(t, carrier); + } else if (m_settings.m_m17Mode != M17ModSettings::M17ModeNone) { + pullM17(t, carrier); + } else { + t = 0; + } if (m_settings.m_feedbackAudioEnable) { pushFeedback(t * m_settings.m_feedbackVolumeFactor * 16384.0f); } - calculateLevel(t); - t1 = m_lowpass.filter(t) * 1.2f; + if (carrier) + { + calculateLevel(t); + t1 = m_lowpass.filter(t) * 1.2f; - m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * t1; + m_modPhasor += (m_settings.m_fmDeviation / (float) m_audioSampleRate) * t1; - // limit phasor range to ]-pi,pi] - if (m_modPhasor > M_PI) { - m_modPhasor -= (2.0f * M_PI); + // limit phasor range to ]-pi,pi] + if (m_modPhasor > M_PI) { + m_modPhasor -= (2.0f * M_PI); + } + + m_modSample.real(cos(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF); // -1 dB + m_modSample.imag(sin(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF); + } + else + { + m_modSample.real(0.0f); + m_modSample.imag(0.0f); } - - m_modSample.real(cos(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF); // -1 dB - m_modSample.imag(sin(m_modPhasor) * 0.891235351562f * SDR_TX_SCALEF); m_demodBuffer[m_demodBufferFill] = t1 * std::numeric_limits<int16_t>::max(); ++m_demodBufferFill; @@ -186,63 +205,74 @@ void M17ModSource::modulateSample() } } -void M17ModSource::pullAF(Real& sample) +void M17ModSource::pullAF(Real& sample, bool& carrier) { - switch (m_settings.m_modAFInput) - { - case M17ModSettings::M17ModInputTone: - sample = m_toneNco.next(); - break; - case M17ModSettings::M17ModInputFile: - // sox f4exb_call.wav --encoding float --endian little f4exb_call.raw - // ffplay -f f32le -ar 48k -ac 1 f4exb_call.raw - if (m_ifstream && m_ifstream->is_open()) - { - if (m_ifstream->eof()) - { - if (m_settings.m_playLoop) - { - m_ifstream->clear(); - m_ifstream->seekg(0, std::ios::beg); - } - } + carrier = true; - if (m_ifstream->eof()) + if (m_settings.m_m17Mode == M17ModSettings::M17ModeFMTone) + { + sample = m_toneNco.next(); + } + else if (m_settings.m_m17Mode == M17ModSettings::M17ModeFMAudio) + { + if (m_settings.m_audioType == M17ModSettings::AudioFile) + { + // sox f4exb_call.wav --encoding float --endian little f4exb_call.raw + // ffplay -f f32le -ar 48k -ac 1 f4exb_call.raw + if (m_ifstream && m_ifstream->is_open()) { - sample = 0.0f; + if (m_ifstream->eof()) + { + if (m_settings.m_playLoop) + { + m_ifstream->clear(); + m_ifstream->seekg(0, std::ios::beg); + } + } + + if (m_ifstream->eof()) + { + sample = 0.0f; + } + else + { + m_ifstream->read(reinterpret_cast<char*>(&sample), sizeof(Real)); + sample *= m_settings.m_volumeFactor; + } } else { - m_ifstream->read(reinterpret_cast<char*>(&sample), sizeof(Real)); - sample *= m_settings.m_volumeFactor; + sample = 0.0f; + } + } + else if (m_settings.m_audioType == M17ModSettings::AudioInput) + { + if (m_audioBufferFill < m_audioBuffer.size()) + { + sample = ((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f) * m_settings.m_volumeFactor; + m_audioBufferFill++; + } + else + { + unsigned int size = m_audioBuffer.size(); + qDebug("NFMModSource::pullAF: starve audio samples: size: %u", size); + sample = ((m_audioBuffer[size-1].l + m_audioBuffer[size-1].r) / 65536.0f) * m_settings.m_volumeFactor; } } else { sample = 0.0f; } - break; - case M17ModSettings::M17ModInputAudio: - if (m_audioBufferFill < m_audioBuffer.size()) - { - sample = ((m_audioBuffer[m_audioBufferFill].l + m_audioBuffer[m_audioBufferFill].r) / 65536.0f) * m_settings.m_volumeFactor; - m_audioBufferFill++; - } - else - { - unsigned int size = m_audioBuffer.size(); - qDebug("NFMModSource::pullAF: starve audio samples: size: %u", size); - sample = ((m_audioBuffer[size-1].l + m_audioBuffer[size-1].r) / 65536.0f) * m_settings.m_volumeFactor; - } - - break; - case M17ModSettings::M17ModInputNone: - default: - sample = 0.0f; - break; } } +void M17ModSource::pullM17(Real& sample, bool& carrier) +{ + // TODO + carrier = false; + sample = 0.0f; +} + void M17ModSource::pushFeedback(Real sample) { Complex c(sample, sample); @@ -368,9 +398,9 @@ void M17ModSource::applySettings(const M17ModSettings& settings, bool force) m_toneNco.setFreq(settings.m_toneFrequency, m_audioSampleRate); } - if ((settings.m_modAFInput != m_settings.m_modAFInput) || force) + if ((settings.m_audioType != m_settings.m_audioType) || force) { - if (settings.m_modAFInput == M17ModSettings::M17ModInputAudio) { + if (settings.m_audioType == M17ModSettings::AudioInput) { connect(&m_audioFifo, SIGNAL(dataReady()), this, SLOT(handleAudio())); } else { disconnect(&m_audioFifo, SIGNAL(dataReady()), this, SLOT(handleAudio())); @@ -416,3 +446,16 @@ void M17ModSource::handleAudio() } } } + +void M17ModSource::sendPacket() +{ + if (m_settings.m_packetType == M17ModSettings::PacketType::PacketSMS) + { + M17ModProcessor::MsgSendSMS *msg = M17ModProcessor::MsgSendSMS::create( + m_settings.m_sourceCall, + m_settings.m_destCall, + m_settings.m_smsText + ); + m_processor->getInputMessageQueue()->push(msg); + } +} diff --git a/plugins/channeltx/modm17/m17modsource.h b/plugins/channeltx/modm17/m17modsource.h index 6b852b4b1..6890edc5b 100644 --- a/plugins/channeltx/modm17/m17modsource.h +++ b/plugins/channeltx/modm17/m17modsource.h @@ -37,6 +37,7 @@ #include "m17modsettings.h" class ChannelAPI; +class M17ModProcessor; class M17ModSource : public QObject, public ChannelSampleSource { @@ -67,6 +68,8 @@ public: void applySettings(const M17ModSettings& settings, bool force = false); void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false); + void sendPacket(); + private: int m_channelSampleRate; int m_channelFrequencyOffset; @@ -115,6 +118,7 @@ private: Real m_levelSum; std::ifstream *m_ifstream; + M17ModProcessor *m_processor; QMutex m_mutex; @@ -122,7 +126,8 @@ private: static const float m_preemphasis; void processOneSample(Complex& ci); - void pullAF(Real& sample); + void pullAF(Real& sample, bool& carrier); + void pullM17(Real& sample, bool& carrier); void pullAudio(unsigned int nbSamples); void pushFeedback(Real sample); void calculateLevel(Real& sample); diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index c77a093ed..0099b9d15 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -8390,8 +8390,17 @@ margin-bottom: 20px; "audioDeviceName" : { "type" : "string" }, - "modAFInput" : { - "type" : "integer" + "m17Mode" : { + "type" : "integer", + "description" : "M17Mode" + }, + "audioType" : { + "type" : "integer", + "description" : "AudioType" + }, + "packetType" : { + "type" : "integer", + "description" : "PacketType" }, "streamIndex" : { "type" : "integer", @@ -56380,7 +56389,7 @@ except ApiException as e: </div> <div id="generator"> <div class="content"> - Generated 2022-06-09T22:25:54.513+02:00 + Generated 2022-06-10T22:26:56.056+02:00 </div> </div> </div> diff --git a/sdrbase/resources/webapi/doc/swagger/include/M17Mod.yaml b/sdrbase/resources/webapi/doc/swagger/include/M17Mod.yaml index 5cb05b2ce..8a87ee14a 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/M17Mod.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/M17Mod.yaml @@ -26,8 +26,15 @@ M17ModSettings: type: string audioDeviceName: type: string - modAFInput: + m17Mode: type: integer + description: M17Mode + audioType: + type: integer + description: AudioType + packetType: + type: integer + description: PacketType streamIndex: description: MIMO channel. Not relevant when connected to SI (single Rx). type: integer diff --git a/sdrgui/resources/res.qrc b/sdrgui/resources/res.qrc index c62dcd600..90fe1ae90 100644 --- a/sdrgui/resources/res.qrc +++ b/sdrgui/resources/res.qrc @@ -8,6 +8,8 @@ <file>bell_fill.png</file> <file>bell_gradient.png</file> <file>bell_line.png</file> + <file>world.png</file> + <file>sms.png</file> <file>ruler.png</file> <file>sort.png</file> <file>audio_mic.png</file> diff --git a/sdrgui/resources/sms.png b/sdrgui/resources/sms.png new file mode 100644 index 0000000000000000000000000000000000000000..0f9312a9a501d84171fb0c65d0a7d3a86839bae4 GIT binary patch literal 821 zcmV-51Iqk~P)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv0004mX+uL$Nkc;* zaB^>EX>4Tx04R}tkv&MmKpe$iQ?;TM2Rn#3WT;LS#ELj-6^c+H)C#RSm|XfHG-*gu zTpR`0f`cE6RR<SmT^(EnLGS~_(aA~CMN0f%QfLw5!Ery{-Fw`<1B7~+X;#NLpy{@m zPA0@`Zbb~eq6@tUB96GsEMr!ZQt%yL_XzOyF2=L`&;2?2)V#%jfJi*U4AUlFC!X50 z4bJ<-5mu5_;&b9LlP*a7$aTfzH_k<u1)do(GwC_v2(egfW2KE*$<&A^iKD8fQ@)V( zSmnIMSu0mr^Pc>L;k>@Q#C4j(NMZqtkRU=q6&onSMvPXS6botEPx$zUT)#vvg<Kn8 z<d{bV8f4cG{s+IiwF>bGFDaY=I$s>;V+0880*#vEd>=bb;{*sk16O*>U#SDrpQP7X zTJ#9$-v%zOTbi;5T<!paPljyDt`wvx6bium8GTa@7`O#`R=wVu`#607GSpS-1~@nb zMvIia=JW3E_TK(I)9mjDpQCcQA8<vX00006VoOIv00000008+zyMF)x010qNS#tmY z4c7nw4c7reD4Tcy000McNliru<^~G`I0#RQsty1E0WwKMK~zY`?Uk`g15pq~&qNU= zHVSF1EEUBfHa3clmAztVp_PTbU?W1lK=1=B{fPu^tb!<hfR%!s7>x1Qyui8;Ld*&l zURd6~yX>5Kv%^l1q%HyrKro!1fqF!=$pk;MSlz2r0Fg4k1?s>B!)qQm1WqF27<D^Q z_X`M)T1xTG0ZIkb{F@@;GrKSG%lZfW44}@aH|lD}tEgA%X2vV44RvSG6MO(~>FTNj zw1L;0*8<*q0Y-bY+7qyr^Im}UoYw+2{=4Y!11vJ2I+E|AX1d>1$pIS?@sM5|1Ga#P zK8%&LK4z)49)n{qJzr9r0}PyNb&~9_TAc-^({?Tmp97!*9HnyBfXhB7=tM-bUmdF{ zlh?G~smn!vs4k$Ro~q*%+zHjfv(5p^MP>a3q2WXn`<?dz00000NkvXXu0mjfc+F$Q literal 0 HcmV?d00001 diff --git a/sdrgui/resources/world.png b/sdrgui/resources/world.png new file mode 100644 index 0000000000000000000000000000000000000000..4572120e78f18e936c7931b2d4a709bc2ed5a2c7 GIT binary patch literal 7828 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 D&}sz4 literal 0 HcmV?d00001 diff --git a/swagger/sdrangel/api/swagger/include/M17Mod.yaml b/swagger/sdrangel/api/swagger/include/M17Mod.yaml index 42a65efa8..162071947 100644 --- a/swagger/sdrangel/api/swagger/include/M17Mod.yaml +++ b/swagger/sdrangel/api/swagger/include/M17Mod.yaml @@ -26,8 +26,15 @@ M17ModSettings: type: string audioDeviceName: type: string - modAFInput: + m17Mode: type: integer + description: M17Mode + audioType: + type: integer + description: AudioType + packetType: + type: integer + description: PacketType streamIndex: description: MIMO channel. Not relevant when connected to SI (single Rx). type: integer diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index c77a093ed..0099b9d15 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -8390,8 +8390,17 @@ margin-bottom: 20px; "audioDeviceName" : { "type" : "string" }, - "modAFInput" : { - "type" : "integer" + "m17Mode" : { + "type" : "integer", + "description" : "M17Mode" + }, + "audioType" : { + "type" : "integer", + "description" : "AudioType" + }, + "packetType" : { + "type" : "integer", + "description" : "PacketType" }, "streamIndex" : { "type" : "integer", @@ -56380,7 +56389,7 @@ except ApiException as e: </div> <div id="generator"> <div class="content"> - Generated 2022-06-09T22:25:54.513+02:00 + Generated 2022-06-10T22:26:56.056+02:00 </div> </div> </div> diff --git a/swagger/sdrangel/code/qt5/client/SWGM17ModSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGM17ModSettings.cpp index 1ff287761..db04df885 100644 --- a/swagger/sdrangel/code/qt5/client/SWGM17ModSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGM17ModSettings.cpp @@ -48,8 +48,12 @@ SWGM17ModSettings::SWGM17ModSettings() { m_title_isSet = false; audio_device_name = nullptr; m_audio_device_name_isSet = false; - mod_af_input = 0; - m_mod_af_input_isSet = false; + m17_mode = 0; + m_m17_mode_isSet = false; + audio_type = 0; + m_audio_type_isSet = false; + packet_type = 0; + m_packet_type_isSet = false; stream_index = 0; m_stream_index_isSet = false; use_reverse_api = 0; @@ -94,8 +98,12 @@ SWGM17ModSettings::init() { m_title_isSet = false; audio_device_name = new QString(""); m_audio_device_name_isSet = false; - mod_af_input = 0; - m_mod_af_input_isSet = false; + m17_mode = 0; + m_m17_mode_isSet = false; + audio_type = 0; + m_audio_type_isSet = false; + packet_type = 0; + m_packet_type_isSet = false; stream_index = 0; m_stream_index_isSet = false; use_reverse_api = 0; @@ -133,6 +141,8 @@ SWGM17ModSettings::cleanup() { + + if(reverse_api_address != nullptr) { delete reverse_api_address; } @@ -178,7 +188,11 @@ SWGM17ModSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&audio_device_name, pJson["audioDeviceName"], "QString", "QString"); - ::SWGSDRangel::setValue(&mod_af_input, pJson["modAFInput"], "qint32", ""); + ::SWGSDRangel::setValue(&m17_mode, pJson["m17Mode"], "qint32", ""); + + ::SWGSDRangel::setValue(&audio_type, pJson["audioType"], "qint32", ""); + + ::SWGSDRangel::setValue(&packet_type, pJson["packetType"], "qint32", ""); ::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", ""); @@ -242,8 +256,14 @@ SWGM17ModSettings::asJsonObject() { if(audio_device_name != nullptr && *audio_device_name != QString("")){ toJsonValue(QString("audioDeviceName"), audio_device_name, obj, QString("QString")); } - if(m_mod_af_input_isSet){ - obj->insert("modAFInput", QJsonValue(mod_af_input)); + if(m_m17_mode_isSet){ + obj->insert("m17Mode", QJsonValue(m17_mode)); + } + if(m_audio_type_isSet){ + obj->insert("audioType", QJsonValue(audio_type)); + } + if(m_packet_type_isSet){ + obj->insert("packetType", QJsonValue(packet_type)); } if(m_stream_index_isSet){ obj->insert("streamIndex", QJsonValue(stream_index)); @@ -374,13 +394,33 @@ SWGM17ModSettings::setAudioDeviceName(QString* audio_device_name) { } qint32 -SWGM17ModSettings::getModAfInput() { - return mod_af_input; +SWGM17ModSettings::getM17Mode() { + return m17_mode; } void -SWGM17ModSettings::setModAfInput(qint32 mod_af_input) { - this->mod_af_input = mod_af_input; - this->m_mod_af_input_isSet = true; +SWGM17ModSettings::setM17Mode(qint32 m17_mode) { + this->m17_mode = m17_mode; + this->m_m17_mode_isSet = true; +} + +qint32 +SWGM17ModSettings::getAudioType() { + return audio_type; +} +void +SWGM17ModSettings::setAudioType(qint32 audio_type) { + this->audio_type = audio_type; + this->m_audio_type_isSet = true; +} + +qint32 +SWGM17ModSettings::getPacketType() { + return packet_type; +} +void +SWGM17ModSettings::setPacketType(qint32 packet_type) { + this->packet_type = packet_type; + this->m_packet_type_isSet = true; } qint32 @@ -498,7 +538,13 @@ SWGM17ModSettings::isSet(){ if(audio_device_name && *audio_device_name != QString("")){ isObjectUpdated = true; break; } - if(m_mod_af_input_isSet){ + if(m_m17_mode_isSet){ + isObjectUpdated = true; break; + } + if(m_audio_type_isSet){ + isObjectUpdated = true; break; + } + if(m_packet_type_isSet){ isObjectUpdated = true; break; } if(m_stream_index_isSet){ diff --git a/swagger/sdrangel/code/qt5/client/SWGM17ModSettings.h b/swagger/sdrangel/code/qt5/client/SWGM17ModSettings.h index 2226d218b..794e6b639 100644 --- a/swagger/sdrangel/code/qt5/client/SWGM17ModSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGM17ModSettings.h @@ -74,8 +74,14 @@ public: QString* getAudioDeviceName(); void setAudioDeviceName(QString* audio_device_name); - qint32 getModAfInput(); - void setModAfInput(qint32 mod_af_input); + qint32 getM17Mode(); + void setM17Mode(qint32 m17_mode); + + qint32 getAudioType(); + void setAudioType(qint32 audio_type); + + qint32 getPacketType(); + void setPacketType(qint32 packet_type); qint32 getStreamIndex(); void setStreamIndex(qint32 stream_index); @@ -135,8 +141,14 @@ private: QString* audio_device_name; bool m_audio_device_name_isSet; - qint32 mod_af_input; - bool m_mod_af_input_isSet; + qint32 m17_mode; + bool m_m17_mode_isSet; + + qint32 audio_type; + bool m_audio_type_isSet; + + qint32 packet_type; + bool m_packet_type_isSet; qint32 stream_index; bool m_stream_index_isSet;