/* * 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; size_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", (long long)((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; }