From 22ad8cbaad00d89361cbd92023dd20a807bcf5cb Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Tue, 3 Jan 2023 00:58:28 -0500 Subject: Rework radio support for new gRPC API Update the stubbed out radio support library to use the new gRPC API. The "Radio" Qt wrapper object has been renamed to "RadioClient" to avoid conflicting with the generated gRPC API code. This somewhat aligns with the naming that has been used with the AppLauncher support. Bug-AGL: SPEC-4665 Signed-off-by: Scott Murray Change-Id: I642f9b9b62d6981cf5231ecea4caddba713f493a --- radio/RadioClient.cpp | 142 ++++++++++++++++++++++ radio/RadioClient.h | 95 +++++++++++++++ radio/RadioGrpcClient.cpp | 213 +++++++++++++++++++++++++++++++++ radio/RadioGrpcClient.h | 67 +++++++++++ radio/meson.build | 43 ++++++- radio/protos/radio.proto | 205 ++++++++++++++++++++++++++++++++ radio/radio.cpp | 294 ---------------------------------------------- radio/radio.h | 98 ---------------- 8 files changed, 761 insertions(+), 396 deletions(-) create mode 100644 radio/RadioClient.cpp create mode 100644 radio/RadioClient.h create mode 100644 radio/RadioGrpcClient.cpp create mode 100644 radio/RadioGrpcClient.h create mode 100644 radio/protos/radio.proto delete mode 100644 radio/radio.cpp delete mode 100644 radio/radio.h diff --git a/radio/RadioClient.cpp b/radio/RadioClient.cpp new file mode 100644 index 0000000..a142d22 --- /dev/null +++ b/radio/RadioClient.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2018-2020,2022 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "RadioClient.h" +#include "RadioGrpcClient.h" + +RadioClient::RadioClient(QQmlContext *context, QObject * parent) : + QObject(parent), + m_band(1), + m_frequency(0), + m_minFrequency(0), + m_maxFrequency(0), + m_playing(false), + m_scanning(false) +{ + m_radio = new RadioGrpcClient(this); + + if (m_radio) { + m_radio->GetBandParameters(m_band, m_minFrequency, m_maxFrequency, m_frequencyStep); + emit minFrequencyChanged(m_minFrequency); + emit maxFrequencyChanged(m_maxFrequency); + emit frequencyStepChanged(m_frequencyStep); + + // Handle start up + if (!m_frequency) { + m_frequency = m_minFrequency; + emit frequencyChanged(m_frequency); + } + } +} + +RadioClient::~RadioClient() +{ + delete m_radio; +} + +void RadioClient::setBand(int band) +{ + if (m_radio) + m_radio->SetBand(band); +} + +void RadioClient::setFrequency(int frequency) +{ + if (!m_radio) + return; + + m_radio->SetFrequency(frequency); + + // To improve UI responsiveness, signal the change here immediately + // This fixes visual glitchiness in the slider caused by the frequency + // update event taking long enough that the QML engine gets a chance + // to update the slider with the current value before the event with + // the new value comes. + m_frequency = frequency; + emit frequencyChanged(m_frequency); +} + +// control related methods + +void RadioClient::start() +{ + if (m_radio) + m_radio->Start(); +} + +void RadioClient::stop() +{ + if (m_radio) + m_radio->Stop(); +} + +void RadioClient::scanForward() +{ + if (!m_radio || m_scanning) + return; + + m_radio->ScanForward(); + + m_scanning = true; + emit scanningChanged(m_scanning); +} + +void RadioClient::scanBackward() +{ + if (!m_radio || m_scanning) + return; + + m_radio->ScanBackward(); + + m_scanning = true; + emit scanningChanged(m_scanning); +} + +void RadioClient::scanStop() +{ + if (m_radio) + m_radio->ScanStop(); + + m_scanning = false; + emit scanningChanged(m_scanning); +} + +void RadioClient::updateBand(int band) +{ + m_band = band; + emit bandChanged(m_band); +} + +void RadioClient::updateFrequency(int frequency) +{ + m_frequency = frequency; + emit frequencyChanged(m_frequency); +} + +void RadioClient::updatePlaying(bool status) +{ + m_playing = status; + emit playingChanged(m_playing); +} + +void RadioClient::updateScanning(int station_found) +{ + if (station_found && m_scanning) { + m_scanning = false; + emit scanningChanged(m_scanning); + } +} diff --git a/radio/RadioClient.h b/radio/RadioClient.h new file mode 100644 index 0000000..5920442 --- /dev/null +++ b/radio/RadioClient.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2018-2020,2022 Konsulko Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RADIO_CLIENT_H +#define RADIO_CLIENT_H + +#include +#include + +class RadioGrpcClient; + +class RadioClient : public QObject +{ + Q_OBJECT + Q_PROPERTY(unsigned int band READ band WRITE setBand NOTIFY bandChanged) + Q_PROPERTY(unsigned int amBand READ amBand CONSTANT) + Q_PROPERTY(unsigned int fmBand READ fmBand CONSTANT) + Q_PROPERTY(unsigned int frequency READ frequency WRITE setFrequency NOTIFY frequencyChanged) + Q_PROPERTY(bool playing READ playing NOTIFY playingChanged) + Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged) + Q_PROPERTY(unsigned int minFrequency READ minFrequency NOTIFY minFrequencyChanged) + Q_PROPERTY(unsigned int maxFrequency READ maxFrequency NOTIFY maxFrequencyChanged) + Q_PROPERTY(unsigned int frequencyStep READ frequencyStep NOTIFY frequencyStepChanged) + +public: + explicit RadioClient(QQmlContext *context, QObject * parent = Q_NULLPTR); + virtual ~RadioClient(); + + unsigned int band() const { return m_band; } + void setBand(int band); + + unsigned int amBand() const { return 0; } + unsigned int fmBand() const { return 1; } + + unsigned int frequency() const { return m_frequency; } + void setFrequency(int frequency); + + unsigned int minFrequency() const { return m_minFrequency; } + unsigned int maxFrequency() const { return m_maxFrequency; } + unsigned int frequencyStep() const { return m_frequencyStep; } + + bool playing() const { return m_playing; } + + bool scanning() const { return m_scanning; } + + // controls + Q_INVOKABLE void start(); + Q_INVOKABLE void stop(); + Q_INVOKABLE void scanForward(); + Q_INVOKABLE void scanBackward(); + Q_INVOKABLE void scanStop(); + +public slots: + void updateBand(int band); + void updateFrequency(int frequency); + void updatePlaying(bool status); + void updateScanning(int station_found); + +signals: + void bandChanged(int band); + void frequencyChanged(int frequency); + void playingChanged(bool status); + void scanningChanged(bool scanning); + void minFrequencyChanged(int minFrequency); + void maxFrequencyChanged(int maxFrequency); + void frequencyStepChanged(int frequencyStep); + +private: + QQmlContext *m_context; + + RadioGrpcClient *m_radio; + + unsigned int m_band; + unsigned int m_frequency; + unsigned int m_minFrequency; + unsigned int m_maxFrequency; + unsigned int m_frequencyStep; + bool m_playing; + bool m_scanning; +}; + +#endif // RADIO_H diff --git a/radio/RadioGrpcClient.cpp b/radio/RadioGrpcClient.cpp new file mode 100644 index 0000000..3795d1d --- /dev/null +++ b/radio/RadioGrpcClient.cpp @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2023 Konsulko Group + */ + +#include +#include "RadioGrpcClient.h" +#include "RadioClient.h" + +using grpc::Channel; +using grpc::ClientContext; +using grpc::ClientReader; +using grpc::Status; + +using automotivegradelinux::Radio; +using automotivegradelinux::SetBandRequest; +using automotivegradelinux::SetBandResponse; +using automotivegradelinux::SetFrequencyRequest; +using automotivegradelinux::SetFrequencyResponse; +using automotivegradelinux::StartRequest; +using automotivegradelinux::StartResponse; +using automotivegradelinux::StopRequest; +using automotivegradelinux::StopResponse; +using automotivegradelinux::ScanStartRequest; +using automotivegradelinux::ScanStartResponse; +using automotivegradelinux::ScanStopRequest; +using automotivegradelinux::ScanStopResponse; +using automotivegradelinux::GetBandParametersRequest; +using automotivegradelinux::GetBandParametersResponse; +using automotivegradelinux::StatusRequest; +using automotivegradelinux::StatusResponse; +using automotivegradelinux::BandStatus; +using automotivegradelinux::FrequencyStatus; +using automotivegradelinux::PlayStatus; +using automotivegradelinux::ScanStatus; + +// Enum values used +using automotivegradelinux::BAND_AM; +using automotivegradelinux::BAND_FM; +using automotivegradelinux::SCAN_DIRECTION_FORWARD; +using automotivegradelinux::SCAN_DIRECTION_BACKWARD; + +void RadioStatusEventReader::GetStatusEvents() +{ + ClientContext context; + StatusRequest request; + StatusResponse response; + + std::unique_ptr > reader(stub_->GetStatusEvents(&context, request)); + while (reader->Read(&response)) { + if (response.has_band()) { + BandStatus band_status = response.band(); + unsigned int band; + if (band_status.band() == BAND_AM) + band = 0; + else if (band_status.band() == BAND_FM) + band = 1; + else + continue; + emit bandUpdate(band); + } else if (response.has_frequency()) { + FrequencyStatus frequency_status = response.frequency(); + emit frequencyUpdate(frequency_status.frequency()); + } else if (response.has_play()) { + PlayStatus play_status = response.play(); + emit playingUpdate(play_status.playing()); + } else if (response.has_scan()) { + ScanStatus scan_status = response.scan(); + emit scanningUpdate(scan_status.station_found()); + } + } + Status status = reader->Finish(); + if (!status.ok()) { + qWarning() << "GetStatusEvents RPC failed"; + } + + emit finished(); +} + + +RadioGrpcClient::RadioGrpcClient(QObject *parent) : QObject(parent) +{ + stub_ = Radio::NewStub(grpc::CreateChannel("localhost:50053", grpc::InsecureChannelCredentials())); + + // Create thread to read status events + RadioStatusEventReader *reader = new RadioStatusEventReader(stub_); + reader->moveToThread(&m_event_thread); + connect(&m_event_thread, &QThread::started, reader, &RadioStatusEventReader::GetStatusEvents); + connect(reader, &RadioStatusEventReader::finished, &m_event_thread, &QThread::quit); + // FIXME: Normally the thread finishing would be connected per the below + // to trigger cleaning up the object. That seems to trigger a crash + // for not entirely obvious reasons. It seems unrelated to the signal + // connection to AppLauncherClient, as not connecting does not prevent + // the crash; further investigation is required. + //connect(reader, &RadioStatusEventReader::finished, reader, &RadioStatusEventReader::deleteLater); + //connect(&m_event_thread, &QThread::finished, &m_event_thread, &QThread::deleteLater); + + // To avoid having intermediary slot+signal's in this class, try + // casting parent to Radio and connect directly to its slot. + // Callers should set parent to ensure this works as required. + if (parent) { + RadioClient *radio = qobject_cast(parent); + if (radio) { + connect(reader, + &RadioStatusEventReader::bandUpdate, + radio, + &RadioClient::updateBand); + connect(reader, + &RadioStatusEventReader::frequencyUpdate, + radio, + &RadioClient::updateFrequency); + connect(reader, + &RadioStatusEventReader::playingUpdate, + radio, + &RadioClient::updatePlaying); + connect(reader, + &RadioStatusEventReader::scanningUpdate, + radio, + &RadioClient::updateScanning); + } + } + + // Start status event handling + m_event_thread.start(); +} + +void RadioGrpcClient::SetBand(unsigned int band) +{ + SetBandRequest request; + + ClientContext context; + SetBandResponse response; + if (band) + request.set_band(BAND_FM); + else + request.set_band(BAND_AM); + Status status = stub_->SetBand(&context, request, &response); +} + +void RadioGrpcClient::SetFrequency(unsigned int frequency) +{ + SetFrequencyRequest request; + + ClientContext context; + SetFrequencyResponse response; + request.set_frequency(frequency); + Status status = stub_->SetFrequency(&context, request, &response); +} + +void RadioGrpcClient::Start() +{ + StartRequest request; + + ClientContext context; + StartResponse response; + Status status = stub_->Start(&context, request, &response); +} + +void RadioGrpcClient::Stop() +{ + StopRequest request; + + ClientContext context; + StopResponse response; + Status status = stub_->Stop(&context, request, &response); +} + +void RadioGrpcClient::ScanForward() +{ + ScanStartRequest request; + + ClientContext context; + ScanStartResponse response; + request.set_direction(SCAN_DIRECTION_FORWARD); + Status status = stub_->ScanStart(&context, request, &response); +} + +void RadioGrpcClient::ScanBackward() +{ + ScanStartRequest request; + + ClientContext context; + ScanStartResponse response; + request.set_direction(SCAN_DIRECTION_BACKWARD); + Status status = stub_->ScanStart(&context, request, &response); +} + +void RadioGrpcClient::ScanStop() +{ + ScanStopRequest request; + + ClientContext context; + ScanStopResponse response; + Status status = stub_->ScanStop(&context, request, &response); +} + +void RadioGrpcClient::GetBandParameters(unsigned int band, unsigned int &min, unsigned int &max, unsigned int &step) +{ + GetBandParametersRequest request; + + ClientContext context; + GetBandParametersResponse response; + if (band) + request.set_band(BAND_FM); + else + request.set_band(BAND_AM); + Status status = stub_->GetBandParameters(&context, request, &response); + if (status.ok()) { + min = response.min(); + max = response.max(); + step = response.step(); + } +} diff --git a/radio/RadioGrpcClient.h b/radio/RadioGrpcClient.h new file mode 100644 index 0000000..603253a --- /dev/null +++ b/radio/RadioGrpcClient.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2023 Konsulko Group + */ + +#ifndef RADIO_GRPC_CLIENT_H +#define RADIO_GRPC_CLIENT_H + +#include +#include +#include +#include +#include + +#include "radio.grpc.pb.h" + +using grpc::Channel; + +class RadioStatusEventReader : public QObject +{ + Q_OBJECT +public: + RadioStatusEventReader(std::shared_ptr &stub, + QObject *parent = Q_NULLPTR) : QObject(parent), stub_(stub) {} + +public slots: + void GetStatusEvents(); + +signals: + void bandUpdate(int band); + void frequencyUpdate(int frequency); + void playingUpdate(bool status); + void scanningUpdate(bool scanning); + + void finished(); + +private: + std::shared_ptr stub_; +}; + +class RadioGrpcClient : public QObject +{ + Q_OBJECT + +public: + RadioGrpcClient(QObject *parent = Q_NULLPTR); + + void SetBand(unsigned int band); + void SetFrequency(unsigned int frequency); + void Start(); + void Stop(); + void ScanForward(); + void ScanBackward(); + void ScanStop(); + void GetBandParameters(unsigned int band, + unsigned int &min, + unsigned int &max, + unsigned int &step); + +private: + std::shared_ptr stub_; + + QThread m_event_thread; + +}; + +#endif // RADIO_GRPC_CLIENT_H diff --git a/radio/meson.build b/radio/meson.build index c8218a3..7ae1bac 100644 --- a/radio/meson.build +++ b/radio/meson.build @@ -1,17 +1,52 @@ +cpp = meson.get_compiler('cpp') +grpcpp_reflection_dep = cpp.find_library('grpc++_reflection') + qt5_dep = dependency('qt5', modules: ['Qml']) +radio_dep = [ + qt5_dep, + dependency('protobuf'), + dependency('grpc'), + dependency('grpc++'), + grpcpp_reflection_dep, +] + +protoc = find_program('protoc') +grpc_cpp = find_program('grpc_cpp_plugin') + +protoc_gen = generator(protoc, \ + output : ['@BASENAME@.pb.cc', '@BASENAME@.pb.h'], + arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/protos', + '--cpp_out=@BUILD_DIR@', + '@INPUT@']) +generated_protoc_sources = protoc_gen.process('protos/radio.proto') -moc_files = qt5.compile_moc(headers: 'radio.h', +grpc_gen = generator(protoc, \ + output : ['@BASENAME@.grpc.pb.cc', '@BASENAME@.grpc.pb.h'], + arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/protos', + '--grpc_out=@BUILD_DIR@', + '--plugin=protoc-gen-grpc=' + grpc_cpp.path(), + '@INPUT@']) +generated_grpc_sources = grpc_gen.process('protos/radio.proto') + +moc_files = qt5.compile_moc(headers: ['RadioClient.h', 'RadioGrpcClient.h'], dependencies: qt5_dep) -src = ['radio.cpp', moc_files] +src = [ + 'RadioClient.cpp', + 'RadioGrpcClient.cpp', + generated_protoc_sources, + generated_grpc_sources, + moc_files +] + lib = shared_library('qtappfw-radio', sources: src, version: '1.0.0', soversion: '0', - dependencies: qt5_dep, + dependencies: radio_dep, install: true) -install_headers('radio.h') +install_headers('RadioClient.h') pkg_mod = import('pkgconfig') pkg_mod.generate(libraries : lib, diff --git a/radio/protos/radio.proto b/radio/protos/radio.proto new file mode 100644 index 0000000..60afc45 --- /dev/null +++ b/radio/protos/radio.proto @@ -0,0 +1,205 @@ +syntax = "proto3"; + +package automotivegradelinux; + +service Radio { + rpc GetFrequency(GetFrequencyRequest) returns (GetFrequencyResponse) {} + rpc SetFrequency(SetFrequencyRequest) returns (SetFrequencyResponse) {} + + rpc GetBand(GetBandRequest) returns (GetBandResponse) {} + rpc SetBand(SetBandRequest) returns (SetBandResponse) {} + + rpc GetBandSupported(GetBandSupportedRequest) returns (GetBandSupportedResponse) {} + rpc GetBandParameters(GetBandParametersRequest) returns (GetBandParametersResponse) {} + + rpc GetStereoMode(GetStereoModeRequest) returns (GetStereoModeResponse) {} + rpc SetStereoMode(SetStereoModeRequest) returns (SetStereoModeResponse) {} + + rpc Start(StartRequest) returns (StartResponse) {} + rpc Stop(StopRequest) returns (StopResponse) {} + + rpc ScanStart(ScanStartRequest) returns (ScanStartResponse) {} + rpc ScanStop(ScanStopRequest) returns (ScanStopResponse) {} + + rpc GetRDS(GetRDSRequest) returns (GetRDSResponse) {} + + rpc GetQuality(GetQualityRequest) returns (GetQualityResponse) {} + + rpc SetAlternativeFrequency(SetAlternativeFrequencyRequest) returns (SetAlternativeFrequencyResponse) {} + + rpc GetStatusEvents(StatusRequest) returns (stream StatusResponse) {} +} + +message GetFrequencyRequest { +} + +message GetFrequencyResponse { + uint32 frequency = 1; +} + +message SetFrequencyRequest { + uint32 frequency = 1; +} + +message SetFrequencyResponse { + uint32 frequency = 1; +} + +message GetBandRequest { +} + +enum Band { + BAND_UNSPECIFIED = 0; + BAND_AM = 1; + BAND_FM = 2; + BAND_DBS = 3; +} + +message GetBandResponse { + Band band = 1; +} + +message SetBandRequest { + Band band = 1; +} + +message SetBandResponse { + Band band = 1; +} + +message GetBandSupportedRequest { + Band band = 1; +} + +message GetBandSupportedResponse { + bool supported = 1; +} + +message GetBandParametersRequest { + Band band = 1; +} + +message GetBandParametersResponse { + uint32 min = 1; + uint32 max = 2; + uint32 step = 3; +} + +enum StereoMode { + STEREO_MODE_UNSPECIFIED = 0; + STEREO_MODE_MONO = 1; + STEREO_MODE_STEREO = 2; +} + +message GetStereoModeRequest { +} + +message GetStereoModeResponse { + StereoMode mode = 1; +} + +message SetStereoModeRequest { + StereoMode mode = 1; +} + +message SetStereoModeResponse { + StereoMode mode = 1; +} + +message StartRequest { +} + +message StartResponse { +} + +message StopRequest { +} + +message StopResponse { +} + +enum ScanDirection { + SCAN_DIRECTION_UNSPECIFIED = 0; + SCAN_DIRECTION_FORWARD = 1; + SCAN_DIRECTION_BACKWARD = 2; +} + +message ScanStartRequest { + ScanDirection direction = 1; +} + +message ScanStartResponse { +} + +message ScanStopRequest { +} + +message ScanStopResponse { +} + +message GetRDSRequest { +} + +// NOTE: This is a placeholder and will be revised! +message GetRDSResponse { + string name = 1; + string radio_text = 2; + string alternatives = 3; + string minute = 4; + string hour = 5; + string day = 6; + string month = 7; + string year = 8; + string pi = 9; + string pty = 10; + string ta = 11; + string tp = 12; + string ms = 13; +} + +message GetQualityRequest { +} + +message GetQualityResponse { +} + +message SetAlternativeFrequencyRequest { + uint32 frequency = 1; +} + +message SetAlternativeFrequencyResponse { + uint32 frequency = 1; +} + +message StatusRequest { +} + +message BandStatus { + Band band = 1; +} + +message FrequencyStatus { + uint32 frequency = 1; +} + +message PlayStatus { + bool playing = 1; +} + +message ScanStatus { + bool station_found = 1; +} + +message StereoStatus { + StereoMode mode = 1; +} + +message StatusResponse { + oneof status { + BandStatus band = 1; + FrequencyStatus frequency = 2; + PlayStatus play = 3; + StereoStatus stereo = 4; + ScanStatus scan = 5; + } +} diff --git a/radio/radio.cpp b/radio/radio.cpp deleted file mode 100644 index efe8e78..0000000 --- a/radio/radio.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2018-2020,2022 Konsulko Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "radio.h" - - -Radio::Radio(QQmlContext *context, QObject * parent) : - QObject(parent), - m_band(1), - m_frequency(0), - m_minFrequency(0), - m_maxFrequency(0), - m_playing(false), - m_scanning(false) -{ -#if 0 - m_mloop = MessageEngineFactory::getInstance().getMessageEngine(url); - m_context = context; - - QObject::connect(m_mloop.get(), &MessageEngine::connected, this, &Radio::onConnected); - QObject::connect(m_mloop.get(), &MessageEngine::disconnected, this, &Radio::onDisconnected); - QObject::connect(m_mloop.get(), &MessageEngine::messageReceived, this, &Radio::onMessageReceived); -#endif -} - -Radio::~Radio() -{ -} - -void Radio::setBand(int band) -{ -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - - parameter.insert("band", band ? "FM": "AM"); - rmsg->createRequest("radio", "band", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif -} - -void Radio::setFrequency(int frequency) -{ -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - - if (m_scanning) - scanStop(); - - if (frequency == m_frequency) - return; - - parameter.insert("value", QString::number(frequency)); - rmsg->createRequest("radio", "frequency", parameter); - m_mloop->sendMessage(std::move(msg)); - - // To improve UI responsiveness, signal the change here immediately - // This fixes visual glitchiness in the slider caused by the frequency - // update event taking long enough that the QML engine gets a chance - // to update the slider with the current value before the event with - // the new value comes. - m_frequency = frequency; - emit frequencyChanged(m_frequency); -#endif -} - -// control related methods - -void Radio::start() -{ -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - - rmsg->createRequest("radio", "start", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif -} - -void Radio::stop() -{ -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - rmsg->createRequest("radio", "stop", parameter); - m_mloop->sendMessage(std::move(msg)); -#endif -} - -void Radio::scanForward() -{ - if (m_scanning) - return; - -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - parameter.insert("direction", "forward"); - rmsg->createRequest("radio", "scan_start", parameter); - m_mloop->sendMessage(std::move(msg)); - - m_scanning = true; - emit scanningChanged(m_scanning); -#endif -} - -void Radio::scanBackward() -{ - if (m_scanning) - return; - -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - parameter.insert("direction", "backward"); - rmsg->createRequest("radio", "scan_start", parameter); - m_mloop->sendMessage(std::move(msg)); - - m_scanning = true; - emit scanningChanged(m_scanning); -#endif -} - -void Radio::scanStop() -{ -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - rmsg->createRequest("radio", "scan_stop", parameter); - m_mloop->sendMessage(std::move(msg)); - - m_scanning = false; - emit scanningChanged(m_scanning); -#endif -} - -void Radio::updateFrequencyBandParameters() -{ -#if 0 - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - parameter.insert("band", m_band ? "FM" : "AM"); - rmsg->createRequest("radio", "frequency_range", parameter); - m_mloop->sendMessage(std::move(msg)); - - std::unique_ptr msg2 = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg2) - return; - - rmsg = static_cast(msg2.get()); - rmsg->createRequest("radio", "frequency_step", parameter); - m_mloop->sendMessage(std::move(msg2)); -#endif -} - -#if 0 -void Radio::onConnected() -{ - QStringListIterator eventIterator(events); - - while (eventIterator.hasNext()) { - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - parameter.insert("value", eventIterator.next()); - rmsg->createRequest("radio", "subscribe", parameter); - m_mloop->sendMessage(std::move(msg)); - } - - // Trigger initial update of frequency band parameters (min/max/step) - updateFrequencyBandParameters(); -} - -void Radio::onDisconnected() -{ - QStringListIterator eventIterator(events); - - while (eventIterator.hasNext()) { - std::unique_ptr msg = MessageFactory::getInstance().createOutboundMessage(MessageId::Call); - if (!msg) - return; - - CallMessage* rmsg = static_cast(msg.get()); - QJsonObject parameter; - parameter.insert("value", eventIterator.next()); - rmsg->createRequest("radio", "unsubscribe", parameter); - m_mloop->sendMessage(std::move(msg)); - } -} - -void Radio::onMessageReceived(std::shared_ptr msg) -{ - if (!msg) - return; - - if (msg->isEvent()) { - std::shared_ptr emsg = std::static_pointer_cast(msg); - QString ename = emsg->eventName(); - QString eapi = emsg->eventApi(); - QJsonObject data = emsg->eventData(); - if (ename == "frequency") { - unsigned int frequency = data.value("value").toInt(); - m_frequency = frequency; - if (!m_scanning && (m_frequency != frequency)) { - emit frequencyChanged(m_frequency); - } - } else if (ename == "station_found") { - m_scanning = false; - emit scanningChanged(m_scanning); - - m_frequency = data.value("value").toInt(); - emit frequencyChanged(m_frequency); - } else if (ename == "status") { - if (data.value("value") == QString("playing")) { - m_playing = true; - emit playingChanged(m_playing); - } else if (data.value("value") == QString("stopped")) { - m_playing = false; - emit playingChanged(m_playing); - } - } - } else if (msg->isReply()) { - std::shared_ptr rmsg = std::static_pointer_cast(msg); - QString api = rmsg->requestApi(); - if (api != "radio") - return; - - QString verb = rmsg->requestVerb(); - QJsonObject data = rmsg->replyData(); - if (verb == "frequency_range") { - m_minFrequency = data.value("min").toInt(); - emit minFrequencyChanged(m_minFrequency); - m_maxFrequency = data.value("max").toInt(); - emit maxFrequencyChanged(m_maxFrequency); - - // Handle start up - if (!m_frequency) { - m_frequency = m_minFrequency; - emit frequencyChanged(m_frequency); - } - } else if (verb == "frequency_step") { - m_frequencyStep = data.value("step").toInt(); - emit frequencyStepChanged(m_frequencyStep); - } - } -} -#endif diff --git a/radio/radio.h b/radio/radio.h deleted file mode 100644 index cfd314c..0000000 --- a/radio/radio.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2018-2020,2022 Konsulko Group - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RADIO_H -#define RADIO_H - -#include -#include - -class Radio : public QObject -{ - Q_OBJECT - Q_PROPERTY(unsigned int band READ band WRITE setBand NOTIFY bandChanged) - Q_PROPERTY(unsigned int amBand READ amBand CONSTANT) - Q_PROPERTY(unsigned int fmBand READ fmBand CONSTANT) - Q_PROPERTY(unsigned int frequency READ frequency WRITE setFrequency NOTIFY frequencyChanged) - Q_PROPERTY(bool playing READ playing NOTIFY playingChanged) - Q_PROPERTY(bool scanning READ scanning NOTIFY scanningChanged) - Q_PROPERTY(unsigned int minFrequency READ minFrequency NOTIFY minFrequencyChanged) - Q_PROPERTY(unsigned int maxFrequency READ maxFrequency NOTIFY maxFrequencyChanged) - Q_PROPERTY(unsigned int frequencyStep READ frequencyStep NOTIFY frequencyStepChanged) - - public: - explicit Radio(QQmlContext *context, QObject * parent = Q_NULLPTR); - virtual ~Radio(); - - unsigned int band() const { return m_band; } - void setBand(int band); - - unsigned int amBand() const { return 0; } - unsigned int fmBand() const { return 1; } - - unsigned int frequency() const { return m_frequency; } - void setFrequency(int frequency); - - unsigned int minFrequency() const { return m_minFrequency; } - unsigned int maxFrequency() const { return m_maxFrequency; } - unsigned int frequencyStep() const { return m_frequencyStep; } - - bool playing() const { return m_playing; } - - bool scanning() const { return m_scanning; } - - // controls - Q_INVOKABLE void start(); - Q_INVOKABLE void stop(); - Q_INVOKABLE void scanForward(); - Q_INVOKABLE void scanBackward(); - Q_INVOKABLE void scanStop(); - - signals: - void bandChanged(int band); - void frequencyChanged(int frequency); - void playingChanged(bool status); - void scanningChanged(bool scanning); - void minFrequencyChanged(int minFrequency); - void maxFrequencyChanged(int maxFrequency); - void frequencyStepChanged(int frequencyStep); - - private: - QQmlContext *m_context; - - unsigned int m_band; - unsigned int m_frequency; - unsigned int m_minFrequency; - unsigned int m_maxFrequency; - unsigned int m_frequencyStep; - bool m_playing; - bool m_scanning; - - void updateFrequencyBandParameters(); -#if 0 - void onConnected(); - void onDisconnected(); - void onMessageReceived(std::shared_ptr msg); - - const QStringList events { - "frequency", - "station_found", - "status", - }; -#endif -}; - -#endif // RADIO_H -- cgit 1.2.3-korg