diff options
-rw-r--r-- | README.md | 3 | ||||
-rwxr-xr-x | autobuild/agl/autobuild | 128 | ||||
-rwxr-xr-x | autobuild/linux/autobuild | 128 | ||||
-rw-r--r-- | conf.d/CMakeLists.txt | 20 | ||||
-rw-r--r-- | conf.d/cmake/config.cmake | 161 | ||||
-rw-r--r-- | conf.d/wgt/config.xml.in | 33 | ||||
-rw-r--r-- | meson.build (renamed from CMakeLists.txt) | 28 | ||||
-rw-r--r-- | protos/radio.proto | 205 | ||||
-rw-r--r-- | src/CMakeLists.txt (renamed from binding/CMakeLists.txt) | 0 | ||||
-rw-r--r-- | src/RadioImpl.cc | 326 | ||||
-rw-r--r-- | src/RadioImpl.h | 123 | ||||
-rw-r--r-- | src/convenience/convenience.c (renamed from binding/convenience/convenience.c) | 0 | ||||
-rw-r--r-- | src/convenience/convenience.h (renamed from binding/convenience/convenience.h) | 0 | ||||
-rw-r--r-- | src/main-grpc.cc | 83 | ||||
-rw-r--r-- | src/meson.build | 81 | ||||
-rw-r--r-- | src/radio-binding.c (renamed from binding/radio-binding.c) | 0 | ||||
-rw-r--r-- | src/radio_impl.h (renamed from binding/radio_impl.h) | 17 | ||||
-rw-r--r-- | src/radio_impl_kingfisher.c (renamed from binding/radio_impl_kingfisher.c) | 32 | ||||
-rw-r--r-- | src/radio_impl_kingfisher.h (renamed from binding/radio_impl_kingfisher.h) | 0 | ||||
-rw-r--r-- | src/radio_impl_null.c (renamed from binding/radio_impl_null.c) | 18 | ||||
-rw-r--r-- | src/radio_impl_null.h (renamed from binding/radio_impl_null.h) | 0 | ||||
-rw-r--r-- | src/radio_impl_rtlsdr.c (renamed from binding/radio_impl_rtlsdr.c) | 51 | ||||
-rw-r--r-- | src/radio_impl_rtlsdr.h (renamed from binding/radio_impl_rtlsdr.h) | 0 | ||||
-rw-r--r-- | src/radio_impl_tef665x.c (renamed from binding/radio_impl_tef665x.c) | 112 | ||||
-rw-r--r-- | src/radio_impl_tef665x.h (renamed from binding/radio_impl_tef665x.h) | 0 | ||||
-rw-r--r-- | src/radio_output.h (renamed from binding/radio_output.h) | 0 | ||||
-rw-r--r-- | src/radio_output_gstreamer.c (renamed from binding/radio_output_gstreamer.c) | 0 | ||||
-rw-r--r-- | src/rtl_fm.c (renamed from binding/rtl_fm.c) | 0 | ||||
-rw-r--r-- | src/rtl_fm.h (renamed from binding/rtl_fm.h) | 0 | ||||
-rw-r--r-- | src/rtl_fm_helper.c (renamed from binding/rtl_fm_helper.c) | 0 | ||||
-rw-r--r-- | src/tef665x.h (renamed from binding/tef665x.h) | 0 | ||||
-rw-r--r-- | systemd/agl-service-radio.service | 11 | ||||
-rw-r--r-- | systemd/meson.build | 3 |
33 files changed, 962 insertions, 601 deletions
@@ -2,6 +2,9 @@ ## Overview +NOTE: The verbs/events below are out of date, refer to protos/radio.proto for the +new gRPC API until this documentation gets updated. + Radio Service allows tuning of rtl-sdr based devices to radio stations and receive respective audio stream. diff --git a/autobuild/agl/autobuild b/autobuild/agl/autobuild deleted file mode 100755 index 16181b8..0000000 --- a/autobuild/agl/autobuild +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/make -f -# Copyright (C) 2015 - 2018 "IoT.bzh" -# Copyright (C) 2020 Konsulko Group -# Author "Romain Forlot" <romain.forlot@iot.bzh> -# -# 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. - -THISFILE := $(lastword $(MAKEFILE_LIST)) -ROOT_DIR := $(abspath $(dir $(THISFILE))/../..) - -# Build directories -# Note that the debug/test/coverage directories are defined in relation -# to the release directory (BUILD_DIR), this needs to be kept in mind -# if over-riding it and building those widget types, the specific widget -# type variable (e.g. BUILD_DIR_DEBUG) may also need to be specified -# to yield the desired output hierarchy. -BUILD_DIR = $(ROOT_DIR)/build -BUILD_DIR_DEBUG = $(abspath $(BUILD_DIR)/../build-debug) -BUILD_DIR_TEST = $(abspath $(BUILD_DIR)/../build-test) -BUILD_DIR_COVERAGE = $(abspath $(BUILD_DIR)/../build-coverage) - -# Output directory variable for use in pattern rules. -# This is intended for internal use only, hence the explicit override -# definition. -override OUTPUT_DIR = $(BUILD_DIR) - -# Final install directory for widgets -DEST = $(OUTPUT_DIR) - -# Default build type for release/test builds -BUILD_TYPE = RELEASE - -.PHONY: all help update install distclean -.PHONY: clean clean-release clean-debug clean-test clean-coverage clean-all -.PHONY: configure configure-release configure-debug configure-test configure-coverage -.PHONY: build build-release build-debug build-test build-coverage build-all -.PHONY: package package-release package-debug package-test package-coverage package-all - -help: - @echo "List of targets available:" - @echo "" - @echo "- all" - @echo "- help" - @echo "- clean" - @echo "- distclean" - @echo "- configure" - @echo "- build: compilation, link and prepare files for package into a widget" - @echo "- package: output a widget file '*.wgt'" - @echo "- install: install in your $(CMAKE_INSTALL_DIR) directory" - @echo "" - @echo "Usage: ./autobuild/agl/autobuild package DEST=${HOME}/opt" - @echo "Don't use your build dir as DEST as wgt file is generated at this location" - -all: package-all - -# Target specific variable over-rides so static pattern rules can be -# used for the various type-specific targets. - -configure-test build-test package-test clean-test: OUTPUT_DIR = $(BUILD_DIR_TEST) - -configure-coverage build-coverage package-coverage clean-coverage: OUTPUT_DIR = $(BUILD_DIR_COVERAGE) -configure-coverage build-coverage package-coverage: BUILD_TYPE = COVERAGE - -configure-debug build-debug package-debug clean-debug: OUTPUT_DIR = $(BUILD_DIR_DEBUG) -configure-debug build-debug package-debug: BUILD_TYPE = DEBUG - -clean-release clean-test clean-debug clean-coverage: - @if [ -d $(OUTPUT_DIR) ]; then \ - $(MAKE) -C $(OUTPUT_DIR) $(CLEAN_ARGS) clean; \ - else \ - echo Nothing to clean; \ - fi - -clean: clean-release - -clean-all: clean-release clean-test clean-debug clean-coverage - -distclean: clean-all - -configure-release configure-test configure-debug configure-coverage: - @mkdir -p $(OUTPUT_DIR) - @if [ ! -f $(OUTPUT_DIR)/Makefile ]; then \ - (cd $(OUTPUT_DIR) && cmake -S $(ROOT_DIR) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) $(CONFIGURE_ARGS)); \ - fi - -configure: configure-release - -build-release build-debug build-coverage: build-%: configure-% - @cmake --build $(OUTPUT_DIR) $(BUILD_ARGS) --target all - -# Kept for consistency, empty to avoid building everything for test widget -build-test: configure-test - -build: build-release - -build-all: build-release build-debug build-test build-coverage - -package-release package-debug package-coverage: package-%: build-% - @cmake --build $(OUTPUT_DIR) $(PACKAGE_ARGS) --target widget - @if [ "$(abspath $(DEST))" != "$(abspath $(OUTPUT_DIR))" ]; then \ - mkdir -p $(DEST) && cp $(OUTPUT_DIR)/*.wgt $(DEST); \ - fi - -package-test: build-test - @cmake --build $(OUTPUT_DIR) $(PACKAGE_ARGS) --target test_widget - @if [ "$(abspath $(DEST))" != "$(abspath $(OUTPUT_DIR))" ]; then \ - mkdir -p $(DEST) && cp $(OUTPUT_DIR)/*.wgt $(DEST); \ - fi - -package: package-release - -package-all: package-release package-test package-coverage package-debug - -update: configure - @cmake --build $(BUILD_DIR) --target autobuild - -install: build - @cmake --build $(BUILD_DIR) $(INSTALL_ARGS) --target install diff --git a/autobuild/linux/autobuild b/autobuild/linux/autobuild deleted file mode 100755 index 16181b8..0000000 --- a/autobuild/linux/autobuild +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/make -f -# Copyright (C) 2015 - 2018 "IoT.bzh" -# Copyright (C) 2020 Konsulko Group -# Author "Romain Forlot" <romain.forlot@iot.bzh> -# -# 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. - -THISFILE := $(lastword $(MAKEFILE_LIST)) -ROOT_DIR := $(abspath $(dir $(THISFILE))/../..) - -# Build directories -# Note that the debug/test/coverage directories are defined in relation -# to the release directory (BUILD_DIR), this needs to be kept in mind -# if over-riding it and building those widget types, the specific widget -# type variable (e.g. BUILD_DIR_DEBUG) may also need to be specified -# to yield the desired output hierarchy. -BUILD_DIR = $(ROOT_DIR)/build -BUILD_DIR_DEBUG = $(abspath $(BUILD_DIR)/../build-debug) -BUILD_DIR_TEST = $(abspath $(BUILD_DIR)/../build-test) -BUILD_DIR_COVERAGE = $(abspath $(BUILD_DIR)/../build-coverage) - -# Output directory variable for use in pattern rules. -# This is intended for internal use only, hence the explicit override -# definition. -override OUTPUT_DIR = $(BUILD_DIR) - -# Final install directory for widgets -DEST = $(OUTPUT_DIR) - -# Default build type for release/test builds -BUILD_TYPE = RELEASE - -.PHONY: all help update install distclean -.PHONY: clean clean-release clean-debug clean-test clean-coverage clean-all -.PHONY: configure configure-release configure-debug configure-test configure-coverage -.PHONY: build build-release build-debug build-test build-coverage build-all -.PHONY: package package-release package-debug package-test package-coverage package-all - -help: - @echo "List of targets available:" - @echo "" - @echo "- all" - @echo "- help" - @echo "- clean" - @echo "- distclean" - @echo "- configure" - @echo "- build: compilation, link and prepare files for package into a widget" - @echo "- package: output a widget file '*.wgt'" - @echo "- install: install in your $(CMAKE_INSTALL_DIR) directory" - @echo "" - @echo "Usage: ./autobuild/agl/autobuild package DEST=${HOME}/opt" - @echo "Don't use your build dir as DEST as wgt file is generated at this location" - -all: package-all - -# Target specific variable over-rides so static pattern rules can be -# used for the various type-specific targets. - -configure-test build-test package-test clean-test: OUTPUT_DIR = $(BUILD_DIR_TEST) - -configure-coverage build-coverage package-coverage clean-coverage: OUTPUT_DIR = $(BUILD_DIR_COVERAGE) -configure-coverage build-coverage package-coverage: BUILD_TYPE = COVERAGE - -configure-debug build-debug package-debug clean-debug: OUTPUT_DIR = $(BUILD_DIR_DEBUG) -configure-debug build-debug package-debug: BUILD_TYPE = DEBUG - -clean-release clean-test clean-debug clean-coverage: - @if [ -d $(OUTPUT_DIR) ]; then \ - $(MAKE) -C $(OUTPUT_DIR) $(CLEAN_ARGS) clean; \ - else \ - echo Nothing to clean; \ - fi - -clean: clean-release - -clean-all: clean-release clean-test clean-debug clean-coverage - -distclean: clean-all - -configure-release configure-test configure-debug configure-coverage: - @mkdir -p $(OUTPUT_DIR) - @if [ ! -f $(OUTPUT_DIR)/Makefile ]; then \ - (cd $(OUTPUT_DIR) && cmake -S $(ROOT_DIR) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) $(CONFIGURE_ARGS)); \ - fi - -configure: configure-release - -build-release build-debug build-coverage: build-%: configure-% - @cmake --build $(OUTPUT_DIR) $(BUILD_ARGS) --target all - -# Kept for consistency, empty to avoid building everything for test widget -build-test: configure-test - -build: build-release - -build-all: build-release build-debug build-test build-coverage - -package-release package-debug package-coverage: package-%: build-% - @cmake --build $(OUTPUT_DIR) $(PACKAGE_ARGS) --target widget - @if [ "$(abspath $(DEST))" != "$(abspath $(OUTPUT_DIR))" ]; then \ - mkdir -p $(DEST) && cp $(OUTPUT_DIR)/*.wgt $(DEST); \ - fi - -package-test: build-test - @cmake --build $(OUTPUT_DIR) $(PACKAGE_ARGS) --target test_widget - @if [ "$(abspath $(DEST))" != "$(abspath $(OUTPUT_DIR))" ]; then \ - mkdir -p $(DEST) && cp $(OUTPUT_DIR)/*.wgt $(DEST); \ - fi - -package: package-release - -package-all: package-release package-test package-coverage package-debug - -update: configure - @cmake --build $(BUILD_DIR) --target autobuild - -install: build - @cmake --build $(BUILD_DIR) $(INSTALL_ARGS) --target install diff --git a/conf.d/CMakeLists.txt b/conf.d/CMakeLists.txt deleted file mode 100644 index 18f37e3..0000000 --- a/conf.d/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -########################################################################### -# Copyright 2018 IoT.bzh -# -# author: Thierry Bultel <thierry.bultel@iot.bzh> -# -# 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. -########################################################################### - -# ----------------------------------------------------- -PROJECT_SUBDIRS_ADD(project) diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake deleted file mode 100644 index 7e197c1..0000000 --- a/conf.d/cmake/config.cmake +++ /dev/null @@ -1,161 +0,0 @@ -########################################################################### -# Copyright 2015, 2016, 2017 IoT.bzh -# Copyright (C) 2018 Konsulko Group -# -# author: Fulup Ar Foll <fulup@iot.bzh> -# -# 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. -########################################################################### - -# Project Info -# ------------------ -set(PROJECT_NAME agl-service-radio) -set(PROJECT_PRETTY_NAME "Radio binding service") -set(PROJECT_DESCRIPTION "Expose Radio Low Level APIs through AGL Framework") -set(PROJECT_URL https://gerrit.automotivelinux.org/gerrit/admin/repos/apps/agl-service-radio) -set(PROJECT_ICON "icon.png") -set(PROJECT_AUTHOR "Scott Murray") -set(PROJECT_AUTHOR_MAIL "scott.murray@konsulko.com") -set(PROJECT_LICENSE "APL2.0") -set(PROJECT_LANGUAGES,"C") -set(API_NAME "radio") - -# Where are stored the project configuration files -# relative to the root project directory -set(PROJECT_CMAKE_CONF_DIR "conf.d") - -# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain -# but used and must be built and linked. -# set(PROJECT_LIBDIR "libs") - -# Where are stored data for your application. Pictures, static resources must be placed in that folder. -# set(PROJECT_RESOURCES "data") - -# Which directories inspect to find CMakeLists.txt target files -# set(PROJECT_SRC_DIR_PATTERN "*") - -# Compilation Mode (DEBUG, RELEASE) -# ---------------------------------- -set(BUILD_TYPE "RELEASE") - -# Kernel selection if needed. You can choose between a -# mandatory version to impose a minimal version. -# Or check Kernel minimal version and just print a Warning -# about missing features and define a preprocessor variable -# to be used as preprocessor condition in code to disable -# incompatibles features. Preprocessor define is named -# KERNEL_MINIMAL_VERSION_OK. -# -# NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and -# Yocto SDK Kernel version. -# ----------------------------------------------- -#set(kernel_mandatory_version 4.8) - -# Compiler selection if needed. Impose a minimal version. -# ----------------------------------------------- -set (gcc_minimal_version 4.9) - -# PKG_CONFIG required packages -# ----------------------------- -set (PKG_REQUIRED_LIST - json-c - libsystemd>=222 - afb-daemon - glib-2.0 - gobject-2.0 -) - -# Static constante definition -# ----------------------------- -add_compile_options(-DPB_FIELD_16BIT) -add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-pthread>) - -# Customize link option -# ----------------------------- -list (APPEND link_libraries -pthread) - -# --------------------------------------------------------------------- -set(INSTALL_PREFIX $ENV{HOME}/opt) - -# Optional location for config.xml.in -# ----------------------------------- -set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in) - -# Mandatory widget Mimetype specification of the main unit -# -------------------------------------------------------------------------- -# Choose between : -#- text/html : HTML application, -# content.src designates the home page of the application -# -#- application/vnd.agl.native : AGL compatible native, -# content.src designates the relative path of the binary. -# -# - application/vnd.agl.service: AGL service, content.src is not used. -# -#- ***application/x-executable***: Native application, -# content.src designates the relative path of the binary. -# For such application, only security setup is made. -# -set(WIDGET_TYPE application/vnd.agl.service) - -# Mandatory Widget entry point file of the main unit -# -------------------------------------------------------------- -# This is the file that will be executed, loaded, -# at launch time by the application framework. -# -set(WIDGET_ENTRY_POINT lib/libafm-radio-binding.so) - -# Print a helper message when every thing is finished -# ---------------------------------------------------- -set(CLOSING_MESSAGE "Test with: afb-daemon --rootdir=\$\$(pwd)/package --binding=\$\$(pwd)/package/${WIDGET_ENTRY_POINT} --port=1234 --tracereq=common --token=\"1\" --verbose") -set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") - - - -# Optional dependencies order -# --------------------------- -#set(EXTRA_DEPENDENCIES_ORDER) - -# Optional Extra global include path -# ----------------------------------- -#set(EXTRA_INCLUDE_DIRS) - -# Optional extra libraries -# ------------------------- -#set(EXTRA_LINK_LIBRARIES) - -# Optional force binding installation -# ------------------------------------ -# set(BINDINGS_INSTALL_PREFIX PrefixPath ) - -# Optional force binding Linking flag -# ------------------------------------ -# set(BINDINGS_LINK_FLAG LinkOptions ) - -# Optional force package prefix generation, like widget -# ----------------------------------------------------- -# set(PKG_PREFIX DestinationPath) - -# Optional Application Framework security token -# and port use for remote debugging. -#------------------------------------------------------------ -#set(AFB_TOKEN "" CACHE PATH "Default AFB_TOKEN") -#set(AFB_REMPORT "1234" CACHE PATH "Default AFB_TOKEN") - -# This include is mandatory and MUST happens at the end -# of this file, else you expose you to unexpected behavior -# -# This CMake module could be found at the following url: -# https://gerrit.automotivelinux.org/gerrit/#/admin/projects/src/cmake-apps-module -# ----------------------------------------------------------- -include(CMakeAfbTemplates) diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in deleted file mode 100644 index ecd47a9..0000000 --- a/conf.d/wgt/config.xml.in +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<widget xmlns="http://www.w3.org/ns/widgets" id="@PROJECT_NAME@" version="@PROJECT_VERSION@"> - <name>@PROJECT_NAME@</name> - <icon src="@PROJECT_ICON@"/> - <content src="@WIDGET_ENTRY_POINT@" type="@WIDGET_TYPE@"/> - <description>@PROJECT_DESCRIPTION@</description> - <author>@PROJECT_AUTHOR@ <@PROJECT_AUTHOR_MAIL@></author> - <license>@PROJECT_LICENSE@</license> - - <feature name="urn:AGL:widget:required-permission"> - <param name="urn:AGL:permission::public:hidden" value="required" /> - <param name="urn:AGL:permission::public:no-htdocs" value="required" /> - <param name="urn:AGL:permission::system:run-by-default" value="required" /> - <param name="urn:AGL:permission::public:audio" value="required" /> - </feature> - - <feature name="urn:AGL:widget:file-properties"> - <param name="bin/rtl_fm_helper" value="executable" /> - </feature> - - <feature name="urn:AGL:widget:provided-api"> - <param name="radio" value="ws" /> - </feature> - - <feature name="urn:AGL:widget:required-api"> - <param name="signal-composer" value="ws" /> - </feature> - - <feature name="urn:AGL:widget:required-binding"> - <param name="@WIDGET_ENTRY_POINT@" value="local" /> - </feature> - -</widget> diff --git a/CMakeLists.txt b/meson.build index b485097..2277721 100644 --- a/CMakeLists.txt +++ b/meson.build @@ -1,21 +1,35 @@ -########################################################################### -# Copyright 2015, 2016, 2017 IoT.bzh # -# author: Romain Forlot <romain.forlot@iot.bzh> +# Copyright (C) 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 +# 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. -########################################################################### +# + +project ( + 'agl-service-radio', + ['c', 'cpp'], + version : '2.0.0', + license : 'Apache-2.0', + meson_version : '>= 0.46.0', + default_options : + [ + 'warning_level=1', + 'buildtype=debugoptimized', + 'c_std=gnu17', + 'cpp_std=c++17' + ], +) -CMAKE_MINIMUM_REQUIRED(VERSION 3.3) +systemd_dep = dependency('systemd') -include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake) +subdir('src') +subdir('systemd') diff --git a/protos/radio.proto b/protos/radio.proto new file mode 100644 index 0000000..c7ee16f --- /dev/null +++ b/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/binding/CMakeLists.txt b/src/CMakeLists.txt index 560dcaf..560dcaf 100644 --- a/binding/CMakeLists.txt +++ b/src/CMakeLists.txt diff --git a/src/RadioImpl.cc b/src/RadioImpl.cc new file mode 100644 index 0000000..634f066 --- /dev/null +++ b/src/RadioImpl.cc @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2022 Konsulko Group + */ + +#include "RadioImpl.h" + +// C backend implementations +extern "C" { +#include "radio_impl_null.h" +#include "radio_impl_rtlsdr.h" +#include "radio_impl_kingfisher.h" +#include "radio_impl_tef665x.h" +} + +using grpc::StatusCode; +using automotivegradelinux::Band; +using automotivegradelinux::BAND_UNSPECIFIED; +using automotivegradelinux::BAND_AM; +using automotivegradelinux::BAND_FM; +using automotivegradelinux::StereoMode; +using automotivegradelinux::STEREO_MODE_UNSPECIFIED; +using automotivegradelinux::STEREO_MODE_MONO; +using automotivegradelinux::STEREO_MODE_STEREO; +using automotivegradelinux::ScanDirection; +using automotivegradelinux::SCAN_DIRECTION_FORWARD; +using automotivegradelinux::SCAN_DIRECTION_BACKWARD; + +RadioImpl::RadioImpl() +{ +} + +bool RadioImpl::Detect() +{ + // Probe for radio backends + m_radio_impl_ops = &rtlsdr_impl_ops; + int rc = m_radio_impl_ops->probe(); + if(rc != 0) { + // Look for Kingfisher Si4689 + m_radio_impl_ops = &kf_impl_ops; + rc = m_radio_impl_ops->probe(); + } +#if 0 + if(rc != 0) { + m_radio_impl_ops = &tef665x_impl_ops; + rc = m_radio_impl_ops->probe(); + } +#endif + if (rc != 0) { + m_radio_impl_ops = &null_impl_ops; + rc = m_radio_impl_ops->probe(); + } + if (rc != 0) { + // We don't expect the null implementation to fail probe, but just in case... + std::cerr << "No radio device found, exiting" << std::endl; + return false; + } + // Try to initialize detected backend + rc = m_radio_impl_ops->init(); + if(rc < 0) { + std::cerr << m_radio_impl_ops->name << " initialization failed" << std::endl; + return false; + } + std::cout << m_radio_impl_ops->name << "found" << std::endl; + m_radio_impl_ops->set_frequency_callback(FrequencyCallback, this); + m_radio_impl_ops->set_frequency_callback(FrequencyCallback, this); +#if 0 + if(m_radio_impl_ops->set_rds_callback) { + m_radio_impl_ops->set_rds_callback(RDSCallback); + } +#endif + return true; +} + +Status RadioImpl::GetFrequency(ServerContext* context, const GetFrequencyRequest* request, GetFrequencyResponse* response) +{ + response->set_frequency(m_radio_impl_ops->get_frequency()); + return Status::OK; +} + +Status RadioImpl::SetFrequency(ServerContext* context, const SetFrequencyRequest* request, SetFrequencyResponse* response) +{ + radio_band_t band = m_radio_impl_ops->get_band(); + uint32_t min_frequency = m_radio_impl_ops->get_min_frequency(band); + uint32_t max_frequency = m_radio_impl_ops->get_max_frequency(band); + uint32_t step = m_radio_impl_ops->get_frequency_step(band); + + uint32_t frequency = request->frequency(); + if(frequency < min_frequency || + frequency > max_frequency || + (frequency - min_frequency) % step) { + //afb_req_reply(request, NULL, "failed", "Invalid frequency"); + return Status::OK; + } + m_radio_impl_ops->set_frequency(frequency); + return Status::OK; +} + +Status RadioImpl::GetBand(ServerContext* context, const GetBandRequest* request, GetBandResponse* response) +{ + Band band = BAND_UNSPECIFIED; + radio_band_t impl_band = m_radio_impl_ops->get_band(); + + if (impl_band == RADIO_BAND_AM) + band = BAND_AM; + else if (impl_band == RADIO_BAND_FM) + band = BAND_FM; + response->set_band(band); + return Status::OK; +} + +Status RadioImpl::SetBand(ServerContext* context, const SetBandRequest* request, SetBandResponse* response) +{ + radio_band_t impl_band = RADIO_BAND_UNSPECIFIED; + if (request->band() == BAND_AM) + impl_band = RADIO_BAND_AM; + else if (request->band() == BAND_FM) + impl_band = RADIO_BAND_FM; + + if (impl_band != RADIO_BAND_UNSPECIFIED) { + m_radio_impl_ops->set_band(impl_band); + } else { + // FIXME: Indicate error + return Status::OK; + } + + return Status::OK; +} + +Status RadioImpl::GetBandSupported(ServerContext* context, const GetBandSupportedRequest* request, GetBandSupportedResponse* response) +{ + radio_band_t impl_band = RADIO_BAND_UNSPECIFIED; + if (request->band() == BAND_AM) + impl_band = RADIO_BAND_AM; + else if (request->band() == BAND_FM) + impl_band = RADIO_BAND_FM; + + if (impl_band != RADIO_BAND_UNSPECIFIED) + response->set_supported(m_radio_impl_ops->band_supported(impl_band)); + else + response->set_supported(false); + + return Status::OK; +} + +Status RadioImpl::GetBandParameters(ServerContext* context, const GetBandParametersRequest* request, GetBandParametersResponse* response) +{ + radio_band_t impl_band = RADIO_BAND_UNSPECIFIED; + if (request->band() == BAND_AM) + impl_band = RADIO_BAND_AM; + else if (request->band() == BAND_FM) + impl_band = RADIO_BAND_FM; + + if (impl_band != RADIO_BAND_UNSPECIFIED) { + response->set_min(m_radio_impl_ops->get_min_frequency(impl_band)); + response->set_max(m_radio_impl_ops->get_max_frequency(impl_band)); + response->set_step(m_radio_impl_ops->get_frequency_step(impl_band)); + } else { + // FIXME: Indicate error + return Status::OK; + } + return Status::OK; +} + +Status RadioImpl::GetStereoMode(ServerContext* context, const GetStereoModeRequest* request, GetStereoModeResponse* response) +{ + StereoMode mode = STEREO_MODE_UNSPECIFIED; + radio_stereo_mode_t impl_mode = m_radio_impl_ops->get_stereo_mode(); + + if (impl_mode == RADIO_MODE_MONO) + mode = STEREO_MODE_MONO; + else if (impl_mode == RADIO_MODE_STEREO) + mode = STEREO_MODE_STEREO; + response->set_mode(mode); + return Status::OK; +} + +Status RadioImpl::SetStereoMode(ServerContext* context, const SetStereoModeRequest* request, SetStereoModeResponse* response) +{ + radio_stereo_mode_t impl_mode = RADIO_MODE_UNSPECIFIED; + if (request->mode() == STEREO_MODE_MONO) + impl_mode = RADIO_MODE_MONO; + else if (request->mode() == STEREO_MODE_STEREO) + impl_mode = RADIO_MODE_STEREO; + + if (impl_mode != RADIO_MODE_UNSPECIFIED) { + m_radio_impl_ops->set_stereo_mode(impl_mode); + } else { + // FIXME: Indicate error + return Status::OK; + } + return Status::OK; +} + +Status RadioImpl::Start(ServerContext* context, const StartRequest* request, StartResponse* response) +{ + m_radio_impl_ops->set_output(NULL); + m_radio_impl_ops->start(); + m_playing = true; + + StatusResponse status_response; + auto play_status = status_response.mutable_play(); + play_status->set_playing(true); + SendStatusResponse(status_response); + + return Status::OK; +} + +Status RadioImpl::Stop(ServerContext* context, const StopRequest* request, StopResponse* response) +{ + m_radio_impl_ops->stop(); + m_playing = false; + + StatusResponse status_response; + auto play_status = status_response.mutable_play(); + play_status->set_playing(false); + SendStatusResponse(status_response); + + return Status::OK; +} + +Status RadioImpl::ScanStart(ServerContext* context, const ScanStartRequest* request, ScanStartResponse* response) +{ + radio_scan_direction_t impl_direction = RADIO_SCAN_UNSPECIFIED; + if (request->direction() == SCAN_DIRECTION_FORWARD) + impl_direction = RADIO_SCAN_FORWARD; + else if (request->direction() == SCAN_DIRECTION_BACKWARD) + impl_direction = RADIO_SCAN_BACKWARD; + + if (impl_direction != RADIO_SCAN_UNSPECIFIED) { + m_radio_impl_ops->scan_start(impl_direction, ScanCallback, this); + } else { + // FIXME: Indicate error + return Status::OK; + } + + return Status::OK; +} + +Status RadioImpl::ScanStop(ServerContext* context, const ScanStopRequest* request, ScanStopResponse* response) +{ + m_radio_impl_ops->scan_stop(); + return Status::OK; +} + +Status RadioImpl::GetRDS(ServerContext* context, const GetRDSRequest* request, GetRDSResponse* response) +{ + return Status::OK; +} + +Status RadioImpl::GetQuality(ServerContext* context, const GetQualityRequest* request, GetQualityResponse* response) +{ + return Status::OK; +} + +Status RadioImpl::SetAlternativeFrequency(ServerContext* context, const SetAlternativeFrequencyRequest* request, SetAlternativeFrequencyResponse* response) +{ + return Status::OK; +} + +Status RadioImpl::GetStatusEvents(ServerContext* context, const StatusRequest* request, ServerWriter<StatusResponse>* writer) +{ + // Save client information + m_clients_mutex.lock(); + m_clients.push_back(std::pair(context, writer)); + m_clients_mutex.unlock(); + + // For now block until client disconnect / server shutdown + // A switch to the async or callback server APIs might be more elegant than + // holding the thread like this, and may be worth investigating at some point. + std::unique_lock lock(m_done_mutex); + m_done_cv.wait(lock, [context, this]{ return (context->IsCancelled() || m_done); }); + + return Status::OK; +} + +void RadioImpl::SendStatusResponse(StatusResponse &response) +{ + const std::lock_guard<std::mutex> lock(m_clients_mutex); + + if (m_clients.empty()) + return; + + auto it = m_clients.begin(); + while (it != m_clients.end()) { + if (it->first->IsCancelled()) { + // Client has gone away, remove from list + std::cout << "Removing cancelled RPC client!" << std::endl; + it = m_clients.erase(it); + + // We're not exiting, but wake up blocked client RPC handlers so + // the canceled one will clean exit. + // Note that in practice this means the client RPC handler thread + // sticks around until the next status event is sent. + m_done_cv.notify_all(); + + continue; + } else { + it->second->Write(response); + ++it; + } + } +} + + +void RadioImpl::HandleFrequencyEvent(uint32_t frequency) +{ + StatusResponse response; + auto frequency_status = response.mutable_frequency(); + frequency_status->set_frequency(frequency); + SendStatusResponse(response); +} + +void RadioImpl::HandleScanEvent(uint32_t frequency) +{ + StatusResponse response; + auto scan_status = response.mutable_scan(); + scan_status->set_station_found(frequency); + SendStatusResponse(response); +} + +void RadioImpl::HandleRDSEvent(void *rds_data) +{ + // TODO +} + diff --git a/src/RadioImpl.h b/src/RadioImpl.h new file mode 100644 index 0000000..841c72b --- /dev/null +++ b/src/RadioImpl.h @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2022 Konsulko Group + */ + +#ifndef RADIO_IMPL_H +#define RADIO_IMPL_H + +#include <mutex> +#include <list> +#include <condition_variable> + +#include <grpcpp/ext/proto_server_reflection_plugin.h> +#include <grpcpp/grpcpp.h> +#include <grpcpp/health_check_service_interface.h> + +#include "radio.grpc.pb.h" +extern "C" { +#include "radio_impl.h" +} + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::ServerWriter; +using grpc::Status; + +using automotivegradelinux::Radio; +using automotivegradelinux::GetFrequencyRequest; +using automotivegradelinux::GetFrequencyResponse; +using automotivegradelinux::SetFrequencyRequest; +using automotivegradelinux::SetFrequencyResponse; +using automotivegradelinux::GetBandRequest; +using automotivegradelinux::GetBandResponse; +using automotivegradelinux::SetBandRequest; +using automotivegradelinux::SetBandResponse; +using automotivegradelinux::GetBandSupportedRequest; +using automotivegradelinux::GetBandSupportedResponse; +using automotivegradelinux::GetBandParametersRequest; +using automotivegradelinux::GetBandParametersResponse; +using automotivegradelinux::GetStereoModeRequest; +using automotivegradelinux::GetStereoModeResponse; +using automotivegradelinux::SetStereoModeRequest; +using automotivegradelinux::SetStereoModeResponse; +using automotivegradelinux::GetStereoModeRequest; +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::GetRDSRequest; +using automotivegradelinux::GetRDSResponse; +using automotivegradelinux::GetQualityRequest; +using automotivegradelinux::GetQualityResponse; +using automotivegradelinux::SetAlternativeFrequencyRequest; +using automotivegradelinux::SetAlternativeFrequencyResponse; +using automotivegradelinux::StatusRequest; +using automotivegradelinux::StatusResponse; + + +class RadioImpl final : public Radio::Service +{ +public: + explicit RadioImpl(); + + bool Detect(); + + Status GetFrequency(ServerContext* context, const GetFrequencyRequest* request, GetFrequencyResponse* response) override; + Status SetFrequency(ServerContext* context, const SetFrequencyRequest* request, SetFrequencyResponse* response) override; + Status GetBand(ServerContext* context, const GetBandRequest* request, GetBandResponse* response) override; + Status SetBand(ServerContext* context, const SetBandRequest* request, SetBandResponse* response) override; + Status GetBandSupported(ServerContext* context, const GetBandSupportedRequest* request, GetBandSupportedResponse* response) override; + Status GetBandParameters(ServerContext* context, const GetBandParametersRequest* request, GetBandParametersResponse* response) override; + Status GetStereoMode(ServerContext* context, const GetStereoModeRequest* request, GetStereoModeResponse* response) override; + Status SetStereoMode(ServerContext* context, const SetStereoModeRequest* request, SetStereoModeResponse* response) override; + Status Start(ServerContext* context, const StartRequest* request, StartResponse* response) override; + Status Stop(ServerContext* context, const StopRequest* request, StopResponse* response) override; + Status ScanStart(ServerContext* context, const ScanStartRequest* request, ScanStartResponse* response) override; + Status ScanStop(ServerContext* context, const ScanStopRequest* request, ScanStopResponse* response) override; + Status GetRDS(ServerContext* context, const GetRDSRequest* request, GetRDSResponse* response) override; + Status GetQuality(ServerContext* context, const GetQualityRequest* request, GetQualityResponse* response) override; + Status SetAlternativeFrequency(ServerContext* context, const SetAlternativeFrequencyRequest* request, SetAlternativeFrequencyResponse* response) override; + Status GetStatusEvents(ServerContext* context, const StatusRequest* request, ServerWriter<StatusResponse>* writer) override; + + void Shutdown() { m_done = true; m_done_cv.notify_all(); } + + void SendStatusResponse(StatusResponse &response); + + static void FrequencyCallback(uint32_t frequency, void *data) { + if (data) + ((RadioImpl*) data)->HandleFrequencyEvent(frequency); + } + + static void ScanCallback(uint32_t frequency, void *data) { + if (data) + ((RadioImpl*) data)->HandleScanEvent(frequency); + } + + static void RDSCallback(void *rds_data, void *data) { + if (data) + ((RadioImpl*) data)->HandleRDSEvent(rds_data); + } + +private: + void HandleFrequencyEvent(uint32_t frequency); + void HandleScanEvent(uint32_t frequency); + void HandleRDSEvent(void *rds_data); + + std::mutex m_clients_mutex; + std::list<std::pair<ServerContext*, ServerWriter<StatusResponse>*> > m_clients; + + std::mutex m_done_mutex; + std::condition_variable m_done_cv; + bool m_done = false; + + radio_impl_ops_t *m_radio_impl_ops = NULL; + bool m_playing = false; +}; + +#endif // RADIO_IMPL_H diff --git a/binding/convenience/convenience.c b/src/convenience/convenience.c index ae1e24b..ae1e24b 100644 --- a/binding/convenience/convenience.c +++ b/src/convenience/convenience.c diff --git a/binding/convenience/convenience.h b/src/convenience/convenience.h index 1faa2af..1faa2af 100644 --- a/binding/convenience/convenience.h +++ b/src/convenience/convenience.h diff --git a/src/main-grpc.cc b/src/main-grpc.cc new file mode 100644 index 0000000..29e01f1 --- /dev/null +++ b/src/main-grpc.cc @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2023 Konsulko Group + */ + +#include <thread> +#include <chrono> +#include <glib.h> +#include <glib-unix.h> + +#include "RadioImpl.h" + +GMainLoop *main_loop = NULL; + +RadioImpl *g_service = NULL; + +static gboolean quit_cb(gpointer user_data) +{ + g_info("Quitting..."); + + if (main_loop) + g_idle_add(G_SOURCE_FUNC(g_main_loop_quit), main_loop); + else + exit(0); + + return G_SOURCE_REMOVE; +} + +void RunGrpcServer(std::shared_ptr<Server> &server) +{ + // Start server and wait for shutdown + server->Wait(); +} + +int main(int argc, char *argv[]) +{ + main_loop = g_main_loop_new(NULL, FALSE); + + grpc::EnableDefaultHealthCheckService(true); + grpc::reflection::InitProtoReflectionServerBuilderPlugin(); + ServerBuilder builder; + + // Listen on the given address without any authentication mechanism (for now) + std::string server_address("localhost:50053"); + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + + // Register "service" as the instance through which we'll communicate with + // clients. In this case it corresponds to a *synchronous* service. + RadioImpl *service = new RadioImpl(); + if (!service->Detect()) { + exit(1); + } + builder.RegisterService(service); + + // Finally assemble the server. + std::shared_ptr<Server> server(builder.BuildAndStart()); + if (!server) { + exit(1); + } + std::cout << "Server listening on " << server_address << std::endl; + + g_unix_signal_add(SIGTERM, quit_cb, (gpointer) &server); + g_unix_signal_add(SIGINT, quit_cb, (gpointer) &server); + + // Start gRPC API server on its own thread + std::thread grpc_thread(RunGrpcServer, std::ref(server)); + + g_main_loop_run(main_loop); + + // Service implementation may have threads blocked from client streaming + // RPCs, make sure those exit. + service->Shutdown(); + + // Need to set a deadline to avoid blocking on clients doing streaming + // RPC reads + server->Shutdown(std::chrono::system_clock::now() + std::chrono::milliseconds(500)); + + grpc_thread.join(); + + g_main_loop_unref(main_loop); + + return 0; +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..6446066 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,81 @@ +# +# Copyright (C) 2021 Collabora Ltd +# +# 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. +# + +cpp = meson.get_compiler('cpp') +grpcpp_reflection_dep = cpp.find_library('grpc++_reflection') + +gstreamer_dep = dependency('gstreamer-1.0') + +radio_deps = [ + dependency('gobject-2.0'), + dependency('gio-unix-2.0'), + gstreamer_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') + +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') + +# FIXME: debug radio_impl_tef665x.c compile issues and add +executable ( + 'agl-service-radio', + [ + generated_protoc_sources, + generated_grpc_sources, + 'main-grpc.cc', + 'RadioImpl.cc', + 'radio_impl_null.c', + 'radio_impl_kingfisher.c', + 'radio_impl_rtlsdr.c' + ], + dependencies : radio_deps, + install : true, + install_dir : get_option('sbindir') +) + +cc = meson.get_compiler('c') +m_dep = cc.find_library('m', required : false) +helper_deps = [ gstreamer_dep, m_dep, dependency('librtlsdr'), dependency('libusb-1.0') ] +executable ( + 'rtl_fm_helper', + [ + 'rtl_fm_helper.c', + 'radio_output_gstreamer.c', + 'rtl_fm.c', + 'convenience/convenience.c' + ], + dependencies : helper_deps, + install : true, + install_dir : get_option('sbindir') +) diff --git a/binding/radio-binding.c b/src/radio-binding.c index 8b5559c..8b5559c 100644 --- a/binding/radio-binding.c +++ b/src/radio-binding.c diff --git a/binding/radio_impl.h b/src/radio_impl.h index 3e549ac..96909f5 100644 --- a/binding/radio_impl.h +++ b/src/radio_impl.h @@ -20,24 +20,27 @@ #include <stdint.h> typedef enum { - BAND_AM = 0, - BAND_FM + RADIO_BAND_UNSPECIFIED = 0, + RADIO_BAND_AM, + RADIO_BAND_FM } radio_band_t; typedef enum { - SCAN_FORWARD = 0, - SCAN_BACKWARD + RADIO_SCAN_UNSPECIFIED = 0, + RADIO_SCAN_FORWARD, + RADIO_SCAN_BACKWARD } radio_scan_direction_t; typedef void (*radio_scan_callback_t)(uint32_t frequency, void *data); typedef void (*radio_freq_callback_t)(uint32_t frequency, void *data); -typedef void (*radio_rds_callback_t)(void *rds_data); +typedef void (*radio_rds_callback_t)(void *rds_data, void *dat); typedef enum { - MONO = 0, - STEREO + RADIO_MODE_UNSPECIFIED = 0, + RADIO_MODE_MONO, + RADIO_MODE_STEREO } radio_stereo_mode_t; /* diff --git a/binding/radio_impl_kingfisher.c b/src/radio_impl_kingfisher.c index e906140..a0b8449 100644 --- a/binding/radio_impl_kingfisher.c +++ b/src/radio_impl_kingfisher.c @@ -22,11 +22,8 @@ #include <glib.h> #include <fcntl.h> #include <sys/stat.h> -#include <json-c/json.h> #include <gst/gst.h> -#include <afb/afb-binding.h> - #include "radio_impl.h" #define SI_NODE "/sys/firmware/devicetree/base/si468x@0/compatible" @@ -180,7 +177,7 @@ static int kf_init(void) "scan_valid_snr_threshold", &error); if(!error) { - AFB_API_INFO(afbBindingV3root, "Scan valid SNR level set to %d", n); + printf("Scan valid SNR level set to %d", n); scan_valid_snr_threshold = n; } @@ -190,15 +187,15 @@ static int kf_init(void) "scan_valid_rssi_threshold", &error); if(!error) { - AFB_API_INFO(afbBindingV3root, "Scan valid SNR level set to %d", n); + printf("Scan valid SNR level set to %d", n); scan_valid_rssi_threshold = n; } g_key_file_free(conf_file); } - AFB_API_INFO(afbBindingV3root, "Using FM Bandplan: %s", known_fm_band_plans[bandplan].name); - current_frequency = kf_get_min_frequency(BAND_FM); + printf("Using FM Bandplan: %s", known_fm_band_plans[bandplan].name); + current_frequency = kf_get_min_frequency(RADIO_BAND_FM); snprintf(cmd, sizeof(cmd), "%s /dev/i2c-12 0x65 -b fm -p %s -t %d -u %d -c %d", @@ -209,7 +206,7 @@ static int kf_init(void) current_frequency / 1000); rc = system(cmd); if(rc != 0) { - AFB_API_ERROR(afbBindingV3root, "%s failed, rc = %d", SI_CTL, rc); + fprintf(stderr, "%s failed, rc = %d", SI_CTL, rc); return -1; } @@ -223,12 +220,12 @@ static int kf_init(void) "audio/x-raw,format=F32LE,channels=2 ! " "pipewiresink stream-properties=\"p,media.role=Multimedia\""); if(rc >= GST_PIPELINE_LEN) { - AFB_API_ERROR(afbBindingV3root, "pipeline string too long"); + fprintf(stderr, "pipeline string too long"); return -1; } pipeline = gst_parse_launch(gst_pipeline_str, NULL); if(!pipeline) { - AFB_API_ERROR(afbBindingV3root, "pipeline construction failed!"); + fprintf(stderr, "pipeline construction failed!"); return -1; } @@ -330,7 +327,7 @@ done: static radio_band_t kf_get_band(void) { - return BAND_FM; + return RADIO_BAND_FM; } static void kf_set_band(radio_band_t band) @@ -340,7 +337,7 @@ static void kf_set_band(radio_band_t band) static int kf_band_supported(radio_band_t band) { - if(band == BAND_FM) + if(band == RADIO_BAND_FM) return 1; return 0; } @@ -360,10 +357,10 @@ static uint32_t kf_get_frequency_step(radio_band_t band) uint32_t ret = 0; switch (band) { - case BAND_AM: + case RADIO_BAND_AM: ret = 1000; // 1 kHz break; - case BAND_FM: + case RADIO_BAND_FM: ret = known_fm_band_plans[bandplan].step; break; default: @@ -442,17 +439,16 @@ static void kf_scan_start(radio_scan_direction_t direction, snprintf(cmd, SI_CTL_CMDLINE_MAXLEN, "%s /dev/i2c-12 0x65 -l %s", - SI_CTL, direction == SCAN_FORWARD ? "up" : "down"); + SI_CTL, direction == RADIO_SCAN_FORWARD ? "up" : "down"); fp = popen(cmd, "r"); if(fp == NULL) { - AFB_API_ERROR(afbBindingV3root, "Could not run: %s!", cmd); + fprintf(stderr, "Could not run: %s!", cmd); return; } // Look for "Frequency:" in output while(fgets(line, SI_CTL_OUTPUT_MAXLEN, fp) != NULL) { if(strncmp("Frequency:", line, 10) == 0) { new_frequency = atoi(line + 10); - //AFB_API_DEBUG(afbBindingV3root, "%s: got new_frequency = %d", __FUNCTION__, new_frequency); break; } } @@ -493,7 +489,7 @@ static void kf_scan_stop(void) static radio_stereo_mode_t kf_get_stereo_mode(void) { - return STEREO; + return RADIO_MODE_STEREO; } static void kf_set_stereo_mode(radio_stereo_mode_t mode) diff --git a/binding/radio_impl_kingfisher.h b/src/radio_impl_kingfisher.h index 5d4f064..5d4f064 100644 --- a/binding/radio_impl_kingfisher.h +++ b/src/radio_impl_kingfisher.h diff --git a/binding/radio_impl_null.c b/src/radio_impl_null.c index b66c025..60dbab2 100644 --- a/binding/radio_impl_null.c +++ b/src/radio_impl_null.c @@ -25,12 +25,12 @@ #include <stdint.h> #include <stdbool.h> #include <string.h> +#include <strings.h> #include <unistd.h> #include <pthread.h> #include <sys/stat.h> #include <errno.h> #include <glib.h> -#include <afb/afb-binding.h> #include "radio_impl.h" @@ -72,8 +72,6 @@ static int null_init(void) { GKeyFile *conf_file; char *value_str; - char *rootdir; - char *helper_path; if(!present) return -1; @@ -110,7 +108,7 @@ static int null_init(void) } // Start off with minimum bandplan frequency - current_frequency = null_get_min_frequency(BAND_FM); + current_frequency = null_get_min_frequency(RADIO_BAND_FM); initialized = true; null_set_frequency(current_frequency); @@ -149,7 +147,7 @@ static void null_set_frequency_callback(radio_freq_callback_t callback, static radio_band_t null_get_band(void) { // We only support FM - return BAND_FM; + return RADIO_BAND_FM; } static void null_set_band(radio_band_t band) @@ -159,7 +157,7 @@ static void null_set_band(radio_band_t band) static int null_band_supported(radio_band_t band) { - if(band == BAND_FM) + if(band == RADIO_BAND_FM) return 1; return 0; } @@ -179,10 +177,10 @@ static uint32_t null_get_frequency_step(radio_band_t band) uint32_t ret = 0; switch (band) { - case BAND_AM: + case RADIO_BAND_AM: ret = 1000; // 1 kHz break; - case BAND_FM: + case RADIO_BAND_FM: ret = known_fm_band_plans[bandplan].step; break; default: @@ -226,7 +224,7 @@ static void null_scan_start(radio_scan_direction_t direction, // Just go to the next frequency step up or down frequency = current_frequency; - if(direction == SCAN_FORWARD) { + if(direction == RADIO_SCAN_FORWARD) { frequency += known_fm_band_plans[bandplan].step; } else { frequency -= known_fm_band_plans[bandplan].step; @@ -250,7 +248,7 @@ static void null_scan_stop(void) static radio_stereo_mode_t null_get_stereo_mode(void) { // We only support stereo - return STEREO; + return RADIO_MODE_STEREO; } static void null_set_stereo_mode(radio_stereo_mode_t mode) diff --git a/binding/radio_impl_null.h b/src/radio_impl_null.h index 16bd5e6..16bd5e6 100644 --- a/binding/radio_impl_null.h +++ b/src/radio_impl_null.h diff --git a/binding/radio_impl_rtlsdr.c b/src/radio_impl_rtlsdr.c index 2087d10..d978605 100644 --- a/binding/radio_impl_rtlsdr.c +++ b/src/radio_impl_rtlsdr.c @@ -19,12 +19,12 @@ #include <stdint.h> #include <stdbool.h> #include <string.h> +#include <strings.h> #include <unistd.h> #include <pthread.h> #include <sys/stat.h> #include <errno.h> #include <glib.h> -#include <afb/afb-binding.h> #include "radio_impl.h" @@ -131,22 +131,15 @@ static pid_t popen2(char *command, int *in_fd, int *out_fd) static int rtlsdr_probe(void) { - char *rootdir; + const char *bindir = "/usr/sbin"; char *helper_path; - if(present) - return 0; - - rootdir = getenv("AFM_APP_INSTALL_DIR"); - if(!rootdir) - return -1; - // Run helper to detect adapter helper_path = malloc(HELPER_MAX); if(!helper_path) return -ENOMEM; - if(snprintf(helper_path, HELPER_MAX, "%s/bin/%s --detect", rootdir, HELPER_NAME) == HELPER_MAX) { - AFB_API_ERROR(afbBindingV3root, "Could not create command for \"%s --detect\"", HELPER_NAME); + if(snprintf(helper_path, HELPER_MAX, "%s/%s --detect", bindir, HELPER_NAME) == HELPER_MAX) { + fprintf(stderr, "Could not create command for \"%s --detect\"", HELPER_NAME); return -EINVAL; } if(system(helper_path) != 0) { @@ -160,7 +153,7 @@ static int rtlsdr_probe(void) static int rtlsdr_start_helper(void) { - char *rootdir; + const char *bindir = "/usr/sbin"; char *helper_path; static bool helper_started = false; @@ -170,13 +163,9 @@ static int rtlsdr_start_helper(void) if(helper_started) return 0; - rootdir = getenv("AFM_APP_INSTALL_DIR"); - if(!rootdir) - return -1; - if(helper_output) { // Indicate desired output to helper - AFB_API_INFO(afbBindingV3root, "Setting RADIO_OUTPUT=%s", helper_output); + printf("Setting RADIO_OUTPUT=%s", helper_output); setenv("RADIO_OUTPUT", helper_output, 1); } @@ -184,16 +173,16 @@ static int rtlsdr_start_helper(void) helper_path = malloc(HELPER_MAX); if(!helper_path) return -ENOMEM; - if(snprintf(helper_path, PATH_MAX, "%s/bin/%s", rootdir, HELPER_NAME) == PATH_MAX) { - AFB_API_ERROR(afbBindingV3root, "Could not create path to %s", HELPER_NAME); + if(snprintf(helper_path, PATH_MAX, "%s/%s", bindir, HELPER_NAME) == PATH_MAX) { + fprintf(stderr, "Could not create path to %s", HELPER_NAME); return -EINVAL; } helper_pid = popen2(helper_path, &helper_out, &helper_in); if(helper_pid < 0) { - AFB_API_ERROR(afbBindingV3root, "Could not run %s!", HELPER_NAME); + fprintf(stderr, "Could not run %s!", HELPER_NAME); return -1; } - AFB_API_DEBUG(afbBindingV3root, "%s started", HELPER_NAME); + printf("%s started", HELPER_NAME); helper_started = true; free(helper_path); @@ -241,7 +230,7 @@ static int rtlsdr_init(void) } // Start off with minimum bandplan frequency - current_frequency = rtlsdr_get_min_frequency(BAND_FM); + current_frequency = rtlsdr_get_min_frequency(RADIO_BAND_FM); rc = rtlsdr_start_helper(); if(rc != 0) { return rc; @@ -317,7 +306,7 @@ static void rtlsdr_set_frequency_callback(radio_freq_callback_t callback, static radio_band_t rtlsdr_get_band(void) { // We only support FM - return BAND_FM; + return RADIO_BAND_FM; } static void rtlsdr_set_band(radio_band_t band) @@ -327,7 +316,7 @@ static void rtlsdr_set_band(radio_band_t band) static int rtlsdr_band_supported(radio_band_t band) { - if(band == BAND_FM) + if(band == RADIO_BAND_FM) return 1; return 0; } @@ -347,10 +336,10 @@ static uint32_t rtlsdr_get_frequency_step(radio_band_t band) uint32_t ret = 0; switch (band) { - case BAND_AM: + case RADIO_BAND_AM: ret = 1000; // 1 kHz break; - case BAND_FM: + case RADIO_BAND_FM: ret = known_fm_band_plans[bandplan].step; break; default: @@ -375,7 +364,7 @@ static void rtlsdr_start(void) rc = write(helper_in, cmd, strlen(cmd)); pthread_mutex_unlock(&helper_mutex); if (rc < 0) { - AFB_API_ERROR(afbBindingV3root, "Failed to ask \"%s\" to start", HELPER_NAME); + fprintf(stderr, "Failed to ask \"%s\" to start", HELPER_NAME); return; } active = true; @@ -397,7 +386,7 @@ static void rtlsdr_stop(void) rc = write(helper_in, cmd, strlen(cmd)); pthread_mutex_unlock(&helper_mutex); if (rc < 0) { - AFB_API_ERROR(afbBindingV3root, "Failed to ask \"%s\" to stop", HELPER_NAME); + fprintf(stderr, "Failed to ask \"%s\" to stop", HELPER_NAME); return; } active = false; @@ -419,7 +408,7 @@ static void rtlsdr_scan_start(radio_scan_direction_t direction, scanning = true; snprintf(cmd, sizeof(cmd), - "S=%s\n", direction == SCAN_FORWARD ? "UP" : "DOWN"); + "S=%s\n", direction == RADIO_SCAN_FORWARD ? "UP" : "DOWN"); pthread_mutex_lock(&helper_mutex); if(!scanning) { pthread_mutex_unlock(&helper_mutex); @@ -470,13 +459,13 @@ static void rtlsdr_scan_stop(void) rc = write(helper_in, cmd, strlen(cmd)); pthread_mutex_unlock(&helper_mutex); if (rc < 0) - AFB_API_ERROR(afbBindingV3root, "Failed to ask \"%s\" to stop scan", HELPER_NAME); + fprintf(stderr, "Failed to ask \"%s\" to stop scan", HELPER_NAME); } static radio_stereo_mode_t rtlsdr_get_stereo_mode(void) { // We only support stereo - return STEREO; + return RADIO_MODE_STEREO; } static void rtlsdr_set_stereo_mode(radio_stereo_mode_t mode) diff --git a/binding/radio_impl_rtlsdr.h b/src/radio_impl_rtlsdr.h index 6c83338..6c83338 100644 --- a/binding/radio_impl_rtlsdr.h +++ b/src/radio_impl_rtlsdr.h diff --git a/binding/radio_impl_tef665x.c b/src/radio_impl_tef665x.c index 3abcc00..7cca710 100644 --- a/binding/radio_impl_tef665x.c +++ b/src/radio_impl_tef665x.c @@ -36,16 +36,12 @@ #include <error.h> #include <gst/gst.h> #include <time.h> -//#include <json-c/json.h> -//#include <gst/gst.h> - -#include <afb/afb-binding.h> - +#include <gst/gst.h> #include <pthread.h> + #include "radio_impl.h" #include "tef665x.h" - #define I2C_ADDRESS 0x64 #define I2C_DEV "/dev/i2c-3" #define VERSION "0.1" @@ -242,7 +238,7 @@ static int tef665x_get_cmd(int i2c_file_desc, TEF665x_MODULE module, uint8_t cmd temp = (ret == len) ? 1 : 0; _debug("return value", temp); if(temp==0) - AFB_ERROR("Error Number: %d: %s",errno,strerror(errno)); + fprintf(stderr, "Error Number: %d: %s",errno,strerror(errno)); return temp; } @@ -970,20 +966,20 @@ void Extract_Alt_Freqs(uint8_t* buf,rds_data_t *Rds_STU) } else if(buf[Buffer_Index]==205) { - AFB_ERROR("Filler Code"); + fprintf(stderr, "Filler Code"); } else if(buf[Buffer_Index]==224) { - AFB_ERROR("No AF Exists"); + fprintf(stderr, "No AF Exists"); } else if(buf[Buffer_Index]==250) { - AFB_ERROR("An LF/MF Frequency Follows"); + fprintf(stderr, "An LF/MF Frequency Follows"); AlterFreqOffset=144000; } else if(buf[Buffer_Index]>250) { - AFB_WARNING("Alternative Frequency Not Assigned"); + printf("Alternative Frequency Not Assigned"); } } else if(buf[Buffer_Index]>0) @@ -1014,12 +1010,12 @@ void Extract_Alt_Freqs(uint8_t* buf,rds_data_t *Rds_STU) } else { - AFB_WARNING("Alternative Frequency is not defined"); + printf("Alternative Frequency is not defined"); } } else { - AFB_ERROR("Alternative Frequency- Not to be used"); + fprintf(stderr, "Alternative Frequency- Not to be used"); } } } @@ -1039,13 +1035,13 @@ void Check_RDS_Error(uint8_t Errors[]) { for (int i=0;i<4;i++){ if(Errors[i]==1){ - AFB_WARNING("RDS Block %d Reception Error; small error; possible 1 bit reception error detected; data is corrected",i+1); + printf("RDS Block %d Reception Error; small error; possible 1 bit reception error detected; data is corrected",i+1); } else if(Errors[i]==2){ - AFB_WARNING("RDS Block %d Reception Error; large error; theoretical correctable error detected; data is corrected",i+1); + printf("RDS Block %d Reception Error; large error; theoretical correctable error detected; data is corrected",i+1); } else if(Errors[i]==3){ - AFB_ERROR("RDS Block %d Reception Error; uncorrectable error; no data correction possible",i+1); + fprintf(stderr, "RDS Block %d Reception Error; uncorrectable error; no data correction possible",i+1); } } } @@ -1089,7 +1085,7 @@ void *Process_RDS_Words(void* rds_words){ Rds_STU->PICode=Convert8bto16b(&raw_data[2]); } else{ - AFB_ERROR("Error_A=%d",Error_A); + fprintf(stderr, "Error_A=%d",Error_A); } bool GTypeVer=GType0; @@ -1311,17 +1307,17 @@ void *Process_RDS_Words(void* rds_words){ //Group Type 4B else { - AFB_WARNING("Groupe Type 4B are not supported yet"); + printf("Groupe Type 4B are not supported yet"); } } case 8: { - AFB_WARNING("Groupe Type 8A and 8B are not supported yet"); + printf("Groupe Type 8A and 8B are not supported yet"); } case 10: { - AFB_WARNING("Groupe Type 10A and 10B are not supported yet"); + printf("Groupe Type 10A and 10B are not supported yet"); /* if(Error_B == 0){ uint8_t pos = 0; @@ -1342,18 +1338,18 @@ void *Process_RDS_Words(void* rds_words){ } break; default: - AFB_ERROR("Unsupported Group %d",GType); + fprintf(stderr, "Unsupported Group %d",GType); break; } if(!DataAvailable) { - AFB_ERROR("RDS Data is not available"); + fprintf(stderr, "RDS Data is not available"); } if(DataLoss) { - AFB_ERROR("previous data was not read, replaced by newer data"); + fprintf(stderr, "previous data was not read, replaced by newer data"); } if(GroupType == 0) @@ -1367,12 +1363,12 @@ void *Process_RDS_Words(void* rds_words){ if(!SyncStatus) { - AFB_ERROR(" RDS decoder not synchronized; no RDS data found"); + fprintf(stderr, " RDS decoder not synchronized; no RDS data found"); } if(GroupType != GTypeVer) { - AFB_ERROR("Version is not Correct?"); + fprintf(stderr, "Version is not Correct?"); } } @@ -1509,10 +1505,10 @@ static int tef665x_wait_active(uint32_t i2c_file_desc) //usleep(50000); if(SET_SUCCESS == appl_get_operation_status(i2c_file_desc, &status)) { - AFB_INFO("got status", 1); + printf("got status", 1); if((status != eDevTEF665x_Boot_state) && (status != eDevTEF665x_Idle_state)) { - AFB_INFO("active status", 1); + printf("active status", 1); if(SET_SUCCESS == tef665x_para_load(i2c_file_desc)) { @@ -1524,7 +1520,7 @@ static int tef665x_wait_active(uint32_t i2c_file_desc) return 0; } - if(current_band == BAND_FM){ + if(current_band == RADIO_BAND_FM){ FM_tune_to(i2c_file_desc, eAR_TuningAction_Preset, current_fm_frequency / 10000);// tune to min } else { AM_tune_to(i2c_file_desc, eAR_TuningAction_Preset, current_am_frequency / 1000);// tune to min @@ -1733,12 +1729,12 @@ void *Get_RDS_Packets(rds_data_t *StuRDS){ } else{ - AFB_ERROR("RDS is Not Valid0"); + fprintf(stderr, "RDS is Not Valid0"); } } else{ - AFB_ERROR("RDS is Not Valid1"); + fprintf(stderr, "RDS is Not Valid1"); } i2c_init(I2C_DEV, _close, &fd); } @@ -1784,13 +1780,13 @@ void *scan_frequencies(scan_data_t* scan_data){ uint32_t new_freq = 0; uint32_t init_freq = 0; - init_freq = current_band == BAND_FM ? current_fm_frequency : current_am_frequency; + init_freq = current_band == RADIO_BAND_FM ? current_fm_frequency : current_am_frequency; //First Mute Current Frequency tef665x_search_frequency(init_freq); //freq_step will be negative if direction was backward and positive if direction was forward - uint32_t freq_step = tef665x_get_frequency_step(current_band) * (scan_data->direction==SCAN_FORWARD?1:-1); + uint32_t freq_step = tef665x_get_frequency_step(current_band) * (scan_data->direction==RADIO_SCAN_FORWARD?1:-1); //Continue loop until reaching the initial frequency while(init_freq != new_freq) @@ -1804,7 +1800,7 @@ void *scan_frequencies(scan_data_t* scan_data){ break; } - if(current_band==BAND_FM) + if(current_band==RADIO_BAND_FM) { new_freq = current_fm_frequency + freq_step; @@ -1881,7 +1877,7 @@ static char *tef665x_get_rds_info(void) //If Getting RDS Result wasn't already started, Start it now if(pthread_mutex_trylock(&RDS_Mutex) == 0) { - AFB_DEBUG("Create the thread."); + //AFB_DEBUG("Create the thread."); pthread_create(&rds_thread, NULL,Get_RDS_Packets ,(void *) (&RDS_Message)); } @@ -1955,7 +1951,7 @@ static station_quality_t *tef665x_get_quality_info(void) uint8_t data[14]; int ret = i2c_init(I2C_DEV, _open, &i2c_file_desc); - if(current_band==BAND_FM) + if(current_band==RADIO_BAND_FM) { ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM, TEF665X_Cmd_Get_Quality_Data, @@ -1982,7 +1978,7 @@ static station_quality_t *tef665x_get_quality_info(void) * @brief Start Scan * * @param radio_scan_direction_t direction which is the scan direction and can be - * SCAN_FORWARD or SCAN_BACKWARD + * RADIO_SCAN_FORWARD or RADIO_SCAN_BACKWARD * @param radio_scan_callback_t callback which is the callback for sending result of search to * station_found ecent subscribers * @return void @@ -2006,12 +2002,12 @@ static void tef665x_scan_start(radio_scan_direction_t direction, Clear_RDS_Data(&RDS_Message); usleep(10000); - AFB_DEBUG("check Mutex Condition"); + //AFB_DEBUG("check Mutex Condition"); //check if is there any activated search if(pthread_mutex_trylock(&scan_mutex)==0&&!scanning) { - AFB_DEBUG("Start Scanning..."); + //AFB_DEBUG("Start Scanning..."); inputs=malloc(sizeof(*inputs)); if(!inputs) @@ -2038,7 +2034,7 @@ static void tef665x_scan_stop(void) while(scanning) { usleep(100); - AFB_DEBUG(" Wait for unlocking scan Thread"); + //AFB_DEBUG(" Wait for unlocking scan Thread"); } } @@ -2060,7 +2056,7 @@ radio_stereo_mode_t tef665x_get_stereo_mode(void) uint32_t i2c_file_desc = 0; int ret = i2c_init(I2C_DEV, _open, &i2c_file_desc); uint8_t data[2]; - if(current_band==BAND_FM){ + if(current_band==RADIO_BAND_FM){ ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM, TEF665X_Cmd_Get_Signal_Status, data, sizeof(data)); @@ -2071,7 +2067,7 @@ radio_stereo_mode_t tef665x_get_stereo_mode(void) data, sizeof(data)); } i2c_init(I2C_DEV, _close, &i2c_file_desc); - return data[0]>>7 ==1 ? STEREO:MONO; + return data[0]>>7 ==1 ? RADIO_MODE_STEREO:RADIO_MODE_MONO; } static void tef665x_stop(void) @@ -2104,14 +2100,14 @@ static int tef665x_probe() rc = i2c_init(I2C_DEV, _open, &file_desc); if(rc < 0) { - AFB_NOTICE("tef665x not present"); + fprintf(stderr, "tef665x not present"); return -1; } _debug("file_desc= ", file_desc); rc = appl_get_identification(file_desc); if(rc != 1){ - AFB_ERROR("no tef665x!"); + fprintf(stderr, "no tef665x!"); return -1; } @@ -2133,7 +2129,7 @@ static int tef665x_init() current_am_frequency = known_am_band_plans[am_bandplan].min; current_fm_frequency = known_fm_band_plans[fm_bandplan].min; - current_band = BAND_AM; + current_band = RADIO_BAND_AM; radio_powerSwitch(file_desc, 1); @@ -2151,14 +2147,14 @@ static int tef665x_init() ! pipewiresink stream-properties=\"p,media.role=Multimedia\""); if(rc >= GST_PIPELINE_LEN) { - AFB_ERROR("pipeline string too long"); + fprintf(stderr, "pipeline string too long"); return -1; } printf("pipeline: , %s\n", gst_pipeline_str); pipeline = gst_parse_launch(gst_pipeline_str, NULL); if(!pipeline) { - AFB_ERROR("pipeline construction failed!"); + fprintf(stderr, "pipeline construction failed!"); return -1; } @@ -2207,7 +2203,7 @@ static void tef665x_set_band(radio_band_t band) _debug("i2c_init ret value", ret); - if(band == BAND_FM){ + if(band == RADIO_BAND_FM){ current_band = band; FM_tune_to(fd, eAR_TuningAction_Preset, current_fm_frequency / 10000); } else { @@ -2222,7 +2218,7 @@ static void tef665x_set_band(radio_band_t band) static uint32_t tef665x_get_frequency(void) { - if(current_band == BAND_FM){ + if(current_band == RADIO_BAND_FM){ return current_fm_frequency; } else { return current_am_frequency; @@ -2234,7 +2230,7 @@ static void tef665x_set_alternative_frequency(uint32_t frequency) uint32_t fd = 0; int ret = i2c_init(I2C_DEV, _open, &fd); - if(current_band == BAND_FM) + if(current_band == RADIO_BAND_FM) { FM_tune_to(fd, eAR_TuningAction_AF_Update, frequency / 10000); } @@ -2252,7 +2248,7 @@ static void tef665x_set_frequency(uint32_t frequency) if(scanning) return; - if(current_band == BAND_FM) { + if(current_band == RADIO_BAND_FM) { if(frequency < known_fm_band_plans[fm_bandplan].min || frequency > known_fm_band_plans[fm_bandplan].max ) { _debug("invalid FM frequency", frequency); @@ -2268,7 +2264,7 @@ static void tef665x_set_frequency(uint32_t frequency) int ret = i2c_init(I2C_DEV, _open, &fd); - if(current_band == BAND_FM){ + if(current_band == RADIO_BAND_FM){ current_fm_frequency = frequency; _debug("frequency set to FM :", frequency); FM_tune_to(fd, eAR_TuningAction_Preset, frequency / 10000); @@ -2286,7 +2282,7 @@ static void tef665x_set_frequency(uint32_t frequency) } //Start RDS if the band was FM - if(current_band==BAND_FM){ + if(current_band==RADIO_BAND_FM){ //Unlock Mutex pthread_mutex_unlock (&RDS_Mutex); @@ -2314,7 +2310,7 @@ static void tef665x_search_frequency(uint32_t frequency) { uint32_t fd = 0; int ret = i2c_init(I2C_DEV, _open, &fd); - if(current_band == BAND_FM) + if(current_band == RADIO_BAND_FM) { current_fm_frequency = frequency; _debug("frequency set to FM :", frequency); @@ -2338,14 +2334,14 @@ static void tef665x_search_frequency(uint32_t frequency) static int tef665x_band_supported(radio_band_t band) { - if(band == BAND_FM || band == BAND_AM) + if(band == RADIO_BAND_FM || band == RADIO_BAND_AM) return 1; return 0; } static uint32_t tef665x_get_min_frequency(radio_band_t band) { - if(band == BAND_FM) { + if(band == RADIO_BAND_FM) { return known_fm_band_plans[fm_bandplan].min; } else { return known_am_band_plans[am_bandplan].min; @@ -2354,7 +2350,7 @@ static uint32_t tef665x_get_min_frequency(radio_band_t band) static uint32_t tef665x_get_max_frequency(radio_band_t band) { - if(band == BAND_FM) { + if(band == RADIO_BAND_FM) { return known_fm_band_plans[fm_bandplan].max; } else { return known_am_band_plans[am_bandplan].max; @@ -2366,10 +2362,10 @@ static uint32_t tef665x_get_frequency_step(radio_band_t band) uint32_t ret = 0; switch (band) { - case BAND_AM: + case RADIO_BAND_AM: ret = known_am_band_plans[am_bandplan].step; break; - case BAND_FM: + case RADIO_BAND_FM: ret = known_fm_band_plans[fm_bandplan].step; break; default: diff --git a/binding/radio_impl_tef665x.h b/src/radio_impl_tef665x.h index a95fd99..a95fd99 100644 --- a/binding/radio_impl_tef665x.h +++ b/src/radio_impl_tef665x.h diff --git a/binding/radio_output.h b/src/radio_output.h index bfa13cd..bfa13cd 100644 --- a/binding/radio_output.h +++ b/src/radio_output.h diff --git a/binding/radio_output_gstreamer.c b/src/radio_output_gstreamer.c index e098d2d..e098d2d 100644 --- a/binding/radio_output_gstreamer.c +++ b/src/radio_output_gstreamer.c diff --git a/binding/rtl_fm.c b/src/rtl_fm.c index cfbd487..cfbd487 100644 --- a/binding/rtl_fm.c +++ b/src/rtl_fm.c diff --git a/binding/rtl_fm.h b/src/rtl_fm.h index f5b2a86..f5b2a86 100644 --- a/binding/rtl_fm.h +++ b/src/rtl_fm.h diff --git a/binding/rtl_fm_helper.c b/src/rtl_fm_helper.c index c7df4b9..c7df4b9 100644 --- a/binding/rtl_fm_helper.c +++ b/src/rtl_fm_helper.c diff --git a/binding/tef665x.h b/src/tef665x.h index 10874e8..10874e8 100644 --- a/binding/tef665x.h +++ b/src/tef665x.h diff --git a/systemd/agl-service-radio.service b/systemd/agl-service-radio.service new file mode 100644 index 0000000..a5ea8aa --- /dev/null +++ b/systemd/agl-service-radio.service @@ -0,0 +1,11 @@ +[Unit] +Requires=network.target +After=network.target + +[Service] +Type=simple +ExecStart=/usr/sbin/agl-service-radio +Restart=on-failure + +[Install] +WantedBy=default.target diff --git a/systemd/meson.build b/systemd/meson.build new file mode 100644 index 0000000..8d7a4c3 --- /dev/null +++ b/systemd/meson.build @@ -0,0 +1,3 @@ +systemd_system_unit_dir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir') + +install_data('agl-service-radio.service', install_dir : systemd_system_unit_dir) |