summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)