2 * Copyright (C) 2015, 2016 "IoT.bzh"
3 * Author "Manuel Bachmann"
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 #include <json-c/json.h>
22 #include "radio-api.h"
23 #include "radio-rtlsdr.h"
25 #include <afb/afb-plugin.h>
26 #include <afb/afb-req-itf.h>
28 /* ********************************************************
30 FULUP integration proposal with client session context
32 ******************************************************** */
34 /* ------ LOCAL HELPER FUNCTIONS --------- */
36 static pluginHandleT *the_radio = NULL;
38 /* detect new radio devices */
39 void updateRadioDevList(pluginHandleT *handle) {
43 // loop on existing radio if any
44 for (idx = 0; idx < _radio_dev_count(); idx++) {
45 if (idx == MAX_RADIO) break;
46 handle->radios[idx] = calloc(1, sizeof(radioDevT)); /* use calloc to set "used" to FALSE */
47 handle->radios[idx]->name = (char *) _radio_dev_name(idx);
49 handle->devCount = _radio_dev_count();
52 /* global plugin context creation ; at loading time [radio devices might not be visible] */
53 static void initRadioPlugin() {
55 pluginHandleT *handle;
57 handle = calloc (1, sizeof(pluginHandleT));
58 updateRadioDevList (handle);
62 /* private client context creation ; default values */
63 static radioCtxHandleT* initRadioCtx () {
67 ctx = malloc (sizeof(radioCtxHandleT));
78 /* reserve a radio device for requesting client, power it on */
79 unsigned char reserveRadio (pluginHandleT *handle, radioCtxHandleT *ctx) {
83 /* loop on all devices, find an unused one */
84 for (idx = 0; idx < _radio_dev_count(); idx++) {
85 if (idx == MAX_RADIO) break;
86 if (handle->radios[idx]->used == FALSE) goto found_radio; /* found one */
91 /* try to power it on, passing client context info such as frequency... */
94 /* TODO : try to re-iterate from the next ones if it failed ! */
96 /* globally mark it as reserved */
97 handle->radios[idx]->used = TRUE;
99 /* store relevant info to client context (direct pointer, index) */
100 ctx->radio = handle->radios[idx];
106 /* free a radio device from requesting client, power it off */
107 unsigned char releaseRadio (pluginHandleT *handle, radioCtxHandleT *ctx) {
109 /* stop playing if it was doing this (blocks otherwise) */
110 if (ctx->is_playing) {
112 _radio_stop (ctx->idx);
116 _radio_off (ctx->idx);
118 /* globally mark it as free */
119 handle->radios[ctx->idx]->used = FALSE;
121 /* clean client context */
128 /* called when client session dies [e.g. client quits for more than 15mns] */
129 static void freeRadio (void *context) {
131 releaseRadio (the_radio, context);
136 /* ------ PUBLIC PLUGIN FUNCTIONS --------- */
138 static void init (struct afb_req request) { /* AFB_SESSION_CHECK */
140 radioCtxHandleT *ctx = afb_req_context_get (request);
143 /* create a global plugin handle */
147 /* create a private client context */
149 ctx = initRadioCtx();
150 afb_req_context_set (request, ctx, free);
153 jresp = json_object_new_object();
154 json_object_object_add(jresp, "init", json_object_new_string ("success"));
155 afb_req_success (request, jresp, "Radio initialized");
158 static void power (struct afb_req request) { /* AFB_SESSION_CHECK */
160 pluginHandleT *handle = the_radio;
161 radioCtxHandleT *ctx = afb_req_context_get (request);
162 const char *value = afb_req_value (request, "value");
166 afb_req_fail (request, "failed", "you must call 'init' first");
169 jresp = json_object_new_object();
171 /* no "?value=" parameter : return current state */
174 json_object_object_add (jresp, "power", json_object_new_string ("on"))
175 : json_object_object_add (jresp, "power", json_object_new_string ("off"));
176 afb_req_success (request, jresp, "Radio - Power status obtained");
180 /* "?value=" parameter is "1" or "true" */
181 else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) {
183 if (!reserveRadio (handle, ctx)) {
184 afb_req_fail (request, "failed", "no more radio devices available");
188 json_object_object_add (jresp, "power", json_object_new_string ("on"));
191 /* "?value=" parameter is "0" or "false" */
192 else if ( atoi(value) == 0 || !strcasecmp(value, "false") ) {
194 if (!releaseRadio (handle, ctx)) {
195 afb_req_fail (request, "failed", "Unable to release radio device");
199 json_object_object_add (jresp, "power", json_object_new_string ("off"));
204 afb_req_success (request, jresp, "Radio - Power set");
207 static void mode (struct afb_req request) { /* AFB_SESSION_CHECK */
209 radioCtxHandleT *ctx = afb_req_context_get (request);
210 const char *value = afb_req_value (request, "value");
214 afb_req_fail (request, "failed", "you must call 'init' first");
217 jresp = json_object_new_object();
219 /* no "?value=" parameter : return current state */
220 if (!value || !ctx->radio) {
222 json_object_object_add (jresp, "mode", json_object_new_string ("AM"))
223 : json_object_object_add (jresp, "mode", json_object_new_string ("FM"));
226 /* "?value=" parameter is "1" or "AM" */
227 else if ( atoi(value) == 1 || !strcasecmp(value, "AM") ) {
229 _radio_set_mode (ctx->idx, ctx->mode);
230 json_object_object_add (jresp, "mode", json_object_new_string ("AM"));
233 /* "?value=" parameter is "0" or "FM" */
234 else if ( atoi(value) == 0 || !strcasecmp(value, "FM") ) {
236 _radio_set_mode (ctx->idx, ctx->mode);
237 json_object_object_add (jresp, "mode", json_object_new_string ("FM"));
240 afb_req_success (request, jresp, "Radio - Mode set");
243 static void freq (struct afb_req request) { /* AFB_SESSION_CHECK */
245 radioCtxHandleT *ctx = afb_req_context_get (request);
246 const char *value = afb_req_value (request, "value");
252 afb_req_fail (request, "failed", "you must call 'init' first");
255 jresp = json_object_new_object();
257 /* no "?value=" parameter : return current state */
258 if (!value || !ctx->radio) {
259 snprintf (freq_str, sizeof(freq_str), "%f", ctx->freq);
260 json_object_object_add (jresp, "freq", json_object_new_string (freq_str));
263 /* "?value=" parameter, set frequency */
265 freq = strtod (value, NULL);
266 _radio_set_freq (ctx->idx, freq);
267 ctx->freq = (float)freq;
269 snprintf (freq_str, sizeof(freq_str), "%f", ctx->freq);
270 json_object_object_add (jresp, "freq", json_object_new_string (freq_str));
273 afb_req_success (request, jresp, "Radio - Frequency Set");
276 static void mute (struct afb_req request) { /* AFB_SESSION_CHECK */
278 radioCtxHandleT *ctx = afb_req_context_get (request);
279 const char *value = afb_req_value (request, "value");
280 json_object *jresp = json_object_new_object();
283 afb_req_fail (request, "failed", "you must call 'init' first");
287 /* no "?value=" parameter : return current state */
288 if (!value || !ctx->radio) {
290 json_object_object_add (jresp, "mute", json_object_new_string ("on"))
291 : json_object_object_add (jresp, "mute", json_object_new_string ("off"));
294 /* "?value=" parameter is "1" or "true" */
295 else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) {
297 _radio_set_mute (ctx->idx, ctx->mute);
298 json_object_object_add (jresp, "mute", json_object_new_string ("on"));
301 /* "?value=" parameter is "0" or "false" */
302 else if ( atoi(value) == 0 || !strcasecmp(value, "off") ) {
304 _radio_set_mute (ctx->idx, ctx->mute);
305 json_object_object_add (jresp, "mute", json_object_new_string ("off"));
308 afb_req_success (request, jresp, "Radio - Mute set");
311 static void play (struct afb_req request) { /* AFB_SESSION_CHECK */
313 radioCtxHandleT *ctx = afb_req_context_get (request);
314 const char *value = afb_req_value (request, "value");
315 json_object *jresp = json_object_new_object();
318 afb_req_fail (request, "failed", "you must call 'init' first");
322 /* no "?value=" parameter : return current state */
323 if (!value || !ctx->radio) {
325 json_object_object_add (jresp, "play", json_object_new_string ("on"))
326 : json_object_object_add (jresp, "play", json_object_new_string ("off"));
329 /* "?value=" parameter is "1" or "true" */
330 else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) {
333 _radio_play (ctx->idx);
334 json_object_object_add (jresp, "play", json_object_new_string ("on"));
337 /* "?value=" parameter is "0" or "false" */
338 else if ( atoi(value) == 0 || !strcasecmp(value, "false") ) {
341 _radio_stop (ctx->idx);
342 json_object_object_add (jresp, "play", json_object_new_string ("off"));
345 afb_req_success (request, jresp, "Radio - Play succeeded");
348 static void ping (struct afb_req request) { /* AFB_SESSION_NONE */
349 afb_req_success (request, NULL, "Radio - Ping succeeded");
353 static const struct AFB_verb_desc_v1 verbs[] = {
354 {"init" , AFB_SESSION_CHECK, init , "Radio API - init"},
355 {"power" , AFB_SESSION_CHECK, power , "Radio API - power"},
356 {"mode" , AFB_SESSION_CHECK, mode , "Radio API - mode"},
357 {"freq" , AFB_SESSION_CHECK, freq , "Radio API - freq"},
358 {"mute" , AFB_SESSION_CHECK, mute , "Radio API - mute"},
359 {"play" , AFB_SESSION_CHECK, play , "Radio API - play"},
360 {"ping" , AFB_SESSION_NONE, ping , "Radio API - ping"},
364 static const struct AFB_plugin pluginDesc = {
365 .type = AFB_PLUGIN_VERSION_1,
367 .info = "Application Framework Binder - Radio plugin",
373 const struct AFB_plugin *pluginAfbV1Register (const struct AFB_interface *itf)