diff --git a/plugins/channeltx/modnfm/nfmmod.cpp b/plugins/channeltx/modnfm/nfmmod.cpp index 0425ea5ca..9ac12d3e9 100644 --- a/plugins/channeltx/modnfm/nfmmod.cpp +++ b/plugins/channeltx/modnfm/nfmmod.cpp @@ -57,7 +57,6 @@ NFMMod::NFMMod(DeviceSinkAPI *deviceAPI) : m_fileSize(0), m_recordLength(0), m_sampleRate(48000), - m_afInput(NFMModInputNone), m_levelCalcCount(0), m_peakLevel(0.0f), m_levelSum(0.0f) @@ -179,7 +178,7 @@ void NFMMod::modulateSample() void NFMMod::pullAF(Real& sample) { - switch (m_afInput) + switch (m_settings.m_modAFInput) { case NFMModInputTone: sample = m_toneNco.next(); @@ -330,6 +329,7 @@ bool NFMMod::handleMessage(const Message& cmd) << " m_ctcssOn: " << settings.m_ctcssOn << " m_channelMute: " << settings.m_channelMute << " m_playLoop: " << settings.m_playLoop + << " m_modAFInout " << settings.m_modAFInput << " force: " << cfg.getForce(); applySettings(settings, cfg.getForce()); @@ -360,7 +360,7 @@ bool NFMMod::handleMessage(const Message& cmd) MsgConfigureAFInput& conf = (MsgConfigureAFInput&) cmd; m_afInput = conf.getAFInput(); qDebug() << "NFMMod::handleMessage: MsgConfigureAFInput:" - << " seekPercentage: " << m_afInput; + << " m_afInput: " << m_afInput; return true; } diff --git a/plugins/channeltx/modnfm/nfmmodgui.cpp b/plugins/channeltx/modnfm/nfmmodgui.cpp index c3fe955a4..eeaabf345 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.cpp +++ b/plugins/channeltx/modnfm/nfmmodgui.cpp @@ -203,9 +203,10 @@ void NFMModGUI::on_play_toggled(bool checked) ui->tone->setEnabled(!checked); // release other source inputs ui->mic->setEnabled(!checked); ui->morseKeyer->setEnabled(!checked); - m_modAFInput = checked ? NFMMod::NFMModInputFile : NFMMod::NFMModInputNone; - NFMMod::MsgConfigureAFInput* message = NFMMod::MsgConfigureAFInput::create(m_modAFInput); - m_nfmMod->getInputMessageQueue()->push(message); + m_settings.m_modAFInput = checked ? NFMModSettings::NFMModInputFile : NFMModSettings::NFMModInputNone; + applySettings(); +// NFMMod::MsgConfigureAFInput* message = NFMMod::MsgConfigureAFInput::create(m_modAFInput); +// m_nfmMod->getInputMessageQueue()->push(message); ui->navTimeSlider->setEnabled(!checked); m_enableNavTime = !checked; } @@ -215,9 +216,10 @@ void NFMModGUI::on_tone_toggled(bool checked) ui->play->setEnabled(!checked); // release other source inputs ui->mic->setEnabled(!checked); ui->morseKeyer->setEnabled(!checked); - m_modAFInput = checked ? NFMMod::NFMModInputTone : NFMMod::NFMModInputNone; - NFMMod::MsgConfigureAFInput* message = NFMMod::MsgConfigureAFInput::create(m_modAFInput); - m_nfmMod->getInputMessageQueue()->push(message); + m_settings.m_modAFInput = checked ? NFMModSettings::NFMModInputTone : NFMModSettings::NFMModInputNone; + applySettings(); +// NFMMod::MsgConfigureAFInput* message = NFMMod::MsgConfigureAFInput::create(m_modAFInput); +// m_nfmMod->getInputMessageQueue()->push(message); } void NFMModGUI::on_morseKeyer_toggled(bool checked) @@ -225,9 +227,10 @@ void NFMModGUI::on_morseKeyer_toggled(bool checked) ui->tone->setEnabled(!checked); // release other source inputs ui->mic->setEnabled(!checked); ui->play->setEnabled(!checked); - m_modAFInput = checked ? NFMMod::NFMModInputCWTone : NFMMod::NFMModInputNone; - NFMMod::MsgConfigureAFInput* message = NFMMod::MsgConfigureAFInput::create(m_modAFInput); - m_nfmMod->getInputMessageQueue()->push(message); + m_settings.m_modAFInput = checked ? NFMModSettings::NFMModInputCWTone : NFMModSettings::NFMModInputNone; + applySettings(); +// NFMMod::MsgConfigureAFInput* message = NFMMod::MsgConfigureAFInput::create(m_modAFInput); +// m_nfmMod->getInputMessageQueue()->push(message); } void NFMModGUI::on_mic_toggled(bool checked) @@ -235,9 +238,10 @@ void NFMModGUI::on_mic_toggled(bool checked) ui->play->setEnabled(!checked); // release other source inputs ui->tone->setEnabled(!checked); // release other source inputs ui->morseKeyer->setEnabled(!checked); - m_modAFInput = checked ? NFMMod::NFMModInputAudio : NFMMod::NFMModInputNone; - NFMMod::MsgConfigureAFInput* message = NFMMod::MsgConfigureAFInput::create(m_modAFInput); - m_nfmMod->getInputMessageQueue()->push(message); + m_settings.m_modAFInput = checked ? NFMModSettings::NFMModInputAudio : NFMModSettings::NFMModInputNone; + applySettings(); +// NFMMod::MsgConfigureAFInput* message = NFMMod::MsgConfigureAFInput::create(m_modAFInput); +// m_nfmMod->getInputMessageQueue()->push(message); } void NFMModGUI::on_navTimeSlider_valueChanged(int value) @@ -303,8 +307,7 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_recordSampleRate(48000), m_samplesCount(0), m_tickCount(0), - m_enableNavTime(false), - m_modAFInput(NFMMod::NFMModInputNone) + m_enableNavTime(false) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); @@ -428,6 +431,16 @@ void NFMModGUI::displaySettings() ui->channelMute->setChecked(m_settings.m_channelMute); ui->playLoop->setChecked(m_settings.m_playLoop); + ui->tone->setEnabled((m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputTone) || (m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputNone)); + ui->mic->setEnabled((m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputAudio) || (m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputNone)); + ui->play->setEnabled((m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputFile) || (m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputNone)); + ui->morseKeyer->setEnabled((m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputCWTone) || (m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputNone)); + + ui->tone->setChecked(m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputTone); + ui->mic->setChecked(m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputAudio); + ui->play->setChecked(m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputFile); + ui->morseKeyer->setChecked(m_settings.m_modAFInput == NFMModSettings::NFMModInputAF::NFMModInputCWTone); + blockApplySettings(false); } @@ -448,7 +461,7 @@ void NFMModGUI::tick() m_channelPowerDbAvg.feed(powDb); ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.average(), 0, 'f', 1)); - if (((++m_tickCount & 0xf) == 0) && (m_modAFInput == NFMMod::NFMModInputFile)) + if (((++m_tickCount & 0xf) == 0) && (m_settings.m_modAFInput == NFMMod::NFMModInputFile)) { NFMMod::MsgConfigureFileSourceStreamTiming* message = NFMMod::MsgConfigureFileSourceStreamTiming::create(); m_nfmMod->getInputMessageQueue()->push(message); diff --git a/plugins/channeltx/modnfm/nfmmodsettings.cpp b/plugins/channeltx/modnfm/nfmmodsettings.cpp index f87b066a2..86594eca2 100644 --- a/plugins/channeltx/modnfm/nfmmodsettings.cpp +++ b/plugins/channeltx/modnfm/nfmmodsettings.cpp @@ -59,6 +59,7 @@ void NFMModSettings::resetToDefaults() m_ctcssIndex = 0; m_rgbColor = QColor(255, 0, 0).rgb(); m_title = "NFM Modulator"; + m_modAFInput = NFMModInputAF::NFMModInputNone; } QByteArray NFMModSettings::serialize() const @@ -84,6 +85,7 @@ QByteArray NFMModSettings::serialize() const s.writeBool(9, m_ctcssOn); s.writeS32(10, m_ctcssIndex); s.writeString(12, m_title); + s.writeS32(13, (int) m_modAFInput); return s.final(); } @@ -127,6 +129,13 @@ bool NFMModSettings::deserialize(const QByteArray& data) d.readString(12, &m_title, "NFM Modulator"); + d.readS32(13, &tmp, 0); + if ((tmp < 0) || (tmp > (int) NFMModInputAF::NFMModInputTone)) { + m_modAFInput = NFMModInputNone; + } else { + m_modAFInput = (NFMModInputAF) tmp; + } + return true; } else diff --git a/plugins/channeltx/modnfm/nfmmodsettings.h b/plugins/channeltx/modnfm/nfmmodsettings.h index 6d1ab4f35..221640185 100644 --- a/plugins/channeltx/modnfm/nfmmodsettings.h +++ b/plugins/channeltx/modnfm/nfmmodsettings.h @@ -23,6 +23,15 @@ class Serializable; struct NFMModSettings { + typedef enum + { + NFMModInputNone, + NFMModInputTone, + NFMModInputFile, + NFMModInputAudio, + NFMModInputCWTone + } NFMModInputAF; + static const int m_nbRfBW; static const int m_rfBW[]; static const int m_nbCTCSSFreqs; @@ -43,6 +52,7 @@ struct NFMModSettings int m_ctcssIndex; quint32 m_rgbColor; QString m_title; + NFMModInputAF m_modAFInput; Serializable *m_channelMarker; Serializable *m_cwKeyerGUI; diff --git a/sdrbase/webapi/webapirequestmapper.cpp b/sdrbase/webapi/webapirequestmapper.cpp index 3c371dd3c..ecb06fe95 100644 --- a/sdrbase/webapi/webapirequestmapper.cpp +++ b/sdrbase/webapi/webapirequestmapper.cpp @@ -57,6 +57,7 @@ void WebAPIRequestMapper::service(qtwebapp::HttpRequest& request, qtwebapp::Http { if (m_adapter == 0) // format service unavailable if adapter is null { + response.setHeader("Content-Type", "text/plain"); response.setStatus(500,"Service not available"); response.write("Service not available"); } @@ -106,7 +107,7 @@ void WebAPIRequestMapper::service(qtwebapp::HttpRequest& request, qtwebapp::Http else { QByteArray path = "/index.html"; - response.setStatus(404, "Page not found"); + response.setStatus(400, "API URL does not exist"); m_staticFileController->service(path, response); } @@ -121,10 +122,12 @@ void WebAPIRequestMapper::service(qtwebapp::HttpRequest& request, qtwebapp::Http void WebAPIRequestMapper::instanceSummaryService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { + SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); + if (request.getMethod() == "GET") { SWGSDRangel::SWGInstanceSummaryResponse normalResponse; - SWGSDRangel::SWGErrorResponse errorResponse; int status = m_adapter->instanceSummary(normalResponse, errorResponse); response.setStatus(status); @@ -138,7 +141,9 @@ void WebAPIRequestMapper::instanceSummaryService(qtwebapp::HttpRequest& request, else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } @@ -146,6 +151,7 @@ void WebAPIRequestMapper::instanceDevicesService(qtwebapp::HttpRequest& request, { SWGSDRangel::SWGInstanceDevicesResponse normalResponse; SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "GET") { @@ -168,7 +174,9 @@ void WebAPIRequestMapper::instanceDevicesService(qtwebapp::HttpRequest& request, else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } @@ -176,6 +184,7 @@ void WebAPIRequestMapper::instanceChannelsService(qtwebapp::HttpRequest& request { SWGSDRangel::SWGInstanceChannelsResponse normalResponse; SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "GET") { @@ -198,7 +207,9 @@ void WebAPIRequestMapper::instanceChannelsService(qtwebapp::HttpRequest& request else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } @@ -206,6 +217,7 @@ void WebAPIRequestMapper::instanceLoggingService(qtwebapp::HttpRequest& request, { SWGSDRangel::SWGLoggingInfo normalResponse; SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "GET") { @@ -239,13 +251,16 @@ void WebAPIRequestMapper::instanceLoggingService(qtwebapp::HttpRequest& request, else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } void WebAPIRequestMapper::instanceAudioService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "GET") { @@ -282,13 +297,16 @@ void WebAPIRequestMapper::instanceAudioService(qtwebapp::HttpRequest& request, q else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } void WebAPIRequestMapper::instanceLocationService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "GET") { @@ -325,13 +343,16 @@ void WebAPIRequestMapper::instanceLocationService(qtwebapp::HttpRequest& request else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } void WebAPIRequestMapper::instanceDVSerialService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "PATCH") { @@ -356,13 +377,16 @@ void WebAPIRequestMapper::instanceDVSerialService(qtwebapp::HttpRequest& request else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } void WebAPIRequestMapper::instancePresetService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "GET") { @@ -502,13 +526,16 @@ void WebAPIRequestMapper::instancePresetService(qtwebapp::HttpRequest& request, else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } void WebAPIRequestMapper::instanceDeviceSetsService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "GET") { @@ -556,13 +583,16 @@ void WebAPIRequestMapper::instanceDeviceSetsService(qtwebapp::HttpRequest& reque else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } void WebAPIRequestMapper::devicesetService(const std::string& indexStr, qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); if (request.getMethod() == "GET") { @@ -590,13 +620,16 @@ void WebAPIRequestMapper::devicesetService(const std::string& indexStr, qtwebapp else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } void WebAPIRequestMapper::devicesetDeviceService(const std::string& indexStr, qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); try { @@ -625,7 +658,9 @@ void WebAPIRequestMapper::devicesetDeviceService(const std::string& indexStr, qt else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } catch (const boost::bad_lexical_cast &e) @@ -640,6 +675,7 @@ void WebAPIRequestMapper::devicesetDeviceService(const std::string& indexStr, qt void WebAPIRequestMapper::devicesetDeviceSettingsService(const std::string& indexStr, qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); try { @@ -695,7 +731,9 @@ void WebAPIRequestMapper::devicesetDeviceSettingsService(const std::string& inde else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } catch (const boost::bad_lexical_cast &e) @@ -710,6 +748,7 @@ void WebAPIRequestMapper::devicesetDeviceSettingsService(const std::string& inde void WebAPIRequestMapper::devicesetDeviceRunService(const std::string& indexStr, qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); try { @@ -757,7 +796,9 @@ void WebAPIRequestMapper::devicesetDeviceRunService(const std::string& indexStr, else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } catch (const boost::bad_lexical_cast &e) @@ -775,6 +816,7 @@ void WebAPIRequestMapper::devicesetChannelService( qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); try { @@ -819,6 +861,13 @@ void WebAPIRequestMapper::devicesetChannelService( } } } + else + { + response.setStatus(405,"Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); + } } catch (const boost::bad_lexical_cast &e) { @@ -836,6 +885,7 @@ void WebAPIRequestMapper::devicesetChannelIndexService( qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); try { @@ -856,6 +906,13 @@ void WebAPIRequestMapper::devicesetChannelIndexService( response.write(errorResponse.asJson().toUtf8()); } } + else + { + response.setStatus(405,"Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); + } } catch (const boost::bad_lexical_cast &e) { @@ -873,6 +930,7 @@ void WebAPIRequestMapper::devicesetChannelSettingsService( qtwebapp::HttpResponse& response) { SWGSDRangel::SWGErrorResponse errorResponse; + response.setHeader("Content-Type", "application/json"); try { @@ -930,7 +988,9 @@ void WebAPIRequestMapper::devicesetChannelSettingsService( else { response.setStatus(405,"Invalid HTTP method"); - response.write("Invalid HTTP method"); + errorResponse.init(); + *errorResponse.getMessage() = "Invalid HTTP method"; + response.write(errorResponse.asJson().toUtf8()); } } catch (const boost::bad_lexical_cast &e) diff --git a/sdrgui/gui/cwkeyergui.cpp b/sdrgui/gui/cwkeyergui.cpp index b8761cd0f..009f6b4ef 100644 --- a/sdrgui/gui/cwkeyergui.cpp +++ b/sdrgui/gui/cwkeyergui.cpp @@ -179,30 +179,14 @@ void CWKeyerGUI::displaySettings(const CWKeyerSettings& settings) ui->playLoopCW->setChecked(settings.m_loop); - switch (settings.m_mode) - { - case CWKeyerSettings::CWDashes: - ui->playDots->setEnabled(false); - ui->playDashes->setEnabled(true); - ui->playText->setEnabled(false); - break; - case CWKeyerSettings::CWDots: - ui->playDots->setEnabled(true); - ui->playDashes->setEnabled(false); - ui->playText->setEnabled(false); - break; - case CWKeyerSettings::CWText: - ui->playDots->setEnabled(false); - ui->playDashes->setEnabled(false); - ui->playText->setEnabled(true); - break; - case CWKeyerSettings::CWNone: - default: - ui->playDots->setEnabled(false); - ui->playDashes->setEnabled(false); - ui->playText->setEnabled(false); - break; - } + ui->playDots->setEnabled((settings.m_mode == CWKeyerSettings::CWDots) || (settings.m_mode == CWKeyerSettings::CWNone)); + ui->playDots->setChecked(settings.m_mode == CWKeyerSettings::CWDots); + + ui->playDashes->setEnabled((settings.m_mode == CWKeyerSettings::CWDashes) || (settings.m_mode == CWKeyerSettings::CWNone)); + ui->playDashes->setChecked(settings.m_mode == CWKeyerSettings::CWDashes); + + ui->playText->setEnabled((settings.m_mode == CWKeyerSettings::CWText) || (settings.m_mode == CWKeyerSettings::CWNone)); + ui->playText->setChecked(settings.m_mode == CWKeyerSettings::CWText); ui->cwTextEdit->setText(settings.m_text); ui->cwSpeed->setValue(settings.m_wpm);