Radio Hal tool to test HAL implementation.
A simple tool so that the HAL can be poked using a standalone binary.
Useful when changing the HAL and ensuring that HAL changes are
consistent with the required behavior.
Bug: b/24807501
Bug: b/22701655
Change-Id: I5aa3b614f83c0fd361787346a2c6d6c383fc8519
(cherry picked from commit 611bb7397be3fa341b3ef80f7a252850c68c2597)
diff --git a/modules/radio/Android.mk b/modules/radio/Android.mk
index f433c85..e7647b2 100644
--- a/modules/radio/Android.mk
+++ b/modules/radio/Android.mk
@@ -25,3 +25,12 @@
LOCAL_32_BIT_ONLY := true
include $(BUILD_SHARED_LIBRARY)
+
+# Stub radio tool that can be run in native.
+include $(CLEAR_VARS)
+LOCAL_MODULE := radio_hal_tool
+LOCAL_SRC_FILES := radio_hal_tool.c
+LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
+LOCAL_SHARED_LIBRARIES := libcutils libhardware liblog libradio_metadata
+
+include $(BUILD_EXECUTABLE)
diff --git a/modules/radio/radio_hal_tool.c b/modules/radio/radio_hal_tool.c
new file mode 100644
index 0000000..f5c7637
--- /dev/null
+++ b/modules/radio/radio_hal_tool.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#define LOG_TAG "radio_hal_tool"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <hardware/hardware.h>
+#include <hardware/radio.h>
+#include <system/radio.h>
+#include <system/radio_metadata.h>
+
+
+// Global state variables.
+const struct radio_tuner *hal_tuner = NULL;
+
+void usage() {
+ printf("Usage: "
+ "./radio_hal_tool -l\n"
+ "-l: List properties global to the Radio.\n"
+ );
+}
+
+void list_all_properties(radio_hw_device_t *device) {
+ radio_hal_properties_t hal_properties;
+ device->get_properties(device, &hal_properties);
+ printf("Class: %d\n"
+ "Impl: %s\n"
+ "Tuners: %d\n"
+ "Bands: %d\n\n",
+ hal_properties.class_id, hal_properties.implementor, hal_properties.num_tuners,
+ hal_properties.num_bands);
+
+ uint32_t i;
+ for (i = 0; i < hal_properties.num_bands; i++) {
+ printf("Band Information\n"
+ "Type: %d\n"
+ "Connected: %d\n"
+ "Lower limit: %d\n"
+ "Upper limit: %d\n"
+ "Spacing: %d\n\n",
+ hal_properties.bands[i].type,
+ hal_properties.bands[i].antenna_connected,
+ hal_properties.bands[i].lower_limit,
+ hal_properties.bands[i].upper_limit,
+ hal_properties.bands[i].num_spacings);
+ }
+}
+
+void callback(radio_hal_event_t *event, void *cookie) {
+ printf("\nEvent detected\n"
+ "Type: %d\n", event->type);
+}
+
+void tune(radio_hw_device_t *device, int band_number) {
+ int ret;
+ radio_hal_properties_t hal_properties;
+ ret = device->get_properties(device, &hal_properties);
+ if (ret != 0) {
+ printf("Err: get_properties returned: %d\n", ret);
+ return;
+ }
+
+ if ((uint32_t) band_number >= hal_properties.num_bands) {
+ printf("Tuner number range should be: [0, %d]\n", hal_properties.num_bands);
+ }
+ printf("Setting band config as:\n"
+ "Type: %d\n"
+ "Connected: %d\n"
+ "Lower limit: %d\n"
+ "Upper limit: %d\n"
+ "Spacing: %d\n\n",
+ hal_properties.bands[band_number].type,
+ hal_properties.bands[band_number].antenna_connected,
+ hal_properties.bands[band_number].lower_limit,
+ hal_properties.bands[band_number].upper_limit,
+ hal_properties.bands[band_number].num_spacings);
+ int cookie = 0;
+ ret = device->open_tuner(
+ device, (const radio_hal_band_config_t *) (&(hal_properties.bands[band_number])), false,
+ callback, &cookie, &hal_tuner);
+ if (ret != 0) {
+ printf("Err: open_tuner returned: %d\n", ret);
+ return;
+ }
+ // It takes some time to apply the config which is currently set as 500ms in
+ // the stub implementation.
+ sleep(1);
+
+ // Stub tuner implementation will regard this magic channel as a valid channel to tune.
+ ret = hal_tuner->tune(hal_tuner, 87916, 0);
+ if (ret != 0) {
+ printf("Err: tune returned: %d\n", ret);
+ return;
+ }
+ // In the stub implementation it takes ~100ms to tune to the channel and the
+ // data is set rightafter.
+ sleep(1);
+}
+
+void get_tuner_metadata(radio_hw_device_t *device) {
+ // Get the metadata and print it.
+ radio_program_info_t info;
+ radio_metadata_allocate(&info.metadata, 87916, 0);
+ int ret;
+ ret = hal_tuner->get_program_information(hal_tuner, &info);
+ if (ret != 0) {
+ printf("Err: Get program info ret code: %d\n", ret);
+ return;
+ }
+
+ // Print the info.
+ printf("Metadata from the band\n");
+ int i;
+ for (i = 0; i < radio_metadata_get_count(info.metadata); i++) {
+ radio_metadata_key_t key;
+ radio_metadata_type_t type;
+ void *value;
+ uint32_t size;
+
+ radio_metadata_get_at_index(info.metadata, i, &key, &type, &value, &size);
+
+ printf("\nMetadata key: %d\n"
+ "Type: %d\n", key, type);
+
+ switch (type) {
+ case RADIO_METADATA_TYPE_INT:
+ printf("Int value: %d\n", *((int *) value));
+ break;
+ case RADIO_METADATA_TYPE_TEXT:
+ printf("Text value: %s\n", (char *) value);
+ break;
+ case RADIO_METADATA_TYPE_RAW:
+ printf("Raw value, skipping\n");
+ break;
+ case RADIO_METADATA_TYPE_CLOCK:
+ printf("UTC Epoch: %lld\n"
+ "UTC Offset: %d\n",
+ ((radio_metadata_clock_t *) value)->utc_seconds_since_epoch,
+ ((radio_metadata_clock_t *) value)->timezone_offset_in_minutes);
+ }
+ }
+
+ // Close the tuner when we are done.
+ ret = device->close_tuner(device, hal_tuner);
+ if (ret != 0) {
+ printf("Err: close_tuner returned: %d\n", ret);
+ }
+}
+
+int main(int argc, char** argv) {
+ // Open the radio module and just ask for the list of properties.
+ const hw_module_t *hw_module = NULL;
+ int rc;
+ rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, RADIO_HARDWARE_MODULE_ID_FM, &hw_module);
+ if (rc != 0) {
+ printf("Cannot open the hw module. Does the HAL exist? %d\n", rc);
+ return -1;
+ }
+
+ radio_hw_device_t *dev;
+ rc = radio_hw_device_open(hw_module, &dev);
+ if (rc != 0) {
+ printf("Cannot open the device. Check that HAL implementation. %d\n", rc);
+ return -1;
+ }
+ printf("HAL Loaded!\n");
+
+ // If this is a list properties command - we check for -l command.
+ int list_properties = 0;
+ // Get metadata.
+ int get_metadata = 0;
+ // Tune. Takes a tuner number (see bands obtainaed by list_properties).
+ int should_tune = 0;
+ int band_number = -1;
+
+ int opt;
+ while ((opt = getopt(argc, argv, "lmt:")) != -1) {
+ switch (opt) {
+ case 'l':
+ list_properties = 1;
+ break;
+ case 't':
+ should_tune = 1;
+ band_number = atoi(optarg);
+ break;
+ case 'm':
+ get_metadata = 1;
+ break;
+ }
+ }
+
+ if (list_properties) {
+ printf("Listing properties...\n");
+ list_all_properties(dev);
+ } else {
+ if (should_tune) {
+ if (band_number < 0) {
+ printf("Tuner number should be positive");
+ return -1;
+ }
+ printf("Tuning to a station...\n");
+ tune(dev, band_number);
+ }
+ if (get_metadata) {
+ if (!hal_tuner) {
+ printf("Please pass -t <band_number> to tune to a valid station to get metadata.");
+ exit(1);
+ }
+ get_tuner_metadata(dev);
+ }
+ }
+ return 0;
+}