diff options
Diffstat (limited to 'binding/radio-binding.c')
-rw-r--r-- | binding/radio-binding.c | 752 |
1 files changed, 0 insertions, 752 deletions
diff --git a/binding/radio-binding.c b/binding/radio-binding.c deleted file mode 100644 index 8b5559c..0000000 --- a/binding/radio-binding.c +++ /dev/null @@ -1,752 +0,0 @@ -/* - * Copyright (C) 2017, 2019 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 - * - * 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 _GNU_SOURCE - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <stdbool.h> -#include <unistd.h> -#include <sys/types.h> -#include <json-c/json.h> -#include <afb/afb-binding.h> - -#include "radio_impl.h" -#include "radio_impl_null.h" -#include "radio_impl_rtlsdr.h" -#include "radio_impl_kingfisher.h" -#include "radio_impl_tef665x.h" - -static radio_impl_ops_t *radio_impl_ops; - -static afb_event_t freq_event; -static afb_event_t scan_event; -static afb_event_t status_event; -static afb_event_t rds_event; - -static bool playing; - -static const char *signalcomposer_events[] = { - "event.media.next", - "event.media.previous", - "event.media.mode", - NULL, -}; - -static void freq_callback(uint32_t frequency, void *data) -{ - json_object *jresp = json_object_new_object(); - json_object *value = json_object_new_int((int) frequency); - - json_object_object_add(jresp, "value", value); - afb_event_push(freq_event, json_object_get(jresp)); -} - -static void scan_callback(uint32_t frequency, void *data) -{ - json_object *jresp = json_object_new_object(); - json_object *value = json_object_new_int((int) frequency); - - json_object_object_add(jresp, "value", value); - afb_event_push(scan_event, json_object_get(jresp)); -} - -static void rds_callback(void *rds_data) -{ - //rds_data is a json object - afb_event_push(rds_event, json_object_get(rds_data)); -} - -/* - * Binding verb handlers - */ - -/* - * @brief Get (and optionally set) frequency - * - * @param afb_req_t : an afb request structure - * - */ -static void frequency(afb_req_t request) -{ - json_object *ret_json; - const char *value = afb_req_value(request, "value"); - uint32_t frequency; - - if(value) { - char *p; - radio_band_t band; - uint32_t min_frequency; - uint32_t max_frequency; - uint32_t step; - - frequency = (uint32_t) strtoul(value, &p, 10); - if(frequency && *p == '\0') { - band = radio_impl_ops->get_band(); - min_frequency = radio_impl_ops->get_min_frequency(band); - max_frequency = radio_impl_ops->get_max_frequency(band); - step = radio_impl_ops->get_frequency_step(band); - if(frequency < min_frequency || - frequency > max_frequency || - (frequency - min_frequency) % step) { - afb_req_reply(request, NULL, "failed", "Invalid frequency"); - return; - } - radio_impl_ops->set_frequency(frequency); - } else { - afb_req_reply(request, NULL, "failed", "Invalid frequency"); - return; - } - } - ret_json = json_object_new_object(); - frequency = radio_impl_ops->get_frequency(); - json_object_object_add(ret_json, "frequency", json_object_new_int((int32_t) frequency)); - afb_req_reply(request, ret_json, NULL, NULL); -} - -/* - * @brief Get RDS information - * - * @param afb_req_t : an afb request structure - * - */ -static void rds(afb_req_t request) -{ - json_object *ret_json; - char * rds; - - if (radio_impl_ops->get_rds_info == NULL) { - afb_req_reply(request, NULL, "failed", "not supported"); - return; - } - - ret_json = json_object_new_object(); - rds = radio_impl_ops->get_rds_info(); - json_object_object_add(ret_json, "rds", json_object_new_string(rds?rds:"")); - free(rds); - - afb_req_reply(request, ret_json, NULL, NULL); -} - -/* @brief Get quality information - * - * @param afb_req_t : an afb request structure - * - */ -static void quality(afb_req_t request) -{ - json_object *ret_json; - station_quality_t *quality_data; - - if (radio_impl_ops->get_quality_info == NULL) { - afb_req_reply(request, NULL, "failed", "Not supported"); - return; - } - - quality_data = radio_impl_ops->get_quality_info(); - ret_json=json_object_new_object(); - if(quality_data->af_update) - { - json_object_object_add(ret_json, "af_update", json_object_new_int((int) quality_data->af_update)); - } - if(quality_data->time_stamp){ - json_object_object_add(ret_json, "timestamp", json_object_new_int((int) quality_data->time_stamp)); - } - if(quality_data->rssi) - { - json_object_object_add(ret_json, "rssi", json_object_new_int((int) quality_data->rssi)); - } - if(quality_data->usn) - { - json_object_object_add(ret_json, "usn", json_object_new_int((int) quality_data->usn)); - } - if(quality_data->bandw) - { - json_object_object_add(ret_json, "bandwidth", json_object_new_int((int) quality_data->bandw)); - } - afb_req_reply(request, ret_json, NULL, NULL); - return; -} - -/* @brief Check alternative frequency - * - * @param afb_req_t : an afb request structure - * - */ -static void alternative_frequency(afb_req_t request) -{ - json_object *ret_json; - uint32_t alternative; - const char *value; - - if (radio_impl_ops->set_alternative_frequency == NULL) { - afb_req_reply(request, NULL, "failed", "Not supported"); - return; - } - - value = afb_req_value(request, "value"); - if(value) { - char *p; - radio_band_t band; - uint32_t min_frequency; - uint32_t max_frequency; - uint32_t step; - - alternative = (uint32_t) strtoul(value, &p, 10); - if(alternative && *p == '\0') { - band = radio_impl_ops->get_band(); - min_frequency = radio_impl_ops->get_min_frequency(band); - max_frequency = radio_impl_ops->get_max_frequency(band); - step = radio_impl_ops->get_frequency_step(band); - if(alternative < min_frequency || - alternative > max_frequency || - (alternative - min_frequency) % step) { - afb_req_reply(request, NULL, "failed", "Invalid alternative frequency"); - return; - } - radio_impl_ops->set_alternative_frequency(alternative); - ret_json = json_object_new_object(); - json_object_object_add(ret_json, "alternative", json_object_new_int((int32_t) alternative)); - afb_req_reply(request, ret_json, NULL, NULL); - } else { - afb_req_reply(request, NULL, "failed", "Invalid alternative frequency"); - return; - } - } - else { - afb_req_reply(request, NULL, "failed", "Invalid alternative frequency"); - return; - } -} - -/* - * @brief Get (and optionally set) frequency band - * - * @param afb_req_t : an afb request structure - * - */ -static void band(afb_req_t request) -{ - json_object *ret_json; - const char *value = afb_req_value(request, "value"); - int valid = 0; - radio_band_t band; - char band_name[4]; - - if(value) { - if(!strcasecmp(value, "AM")) { - band = BAND_AM; - valid = 1; - } else if(!strcasecmp(value, "FM")) { - band = BAND_FM; - valid = 1; - } else { - char *p; - band = strtoul(value, &p, 10); - if(p != value && *p == '\0') { - switch(band) { - case BAND_AM: - case BAND_FM: - valid = 1; - break; - default: - break; - } - } - } - if(valid) { - radio_impl_ops->set_band(band); - } else { - afb_req_reply(request, NULL, "failed", "Invalid band"); - return; - } - } - ret_json = json_object_new_object(); - band = radio_impl_ops->get_band(); - sprintf(band_name, "%s", band == BAND_AM ? "AM" : "FM"); - json_object_object_add(ret_json, "band", json_object_new_string(band_name)); - afb_req_reply(request, ret_json, NULL, NULL); -} - -/* - * @brief Check if band is supported - * - * @param afb_req_t : an afb request structure - * - */ -static void band_supported(afb_req_t request) -{ - json_object *ret_json; - const char *value = afb_req_value(request, "band"); - int valid = 0; - radio_band_t band; - - if(value) { - if(!strcasecmp(value, "AM")) { - band = BAND_AM; - valid = 1; - } else if(!strcasecmp(value, "FM")) { - band = BAND_FM; - valid = 1; - } else { - char *p; - band = strtoul(value, &p, 10); - if(p != value && *p == '\0') { - switch(band) { - case BAND_AM: - case BAND_FM: - valid = 1; - break; - default: - break; - } - } - } - } - if(!valid) { - afb_req_reply(request, NULL, "failed", "Invalid band"); - return; - } - ret_json = json_object_new_object(); - json_object_object_add(ret_json, - "supported", - json_object_new_int(radio_impl_ops->band_supported(band))); - afb_req_reply(request, ret_json, NULL, NULL); -} - -/* - * @brief Get frequency range for a band - * - * @param afb_req_t : an afb request structure - * - */ -static void frequency_range(afb_req_t request) -{ - json_object *ret_json; - const char *value = afb_req_value(request, "band"); - int valid = 0; - radio_band_t band; - uint32_t min_frequency; - uint32_t max_frequency; - - if(value) { - if(!strcasecmp(value, "AM")) { - band = BAND_AM; - valid = 1; - } else if(!strcasecmp(value, "FM")) { - band = BAND_FM; - valid = 1; - } else { - char *p; - band = strtoul(value, &p, 10); - if(p != value && *p == '\0') { - switch(band) { - case BAND_AM: - case BAND_FM: - valid = 1; - break; - default: - break; - } - } - } - } - if(!valid) { - afb_req_reply(request, NULL, "failed", "Invalid band"); - return; - } - ret_json = json_object_new_object(); - min_frequency = radio_impl_ops->get_min_frequency(band); - max_frequency = radio_impl_ops->get_max_frequency(band); - json_object_object_add(ret_json, "min", json_object_new_int((int32_t) min_frequency)); - json_object_object_add(ret_json, "max", json_object_new_int((int32_t) max_frequency)); - afb_req_reply(request, ret_json, NULL, NULL); -} - -/* - * @brief Get frequency step size (Hz) for a band - * - * @param afb_req_t : an afb request structure - * - */ -static void frequency_step(afb_req_t request) -{ - json_object *ret_json; - const char *value = afb_req_value(request, "band"); - int valid = 0; - radio_band_t band; - uint32_t step; - - if(value) { - if(!strcasecmp(value, "AM")) { - band = BAND_AM; - valid = 1; - } else if(!strcasecmp(value, "FM")) { - band = BAND_FM; - valid = 1; - } else { - char *p; - band = strtoul(value, &p, 10); - if(p != value && *p == '\0') { - switch(band) { - case BAND_AM: - case BAND_FM: - valid = 1; - break; - default: - break; - } - } - } - } - if(!valid) { - afb_req_reply(request, NULL, "failed", "Invalid band"); - return; - } - ret_json = json_object_new_object(); - step = radio_impl_ops->get_frequency_step(band); - json_object_object_add(ret_json, "step", json_object_new_int((int32_t) step)); - afb_req_reply(request, ret_json, NULL, NULL); -} - -/* - * @brief Start radio playback - * - * @param afb_req_t : an afb request structure - * - */ -static void start(afb_req_t request) -{ - radio_impl_ops->set_output(NULL); - radio_impl_ops->start(); - playing = true; - afb_req_reply(request, NULL, NULL, NULL); - - json_object *jresp = json_object_new_object(); - json_object *value = json_object_new_string("playing"); - json_object_object_add(jresp, "value", value); - afb_event_push(status_event, json_object_get(jresp)); -} - -/* - * @brief Stop radio playback - * - * @param afb_req_t : an afb request structure - * - */ -static void stop(afb_req_t request) -{ - radio_impl_ops->stop(); - playing = false; - afb_req_reply(request, NULL, NULL, NULL); - - json_object *jresp = json_object_new_object(); - json_object *value = json_object_new_string("stopped"); - json_object_object_add(jresp, "value", value); - afb_event_push(status_event, json_object_get(jresp)); -} - -/* - * @brief Scan for a station in the specified direction - * - * @param afb_req_t : an afb request structure - * - */ -static void scan_start(afb_req_t request) -{ - const char *value = afb_req_value(request, "direction"); - int valid = 0; - radio_scan_direction_t direction; - - if(value) { - if(!strcasecmp(value, "forward")) { - direction = SCAN_FORWARD; - valid = 1; - } else if(!strcasecmp(value, "backward")) { - direction = SCAN_BACKWARD; - valid = 1; - } else { - char *p; - direction = strtoul(value, &p, 10); - if(p != value && *p == '\0') { - switch(direction) { - case SCAN_FORWARD: - case SCAN_BACKWARD: - valid = 1; - break; - default: - break; - } - } - } - } - if(!valid) { - afb_req_reply(request, NULL, "failed", "Invalid direction"); - return; - } - radio_impl_ops->scan_start(direction, scan_callback, NULL); - afb_req_reply(request, NULL, NULL, NULL); -} - -/* - * @brief Stop station scan - * - * @param afb_req_t : an afb request structure - * - */ -static void scan_stop(afb_req_t request) -{ - radio_impl_ops->scan_stop(); - afb_req_reply(request, NULL, NULL, NULL); -} - -/* - * @brief Get (and optionally set) stereo mode - * - * @param afb_req_t : an afb request structure - * - */ -static void stereo_mode(afb_req_t request) -{ - json_object *ret_json; - const char *value = afb_req_value(request, "value"); - int valid = 0; - radio_stereo_mode_t mode; - - if(value) { - if(!strcasecmp(value, "mono")) { - mode = MONO; - valid = 1; - } else if(!strcasecmp(value, "stereo")) { - mode = STEREO; - valid = 1; - } else { - char *p; - mode = strtoul(value, &p, 10); - if(p != value && *p == '\0') { - switch(mode) { - case MONO: - case STEREO: - valid = 1; - break; - default: - break; - } - } - } - if(valid) { - radio_impl_ops->set_stereo_mode(mode); - } else { - afb_req_reply(request, NULL, "failed", "Invalid mode"); - return; - } - } - ret_json = json_object_new_object(); - mode = radio_impl_ops->get_stereo_mode(); - - json_object_object_add(ret_json, "mode", json_object_new_string(mode == MONO ? "mono" : "stereo")); - afb_req_reply(request, ret_json, NULL, NULL); -} - -/* - * @brief Subscribe for an event - * - * @param afb_req_t : an afb request structure - * - */ -static void subscribe(afb_req_t request) -{ - const char *value = afb_req_value(request, "value"); - if(value) { - if(!strcasecmp(value, "frequency")) { - afb_req_subscribe(request, freq_event); - } else if(!strcasecmp(value, "station_found")) { - afb_req_subscribe(request, scan_event); - } else if(!strcasecmp(value, "status")) { - afb_req_subscribe(request, status_event); - } else if(!strcasecmp(value, "rds")) { - afb_req_subscribe(request, rds_event); - } - else { - afb_req_reply(request, NULL, "failed", "Invalid event"); - return; - } - } - afb_req_reply(request, NULL, NULL, NULL); -} - -/* - * @brief Unsubscribe for an event - * - * @param afb_req_t : an afb request structure - * - */ -static void unsubscribe(afb_req_t request) -{ - const char *value = afb_req_value(request, "value"); - if(value) { - if(!strcasecmp(value, "frequency")) { - afb_req_unsubscribe(request, freq_event); - } else if(!strcasecmp(value, "station_found")) { - afb_req_unsubscribe(request, scan_event); - } else if(!strcasecmp(value, "status")) { - afb_req_unsubscribe(request, status_event); - - } else if(!strcasecmp(value, "rds")) { - afb_req_unsubscribe(request, rds_event); - - } else { - afb_req_reply(request, NULL, "failed", "Invalid event"); - return; - } - } - afb_req_reply(request, NULL, NULL, NULL); -} - -static const afb_verb_t verbs[]= { - { .verb = "frequency", .session = AFB_SESSION_NONE, .callback = frequency, .info = "Get/Set frequency" }, - { .verb = "band", .session = AFB_SESSION_NONE, .callback = band, .info = "Get/Set band" }, - { .verb = "rds", .session = AFB_SESSION_NONE, .callback = rds, .info = "Get RDS information" }, - { .verb = "quality", .session = AFB_SESSION_NONE, .callback = quality, .info = "Get station quality information" }, - { .verb = "alternative_frequency", .session = AFB_SESSION_NONE, .callback = alternative_frequency, .info = "Check an alternative frequency" }, - { .verb = "band_supported", .session = AFB_SESSION_NONE, .callback = band_supported, .info = "Check band support" }, - { .verb = "frequency_range", .session = AFB_SESSION_NONE, .callback = frequency_range, .info = "Get frequency range" }, - { .verb = "frequency_step", .session = AFB_SESSION_NONE, .callback = frequency_step, .info = "Get frequency step" }, - { .verb = "start", .session = AFB_SESSION_NONE, .callback = start, .info = "Start radio playback" }, - { .verb = "stop", .session = AFB_SESSION_NONE, .callback = stop, .info = "Stop radio playback" }, - { .verb = "scan_start", .session = AFB_SESSION_NONE, .callback = scan_start, .info = "Start station scan" }, - { .verb = "scan_stop", .session = AFB_SESSION_NONE, .callback = scan_stop, .info = "Stop station scan" }, - { .verb = "stereo_mode", .session = AFB_SESSION_NONE, .callback = stereo_mode, .info = "Get/Set stereo_mode" }, - { .verb = "subscribe", .session = AFB_SESSION_NONE, .callback = subscribe, .info = "Subscribe for an event" }, - { .verb = "unsubscribe", .session = AFB_SESSION_NONE, .callback = unsubscribe, .info = "Unsubscribe for an event" }, - { } -}; - -static void onevent(afb_api_t api, const char *event, struct json_object *object) -{ - json_object *tmp = NULL; - const char *uid; - const char *value; - - json_object_object_get_ex(object, "uid", &tmp); - if (tmp == NULL) - return; - - uid = json_object_get_string(tmp); - if (strncmp(uid, "event.media.", 12)) - return; - - if (!playing || - (radio_impl_ops->get_corking_state && - radio_impl_ops->get_corking_state())) { - return; - } - - json_object_object_get_ex(object, "value", &tmp); - if (tmp == NULL) - return; - - value = json_object_get_string(tmp); - if (strncmp(value, "true", 4)) - return; - - if (!strcmp(uid, "event.media.next")) { - radio_impl_ops->scan_start(SCAN_FORWARD, scan_callback, NULL); - } else if (!strcmp(uid, "event.media.previous")) { - radio_impl_ops->scan_start(SCAN_BACKWARD, scan_callback, NULL); - } else if (!strcmp(uid, "event.media.mode")) { - // Do nothing ATM - } else { - AFB_WARNING("Unhandled signal-composer uid '%s'", uid); - } -} - -static int init(afb_api_t api) -{ - // Probe for radio backends - radio_impl_ops = &rtlsdr_impl_ops; - int rc = radio_impl_ops->probe(); - if(rc != 0) { - // Look for Kingfisher Si4689 - radio_impl_ops = &kf_impl_ops; - rc = radio_impl_ops->probe(); - } - if(rc != 0) { - radio_impl_ops = &tef665x_impl_ops; - rc = radio_impl_ops->probe(); - } - if (rc != 0) { - radio_impl_ops = &null_impl_ops; - rc = radio_impl_ops->probe(); - } - if (rc != 0) { - // We don't expect the null implementation to fail probe, but just in case... - AFB_API_ERROR(afbBindingV3root, "No radio device found, exiting"); - return rc; - } - // Try to initialize detected backend - rc = radio_impl_ops->init(); - if(rc < 0) { - AFB_API_ERROR(afbBindingV3root, - "%s initialization failed\n", - radio_impl_ops->name); - return rc; - } - AFB_API_NOTICE(afbBindingV3root, "%s found\n", radio_impl_ops->name); - radio_impl_ops->set_frequency_callback(freq_callback, NULL); - radio_impl_ops->set_frequency_callback(freq_callback, NULL); - if(radio_impl_ops->set_rds_callback) { - radio_impl_ops->set_rds_callback(rds_callback); - } - - rc = afb_daemon_require_api("signal-composer", 1); - if (rc) { - AFB_WARNING("unable to initialize signal-composer binding"); - } else { - const char **tmp = signalcomposer_events; - json_object *args = json_object_new_object(); - json_object *signals = json_object_new_array(); - - while (*tmp) { - json_object_array_add(signals, json_object_new_string(*tmp++)); - } - json_object_object_add(args, "signal", signals); - if(json_object_array_length(signals)) { - afb_api_call_sync(api, "signal-composer", "subscribe", - args, NULL, NULL, NULL); - } else { - json_object_put(args); - } - } - - // Initialize event structures - freq_event = afb_daemon_make_event("frequency"); - scan_event = afb_daemon_make_event("station_found"); - status_event = afb_daemon_make_event("status"); - rds_event = afb_daemon_make_event("rds"); - return 0; -} - -const afb_binding_t afbBindingExport = { - .info = "radio service", - .api = "radio", - .specification = "Radio API", - .verbs = verbs, - .onevent = onevent, - .init = init, -}; |