summaryrefslogtreecommitdiffstats
path: root/meta-agl-bsp/meta-rcar-gen3-adas/recipes-bsp/si-tools/files/si-tools-fm-improvements.patch
blob: 9bbccadd352c9871fb35b16f7996b08dac5adfe8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
FM configuration improvements

Changes include:
- Add command-line option for selecting FM band plan.  The default
  band plan is US / Canada.
- Add command-line options for setting FM scanning valid SNR and RSSI
  thresholds to allow tweaking sensitivity in poor radio environments.
- Increased seeking scan timeout to 3 seconds, which seems to improve
  behavior in poor radio environments where powerful stations may be
  far apart.
- Removed explicit setting of FM_SOFTMUTE_SNR_LIMITS, as it seemed
  like it might be resulting in odd muting behavior when scanning.
- Changed initial FM frequency if not specified to the minimum of the
  band plan.

Signed-off-by: Scott Murray <scott.murray@konsulko.com>

diff --git a/si46xx.h b/si46xx.h
index 172ea8b..c32fca4 100644
--- a/si46xx.h
+++ b/si46xx.h
@@ -83,6 +83,7 @@
 #define SI46XX_PIN_CONFIG_ENABLE 0x0800
 #define SI46XX_FM_SEEK_BAND_BOTTOM 0x3100
 #define SI46XX_FM_SEEK_BAND_TOP 0x3101
+#define SI46XX_FM_SEEK_FREQUENCY_SPACING 0x3102
 #define SI46XX_FM_VALID_MAX_TUNE_ERROR 0x3200
 #define SI46XX_FM_VALID_RSSI_TIME 0x3201
 #define SI46XX_FM_VALID_RSSI_THRESHOLD 0x3202
@@ -150,7 +151,7 @@
 #define MAX_SERVICES 32
 #define MAX_COMPONENTS 15
 
