diff options
Diffstat (limited to 'binding/radio-binding.c')
-rw-r--r-- | binding/radio-binding.c | 222 |
1 files changed, 161 insertions, 61 deletions
diff --git a/binding/radio-binding.c b/binding/radio-binding.c index 847e822..34eb53e 100644 --- a/binding/radio-binding.c +++ b/binding/radio-binding.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Konsulko Group + * 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. @@ -24,18 +24,29 @@ #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 struct afb_event freq_event; -static struct afb_event scan_event; -static struct afb_event status_event; +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) { @@ -55,6 +66,12 @@ static void scan_callback(uint32_t frequency, void *data) 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 */ @@ -62,10 +79,10 @@ static void scan_callback(uint32_t frequency, void *data) /* * @brief Get (and optionally set) frequency * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void frequency(struct afb_req request) +static void frequency(afb_req_t request) { json_object *ret_json; const char *value = afb_req_value(request, "value"); @@ -77,28 +94,28 @@ static void frequency(struct afb_req request) if(frequency && *p == '\0') { radio_impl_ops->set_frequency(frequency); } else { - afb_req_fail(request, "failed", "Invalid scan direction"); + afb_req_reply(request, NULL, "failed", "Invalid scan direction"); 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_success(request, ret_json, NULL); + afb_req_reply(request, ret_json, NULL, NULL); } /* @brief Get RDS information * -* @param struct afb_req : an afb request structure +* @param afb_req_t : an afb request structure * */ -static void rds(struct afb_req request) +static void rds(afb_req_t request) { json_object *ret_json; char * rds; if (radio_impl_ops->get_rds_info == NULL) { - afb_req_fail(request, "failed", "not supported"); + afb_req_reply(request, NULL, "failed", "not supported"); return; } @@ -107,16 +124,16 @@ static void rds(struct afb_req request) json_object_object_add(ret_json, "rds", json_object_new_string(rds?rds:"")); free(rds); - afb_req_success(request, ret_json, NULL); + afb_req_reply(request, ret_json, NULL, NULL); } /* * @brief Get (and optionally set) frequency band * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void band(struct afb_req request) +static void band(afb_req_t request) { json_object *ret_json; const char *value = afb_req_value(request, "value"); @@ -148,7 +165,7 @@ static void band(struct afb_req request) if(valid) { radio_impl_ops->set_band(band); } else { - afb_req_fail(request, "failed", "Invalid band"); + afb_req_reply(request, NULL, "failed", "Invalid band"); return; } } @@ -156,16 +173,16 @@ static void band(struct afb_req request) 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_success(request, ret_json, NULL); + afb_req_reply(request, ret_json, NULL, NULL); } /* * @brief Check if band is supported * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void band_supported(struct afb_req request) +static void band_supported(afb_req_t request) { json_object *ret_json; const char *value = afb_req_value(request, "band"); @@ -195,23 +212,23 @@ static void band_supported(struct afb_req request) } } if(!valid) { - afb_req_fail(request, "failed", "Invalid band"); + 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_success(request, ret_json, NULL); + afb_req_reply(request, ret_json, NULL, NULL); } /* * @brief Get frequency range for a band * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void frequency_range(struct afb_req request) +static void frequency_range(afb_req_t request) { json_object *ret_json; const char *value = afb_req_value(request, "band"); @@ -243,7 +260,7 @@ static void frequency_range(struct afb_req request) } } if(!valid) { - afb_req_fail(request, "failed", "Invalid band"); + afb_req_reply(request, NULL, "failed", "Invalid band"); return; } ret_json = json_object_new_object(); @@ -251,16 +268,16 @@ static void frequency_range(struct afb_req request) 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_success(request, ret_json, NULL); + afb_req_reply(request, ret_json, NULL, NULL); } /* * @brief Get frequency step size (Hz) for a band * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void frequency_step(struct afb_req request) +static void frequency_step(afb_req_t request) { json_object *ret_json; const char *value = afb_req_value(request, "band"); @@ -291,26 +308,27 @@ static void frequency_step(struct afb_req request) } } if(!valid) { - afb_req_fail(request, "failed", "Invalid band"); + 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_success(request, ret_json, NULL); + afb_req_reply(request, ret_json, NULL, NULL); } /* * @brief Start radio playback * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void start(struct afb_req request) +static void start(afb_req_t request) { radio_impl_ops->set_output(NULL); radio_impl_ops->start(); - afb_req_success(request, NULL, NULL); + playing = true; + afb_req_reply(request, NULL, NULL, NULL); json_object *jresp = json_object_new_object(); json_object *value = json_object_new_string("playing"); @@ -321,13 +339,14 @@ static void start(struct afb_req request) /* * @brief Stop radio playback * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void stop(struct afb_req request) +static void stop(afb_req_t request) { radio_impl_ops->stop(); - afb_req_success(request, NULL, NULL); + playing = false; + afb_req_reply(request, NULL, NULL, NULL); json_object *jresp = json_object_new_object(); json_object *value = json_object_new_string("stopped"); @@ -338,10 +357,10 @@ static void stop(struct afb_req request) /* * @brief Scan for a station in the specified direction * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void scan_start(struct afb_req request) +static void scan_start(afb_req_t request) { const char *value = afb_req_value(request, "direction"); int valid = 0; @@ -370,32 +389,32 @@ static void scan_start(struct afb_req request) } } if(!valid) { - afb_req_fail(request, "failed", "Invalid direction"); + afb_req_reply(request, NULL, "failed", "Invalid direction"); return; } radio_impl_ops->scan_start(direction, scan_callback, NULL); - afb_req_success(request, NULL, NULL); + afb_req_reply(request, NULL, NULL, NULL); } /* * @brief Stop station scan * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void scan_stop(struct afb_req request) +static void scan_stop(afb_req_t request) { radio_impl_ops->scan_stop(); - afb_req_success(request, NULL, NULL); + afb_req_reply(request, NULL, NULL, NULL); } /* * @brief Get (and optionally set) stereo mode * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void stereo_mode(struct afb_req request) +static void stereo_mode(afb_req_t request) { json_object *ret_json; const char *value = afb_req_value(request, "value"); @@ -426,7 +445,7 @@ static void stereo_mode(struct afb_req request) if(valid) { radio_impl_ops->set_stereo_mode(mode); } else { - afb_req_fail(request, "failed", "Invalid mode"); + afb_req_reply(request, NULL, "failed", "Invalid mode"); return; } } @@ -434,16 +453,16 @@ static void stereo_mode(struct afb_req request) mode = radio_impl_ops->get_stereo_mode(); json_object_object_add(ret_json, "mode", json_object_new_string(mode == MONO ? "mono" : "stereo")); - afb_req_success(request, ret_json, NULL); + afb_req_reply(request, ret_json, NULL, NULL); } /* * @brief Subscribe for an event * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void subscribe(struct afb_req request) +static void subscribe(afb_req_t request) { const char *value = afb_req_value(request, "value"); if(value) { @@ -453,21 +472,24 @@ static void subscribe(struct afb_req request) afb_req_subscribe(request, scan_event); } else if(!strcasecmp(value, "status")) { afb_req_subscribe(request, status_event); - } else { - afb_req_fail(request, "failed", "Invalid event"); + } else if(!strcasecmp(value, "rds")) { + afb_req_subscribe(request, rds_event); + } + else { + afb_req_reply(request, NULL, "failed", "Invalid event"); return; } } - afb_req_success(request, NULL, NULL); + afb_req_reply(request, NULL, NULL, NULL); } /* * @brief Unsubscribe for an event * - * @param struct afb_req : an afb request structure + * @param afb_req_t : an afb request structure * */ -static void unsubscribe(struct afb_req request) +static void unsubscribe(afb_req_t request) { const char *value = afb_req_value(request, "value"); if(value) { @@ -477,15 +499,19 @@ static void unsubscribe(struct afb_req request) 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_fail(request, "failed", "Invalid event"); + afb_req_reply(request, NULL, "failed", "Invalid event"); return; } } - afb_req_success(request, NULL, NULL); + afb_req_reply(request, NULL, NULL, NULL); } -static const struct afb_verb_v2 verbs[]= { +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" }, @@ -502,7 +528,46 @@ static const struct afb_verb_v2 verbs[]= { { } }; -static int init() +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) { // Look for RTL-SDR USB adapter radio_impl_ops = &rtlsdr_impl_ops; @@ -512,27 +577,62 @@ static int init() radio_impl_ops = &kf_impl_ops; rc = radio_impl_ops->init(); } + if(rc != 0) { + radio_impl_ops = &tef665x_impl_ops; + rc = radio_impl_ops->init(); + } + if (rc != 0) { + radio_impl_ops = &null_impl_ops; + rc = radio_impl_ops->init(); + } if (rc != 0) { - AFB_ERROR("No radio device found, exiting"); + // We don't expect the null implementation to fail init, but just in case... + AFB_API_ERROR(afbBindingV3root, "No radio device found, exiting"); } if(rc == 0) { - AFB_NOTICE("%s found\n", radio_impl_ops->name); + AFB_API_NOTICE(afbBindingV3root, "%s found\n", radio_impl_ops->name); radio_impl_ops->set_frequency_callback(freq_callback, NULL); + if(radio_impl_ops->set_rds_callback) + { + radio_impl_ops->set_rds_callback(rds_callback); + } } else { return rc; } + 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 struct afb_binding_v2 afbBindingV2 = { +const afb_binding_t afbBindingExport = { .info = "radio service", .api = "radio", + .specification = "Radio API", .verbs = verbs, + .onevent = onevent, .init = init, }; |