aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Murray <scott.murray@konsulko.com>2023-01-03 00:51:50 -0500
committerScott Murray <scott.murray@konsulko.com>2023-01-03 00:57:12 -0500
commitdd23c157bdba1b25bbb50cdb99a60aa597735f43 (patch)
tree65c6f192bfc2f685e50d059d1e4ffb87fe7414f6
parente057ee1ea2af4ff1d8121a0857bd9fd63181fba2 (diff)
Repurpose into gRPC serviceneedlefish
Repurpose repository into a spiritual successor of the previous binding. The backend code is retained behind a new gRPC API defined in protos/radio.proto. The simpler synchronous gRPC API had been used for expediency, this may warrant revisiting to rework into an async or callback API based server instead. As well, authentication has been left until some consensus on an approach can be worked out. Bug-AGL: SPEC-4665 Signed-off-by: Scott Murray <scott.murray@konsulko.com> Change-Id: I28b122ce6e0ecfc7504aa08b90394cb1b9e22976
-rw-r--r--README.md3
-rwxr-xr-xautobuild/agl/autobuild128
-rwxr-xr-xautobuild/linux/autobuild128
-rw-r--r--conf.d/CMakeLists.txt20
-rw-r--r--conf.d/cmake/config.cmake161
-rw-r--r--conf.d/wgt/config.xml.in33
-rw-r--r--meson.build (renamed from CMakeLists.txt)28
-rw-r--r--protos/radio.proto205
-rw-r--r--src/CMakeLists.txt (renamed from binding/CMakeLists.txt)0
-rw-r--r--src/RadioImpl.cc326
-rw-r--r--src/RadioImpl.h123
-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.cc83
-rw-r--r--src/meson.build81
-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.service11
-rw-r--r--systemd/meson.build3
33 files changed, 962 insertions, 601 deletions
diff --git a/README.md b/README.md
index 79032ad..1c8841a 100644
--- a/README.md
+++ b/README.md
@@ -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@ &lt;@PROJECT_AUTHOR_MAIL@&gt;</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)