-#define TIMEOUT_SEEK	2000	/* mS = 2S */
+#define TIMEOUT_SEEK	3000	/* mS = 3S */
 #define TIMEOUT_TUNE	500	/* mS = .5S */
 
 struct dab_service_t{
diff --git a/si_ctl.c b/si_ctl.c
index 59dfaf2..f168218 100644
--- a/si_ctl.c
+++ b/si_ctl.c
@@ -101,6 +101,26 @@ uint32_t frequency_list_ch[] = {	CHAN_12A,
 					CHAN_9D,
 					CHAN_8B};
 
+// Structure to describe FM band plans, all values in Hz.
+typedef struct {
+	char *name;
+	uint32_t min;
+	uint32_t max;
+	uint32_t step;
+} fm_band_plan_t;
+
+static fm_band_plan_t known_fm_band_plans[5] = {
+	{ .name = "US", .min = 87900000, .max = 107900000, .step = 200000 },
+	{ .name = "JP", .min = 76000000, .max = 95000000, .step = 100000 },
+	{ .name = "EU", .min = 87500000, .max = 108000000, .step = 50000 },
+	{ .name = "ITU-1", .min = 87500000, .max = 108000000, .step = 50000 },
+	{ .name = "ITU-2", .min = 87900000, .max = 107900000, .step = 50000 }
+};
+
+static unsigned int fm_band_plan;
+static int fm_snr_threshold = 128;
+static int fm_rssi_threshold = 128;
+
 int init_am(int offset)
 {
 	int ret;
@@ -160,12 +180,32 @@ int init_fm(int offset)
 	 * enable I2S output
 	 */
 	si46xx_set_property(SI46XX_PIN_CONFIG_ENABLE, 0x0003);
-	//si46xx_set_property(SI46XX_FM_VALID_RSSI_THRESHOLD,0x0000);
-	//si46xx_set_property(SI46XX_FM_VALID_SNR_THRESHOLD,0x0000);
-	si46xx_set_property(SI46XX_FM_SOFTMUTE_SNR_LIMITS, 0x0000); // set the SNR limits for soft mute attenuation
+	//si46xx_set_property(SI46XX_FM_SOFTMUTE_SNR_LIMITS, 0x0000); // set the SNR limits for soft mute attenuation
 	si46xx_set_property(SI46XX_FM_TUNE_FE_CFG, 0x0000); // front end switch open
-	si46xx_set_property(SI46XX_FM_SEEK_BAND_BOTTOM, 88000 / 10);
-	si46xx_set_property(SI46XX_FM_SEEK_BAND_TOP, 108000 / 10);
+
+	//si46xx_set_property(SI46XX_FM_SEEK_BAND_BOTTOM, 88000 / 10);
+	//si46xx_set_property(SI46XX_FM_SEEK_BAND_TOP, 108000 / 10);
+	if (verbose)
+		fprintf(stderr, "Using FM Bandplan: %s\n", known_fm_band_plans[fm_band_plan].name);
+	si46xx_set_property(SI46XX_FM_SEEK_BAND_BOTTOM, known_fm_band_plans[fm_band_plan].min / 10000);
+	si46xx_set_property(SI46XX_FM_SEEK_BAND_TOP, known_fm_band_plans[fm_band_plan].max / 10000);
+	if (verbose)
+		fprintf(stderr, "Using FM band: %d - %d, %d spacing\n",
+			known_fm_band_plans[fm_band_plan].min / 10000,
+			known_fm_band_plans[fm_band_plan].max / 10000,
+			known_fm_band_plans[fm_band_plan].step / 10000);
+	si46xx_set_property(SI46XX_FM_SEEK_FREQUENCY_SPACING, known_fm_band_plans[fm_band_plan].step / 10000);
+	if (fm_snr_threshold != 128) {
+		if (verbose)
+			fprintf(stderr, "Setting FM valid SNR threshold to %d dB\n", fm_snr_threshold);
+		si46xx_set_property(SI46XX_FM_VALID_SNR_THRESHOLD, fm_snr_threshold);
+	}
+	if (fm_rssi_threshold != 128) {
+		if (verbose)
+			fprintf(stderr, "Setting FM valid RSSI threshold to %d dB\n", fm_rssi_threshold);
+		si46xx_set_property(SI46XX_FM_VALID_RSSI_THRESHOLD, fm_rssi_threshold);
+	}
+
 	/*
 	 * rate
 	 */
@@ -190,6 +230,7 @@ int init_fm(int offset)
 
 	return 0;
 }
+
 int init_dab(int offset)
 {
 	int ret;
@@ -245,6 +286,10 @@ int output_help(char *prog_name)
 	printf("  -l up|down     FM/AM seek next station\n");
 	printf("  -d             FM/AM RSQ status\n");
 	printf("  -m             FM rds status\n");
+	printf("Common FM:\n");
+	printf("  -p bandplan    FM bandplan (us, jp, eu, itu-1, itu-2\n");
+	printf("  -t SNR         FM scan valid SNR threshold (-127 to 127 dB)\n");
+	printf("  -u RSSI        FM scan valid RSSI threshold (-127 to 127 dBuV)\n");
 	printf("DAB only:\n");
 	printf("  -e             dab status\n");
 	printf("  -f service     start service of dab service list\n");
@@ -354,6 +399,7 @@ int main(int argc, char **argv)
 	int offset = - 1;
 	int mode;
 	int tmp;
+	unsigned int i;
 	struct dab_digrad_status_t dab_digrad_status;
 	bool init = false;
 	bool seek_up = false;
@@ -374,7 +420,7 @@ int main(int argc, char **argv)
 
 	optind = 0;
 	while (optind < argc) {
-		if ((c = getopt(argc, argv, "a:b:c:def:ghi:j:k:l:mnosv")) != -1) {
+		if ((c = getopt(argc, argv, "a:b:c:def:ghi:j:k:l:mnop:st:u:v")) != -1) {
 			switch(c){
 			/* init */
 			case 'a':
@@ -422,6 +468,31 @@ int main(int argc, char **argv)
 			case 'c':
 				frequency = atoi(optarg);
 				break;
+			/* FM */
+			case 'p':
+				for(i = 0;
+				    i < sizeof(known_fm_band_plans) / sizeof(fm_band_plan_t);
+				    i++) {
+					if(!strcasecmp(optarg, known_fm_band_plans[i].name)) {
+						fm_band_plan = i;
+						break;
+					}
+				}
+				if(i >= (sizeof(known_fm_band_plans) / sizeof(fm_band_plan_t))) {
+					printf("Invalid mode: %s\n", optarg);
+					return -EINVAL;
+				}
+				break;
+			case 't':
+				fm_snr_threshold = atoi(optarg);
+				if(fm_snr_threshold < -128 || fm_snr_threshold > 127)
+					fm_snr_threshold = 128; // use firmware default
+				break;
+			case 'u':
+				fm_rssi_threshold = atoi(optarg);
+				if(fm_rssi_threshold < -128 || fm_rssi_threshold > 127)
+					fm_rssi_threshold = 128; // use firmware default
+				break;
 			/* DAB stuff. TODO: rework */
 			case 'e':
 				si46xx_dab_digrad_status(&dab_digrad_status);
@@ -473,7 +544,7 @@ int main(int argc, char **argv)
 			case SI46XX_MODE_FM:
 				ret = init_fm(offset);
 				if (frequency < 0)
-					frequency = 105500;
+					frequency = known_fm_band_plans[fm_band_plan].min / 1000;
 			break;
 			case SI46XX_MODE_AM:
 				ret = init_am(offset);
n> # stage (version 0.3.22), these are just experiments, not # actual features. # # libcamera support currently does not build successfully. # # systemd user service files are disabled because per-user # PipeWire instances aren't really something that makes # much sense in an embedded environment. A system-wide # instance does. # # manpage generation requires xmltoman, which is not available. # # Dont build any session managers along with pipewire # wireplumber is the session manger used in AGL and it will # be build in a different recipe # EXTRA_OEMESON += " \ -Daudiotestsrc=enabled \ -Devl=disabled \ -Dsystemd-user-service=disabled \ -Dtests=disabled \ -Dudevrulesdir=${nonarch_base_libdir}/udev/rules.d/ \ -Dvideotestsrc=enabled \ -Dffmpeg=disabled \ -Dvulkan=disabled \ -Dlibcamera=disabled \ -Dman=disabled \ -Dsession-managers=[] \ " PACKAGECONFIG ??= "\ ${@bb.utils.contains('DISTRO_FEATURES', 'bluetooth', 'bluez', '', d)} \ ${@bb.utils.filter('DISTRO_FEATURES', 'alsa systemd', d)} \ gstreamer jack v4l2 \ " # "jack" and "pipewire-jack" packageconfigs cannot be both enabled, # since "jack" imports libjack, and "pipewire-jack" generates # libjack.so* files, thus colliding with the libpack package. This # is why these two are marked in their respective packageconfigs # as being in conflict. PACKAGECONFIG[alsa] = "-Dalsa=enabled,-Dalsa=disabled,alsa-lib udev" PACKAGECONFIG[bluez] = "-Dbluez5=enabled,-Dbluez5=disabled,bluez5 sbc" PACKAGECONFIG[docs] = "-Ddocs=enabled,-Ddocs=disabled,doxygen-native" PACKAGECONFIG[gstreamer] = "-Dgstreamer=enabled,-Dgstreamer=disabled,glib-2.0 gstreamer1.0 gstreamer1.0-plugins-base" PACKAGECONFIG[jack] = "-Djack=enabled,-Djack=disabled,jack,,,pipewire-jack" PACKAGECONFIG[sdl2] = "-Dsdl2=enabled,-Dsdl2=disabled,virtual/libsdl2" PACKAGECONFIG[sndfile] = "-Dsndfile=enabled,-Dsndfile=disabled,libsndfile1" PACKAGECONFIG[systemd] = "-Dsystemd=enabled -Dsystemd-system-service=enabled ,-Dsystemd=disabled -Dsystemd-system-service=disabled,systemd" PACKAGECONFIG[v4l2] = "-Dv4l2=enabled,-Dv4l2=disabled,udev" PACKAGECONFIG[pipewire-alsa] = "-Dpipewire-alsa=enabled,-Dpipewire-alsa=disabled,alsa-lib" PACKAGECONFIG[pipewire-jack] = "-Dpipewire-jack=enabled -Dlibjack-path=${libdir}/${PW_MODULE_SUBDIR}/jack,-Dpipewire-jack=disabled,jack,,,jack" PACKAGECONFIG[pipewire-v4l2] = "-Dpipewire-v4l2=enabled -Dpipewire-v4l2=${libdir}/${PW_MODULE_SUBDIR}/v4l2,-Dpipewire-v4l2=disabled,v4l2" PACKAGESPLITFUNCS:prepend = " split_dynamic_packages " PACKAGESPLITFUNCS:append = " set_dynamic_metapkg_rdepends " PACKAGESPLITFUNCS:append = " fixup_dynamic_pkg_licenses " SPA_SUBDIR = "spa-0.2" PW_MODULE_SUBDIR = "pipewire-0.3" remove_unused_installed_files() { # jack.conf is used by pipewire-jack (not the JACK SPA plugin). # Remove it if pipewire-jack is not built to avoid creating the # pipewire-jack package. if ${@bb.utils.contains('PACKAGECONFIG', 'pipewire-jack', 'false', 'true', d)}; then rm -f "${D}${datadir}/pipewire/jack.conf" fi } do_install[postfuncs] += "remove_unused_installed_files" python fixup_dynamic_pkg_licenses () { #dynamic packages inherit currently whatever is specified in LICENSE (thus multiple) packages = (d.getVar('PACKAGES') or "").split() for pkg in packages: # we manually assign the LICENSES here to cover all packages (even dynamically created ones) d.setVar("LICENSE:" + pkg ,"MIT") # next handle special cases # ==> LICENSE:${PN}-spa-plugins-alsa = "LGPL-2.1-or-later" if "pipewire-spa-plugins-alsa" in pkg: d.setVar("LICENSE:pipewire-spa-plugins-alsa", "LGPL-2.1-or-later") # ==> LICENSE:${PN}-alsa-card-profile = "LGPL-2.1-or-later" if "pipewire-alsa-card-profile" in pkg: d.setVar("LICENSE:pipewire-alsa-card-profile", "LGPL-2.1-or-later") # ==> LICENSE:${PN}-jack = "GPL-2.0-only" if "pipewire-jack" in pkg: d.setVar("LICENSE:pipewire-jack", "GPL-2.0-only") } python split_dynamic_packages () { # Create packages for each SPA plugin. These plugins are located # in individual subdirectories, so a recursive search is needed. spa_libdir = d.expand('${libdir}/${SPA_SUBDIR}') do_split_packages(d, spa_libdir, r'^libspa-(.*)\.so$', d.expand('${PN}-spa-plugins-%s'), 'PipeWire SPA plugin for %s', extra_depends='', recursive=True) # Create packages for each PipeWire module. pw_module_libdir = d.expand('${libdir}/${PW_MODULE_SUBDIR}') do_split_packages(d, pw_module_libdir, r'^libpipewire-module-(.*)\.so$', d.expand('${PN}-modules-%s'), 'PipeWire %s module', extra_depends='', recursive=False) } python set_dynamic_metapkg_rdepends () { import os import oe.utils # Go through all generated SPA plugin and PipeWire module packages # (excluding the main package and the -meta package itself) and # add them to the -meta package as RDEPENDS. base_pn = d.getVar('PN') spa_pn = base_pn + '-spa-plugins' spa_metapkg = spa_pn + '-meta' pw_module_pn = base_pn + '-modules' pw_module_metapkg = pw_module_pn + '-meta' d.setVar('ALLOW_EMPTY:' + spa_metapkg, "1") d.setVar('FILES:' + spa_metapkg, "") d.setVar('ALLOW_EMPTY:' + pw_module_metapkg, "1") d.setVar('FILES:' + pw_module_metapkg, "") blacklist = [ spa_pn, spa_metapkg, pw_module_pn, pw_module_metapkg ] spa_metapkg_rdepends = [] pw_module_metapkg_rdepends = [] pkgdest = d.getVar('PKGDEST') for pkg in oe.utils.packages_filter_out_system(d): if pkg in blacklist: continue is_spa_pkg = pkg.startswith(spa_pn) is_pw_module_pkg = pkg.startswith(pw_module_pn) if not is_spa_pkg and not is_pw_module_pkg: continue if pkg in spa_metapkg_rdepends or pkg in pw_module_metapkg_rdepends: continue # See if the package is empty by looking at the contents of its # PKGDEST subdirectory. If this subdirectory is empty, then then # package is empty as well. Empty packages do not get added to # the meta package's RDEPENDS. pkgdir = os.path.join(pkgdest, pkg) if os.path.exists(pkgdir): dir_contents = os.listdir(pkgdir) or [] else: dir_contents = [] is_empty = len(dir_contents) == 0 if not is_empty: if is_spa_pkg: spa_metapkg_rdepends.append(pkg) if is_pw_module_pkg: pw_module_metapkg_rdepends.append(pkg) d.setVar('RDEPENDS:' + spa_metapkg, ' '.join(spa_metapkg_rdepends)) d.setVar('DESCRIPTION:' + spa_metapkg, spa_pn + ' meta package') d.setVar('RDEPENDS:' + pw_module_metapkg, ' '.join(pw_module_metapkg_rdepends)) d.setVar('DESCRIPTION:' + pw_module_metapkg, pw_module_pn + ' meta package') } PACKAGES =+ "\ libpipewire \ ${PN}-tools \ ${PN}-pulse \ ${PN}-alsa \ ${PN}-jack \ ${PN}-v4l2 \ ${PN}-spa-plugins \ ${PN}-spa-plugins-meta \ ${PN}-spa-tools \ ${PN}-modules \ ${PN}-modules-meta \ ${PN}-alsa-card-profile \ gstreamer1.0-pipewire \ " PACKAGES_DYNAMIC = "^${PN}-spa-plugins.* ^${PN}-modules.*" SYSTEMD_SERVICE:${PN} = "pipewire.service" CONFFILES:${PN} += "${datadir}/pipewire/pipewire.conf" FILES:${PN} = " \ ${datadir}/pipewire/pipewire.conf \ ${datadir}/pipewire/filter-chain.conf \ ${datadir}/pipewire/filter-chain \ ${systemd_user_unitdir}/pipewire.* \ ${systemd_system_unitdir}/pipewire* \ ${bindir}/pipewire \ ${datadir}/pipewire/pipewire-avb.conf \ ${bindir}/pipewire-avb \ ${datadir}/pipewire/pipewire-aes67.conf \ ${bindir}/pipewire-aes67 \ ${datadir}/pipewire/pipewire.conf.avail \ ${datadir}/pipewire/pipewire-pulse.conf.avail \ ${datadir}/pipewire/client-rt.conf.avail \ ${datadir}/pipewire/client.conf.avail \ ${sysconfdir}/security/limits.d \ " FILES:${PN}-dev += " \ ${libdir}/${PW_MODULE_SUBDIR}/jack/libjack*.so \ " CONFFILES:libpipewire += "${datadir}/pipewire/client.conf" FILES:libpipewire = " \ ${datadir}/pipewire/client.conf \ ${datadir}/pipewire/client-rt.conf \ ${datadir}/pipewire/minimal.conf \ ${libdir}/libpipewire-*.so.* \ " # Add the bare minimum modules and plugins required to be able # to use libpipewire. Without these, it is essentially unusable. RDEPENDS:libpipewire += " \ ${PN}-modules-client-node \ ${PN}-modules-protocol-native \ ${PN}-spa-plugins-support \ " FILES:${PN}-tools = " \ ${bindir}/pw-* \ " # This is a shim daemon that is intended to be used as a # drop-in PulseAudio replacement, providing a pulseaudio-compatible # socket that can be used by applications that use libpulse. CONFFILES:${PN}-pulse += "${datadir}/pipewire/pipewire-pulse.conf" FILES:${PN}-pulse = " \ ${datadir}/pipewire/pipewire-pulse.conf \ ${systemd_user_unitdir}/pipewire-pulse.* \ ${bindir}/pipewire-pulse \ " RDEPENDS:${PN}-pulse += " \ ${PN}-modules-protocol-pulse \ " # alsa plugin to redirect audio to pipewire FILES:${PN}-alsa = "\ ${libdir}/alsa-lib/* \ ${datadir}/alsa/alsa.conf.d/* \ " #lib to emulate v4l2 system calls on top of PipeWire FILES:${PN}-v4l2 = "\ ${libdir}/${PW_MODULE_SUBDIR}/v4l2/libpw-v4l2.so \ " # jack drop-in libraries to redirect audio to pipewire CONFFILES:${PN}-jack = "${datadir}/pipewire/jack.conf" FILES:${PN}-jack = "\ ${datadir}/pipewire/jack.conf \ ${libdir}/${PW_MODULE_SUBDIR}/jack/libjack*.so.* \ " # Dynamic packages (see set_dynamic_metapkg_rdepends). FILES:${PN}-spa-plugins-bluez5 += " \ ${datadir}/${SPA_SUBDIR}/bluez5/bluez-hardware.conf \ " RRECOMMENDS:${PN}-spa-plugins += "${PN}-spa-plugins-meta" FILES:${PN}-spa-tools = " \ ${bindir}/spa-* \ " # Dynamic packages (see set_dynamic_metapkg_rdepends). FILES:${PN}-modules = "" RRECOMMENDS:${PN}-modules += "${PN}-modules-meta" CONFFILES:${PN}-modules-rtkit = "${datadir}/pipewire/client-rt.conf" FILES:${PN}-modules-rtkit += " \ ${datadir}/pipewire/client-rt.conf \ " FILES:${PN}-alsa-card-profile = " \ ${datadir}/alsa-card-profile/* \ ${nonarch_base_libdir}/udev/rules.d/90-pipewire-alsa.rules \ " FILES:gstreamer1.0-pipewire = " \ ${libdir}/gstreamer-1.0/* \ "