X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fradio-api.c;h=ef34504448984e7896bd2979bb5863c99700138d;hb=1250a56369315c017abfe429c556b863730b9b44;hp=37da4ebca31fe94910127a9e6b333e5f6c02af1d;hpb=335eeec7aaf944d66cac87b5bb3f64f8fc7e385e;p=src%2Fapp-framework-binder.git diff --git a/src/radio-api.c b/src/radio-api.c index 37da4ebc..ef345044 100644 --- a/src/radio-api.c +++ b/src/radio-api.c @@ -33,6 +33,7 @@ typedef enum { FM, AM } Mode; typedef struct dongle_ctx dongle_ctx; typedef struct demod_ctx demod_ctx; typedef struct output_ctx output_ctx; +typedef struct dev_ctx dev_ctx_T; struct dongle_ctx { pthread_t thr; @@ -66,6 +67,7 @@ struct output_ctx { }; struct dev_ctx { + int used; // radio is free ??? rtlsdr_dev_t* dev; Mode mode; float freq; @@ -78,32 +80,34 @@ struct dev_ctx { }; -void* _dongle_thread_fn (void *); -void* _demod_thread_fn (void *); -void* _output_thread_fn (void *); -unsigned int _radio_dev_count (void); -const char* _radio_dev_name (unsigned int); -unsigned char _radio_dev_init (struct dev_ctx *, unsigned int); -unsigned char _radio_dev_free (struct dev_ctx *); -void _radio_apply_params (struct dev_ctx *); -void _radio_start_threads (struct dev_ctx *); -void _radio_stop_threads (struct dev_ctx *); +STATIC void* _dongle_thread_fn (void *); +STATIC void* _demod_thread_fn (void *); +STATIC void* _output_thread_fn (void *); +STATIC unsigned int _radio_dev_count (void); +STATIC const char* _radio_dev_name (unsigned int); +STATIC unsigned char _radio_dev_init (struct dev_ctx *, unsigned int); +STATIC unsigned char _radio_dev_free (struct dev_ctx *); +STATIC void _radio_apply_params (struct dev_ctx *); +STATIC void _radio_start_threads (struct dev_ctx *); +STATIC void _radio_stop_threads (struct dev_ctx *); static unsigned int init_dev_count; static struct dev_ctx **dev_ctx; /* ------------- RADIO IMPLEMENTATION ----------------- */ - /* ---- PUBLIC FUNCTIONS --- */ -void radio_on () { +// Radio initialization should be done only when user start the radio and not at plugin initialization +// Making this call too early would impose to restart the binder to detect a radio. +STATIC void initRadio () { + init_dev_count = _radio_dev_count(); int i; - dev_ctx = (struct dev_ctx**) malloc(init_dev_count * sizeof(struct dev_ctx)); + dev_ctx = (dev_ctx_T**) malloc(init_dev_count * sizeof(dev_ctx_T)); for (i = 0; i < init_dev_count; i++) { - dev_ctx[i] = (struct dev_ctx*) malloc(sizeof(struct dev_ctx)); + dev_ctx[i] = (dev_ctx_T*) malloc(sizeof(dev_ctx_T)); dev_ctx[i]->dev = NULL; dev_ctx[i]->mode = FM; dev_ctx[i]->freq = 100.0; @@ -116,7 +120,7 @@ void radio_on () { } } -void radio_off () { +STATIC void radio_off () { int i; for (i = 0; i < init_dev_count; i++) { @@ -126,40 +130,40 @@ void radio_off () { free(dev_ctx); } -void radio_set_mode (struct dev_ctx *dev_ctx, Mode mode) { +STATIC void radio_set_mode (dev_ctx_T *dev_ctx, Mode mode) { dev_ctx->mode = mode; _radio_apply_params(dev_ctx); } -void radio_set_freq (struct dev_ctx *dev_ctx, float freq) { +STATIC void radio_set_freq (dev_ctx_T *dev_ctx, float freq) { dev_ctx->freq = freq; _radio_apply_params(dev_ctx); } -void radio_set_mute (struct dev_ctx *dev_ctx, unsigned char mute) { +STATIC void radio_set_mute (dev_ctx_T *dev_ctx, unsigned char mute) { dev_ctx->mute = mute; _radio_apply_params(dev_ctx); } -void radio_play (struct dev_ctx *dev_ctx) { +STATIC void radio_play (dev_ctx_T *dev_ctx) { _radio_start_threads(dev_ctx); } -void radio_stop (struct dev_ctx *dev_ctx) { +STATIC void radio_stop (dev_ctx_T *dev_ctx) { _radio_stop_threads(dev_ctx); } /* --- HELPER FUNCTIONS --- */ -unsigned int _radio_dev_count () { +STATIC unsigned int _radio_dev_count () { return rtlsdr_get_device_count(); } -const char* _radio_dev_name (unsigned int num) { +STATIC const char* _radio_dev_name (unsigned int num) { return rtlsdr_get_device_name(num); } -unsigned char _radio_dev_init (struct dev_ctx *dev_ctx, unsigned int num) { +STATIC unsigned char _radio_dev_init (dev_ctx_T *dev_ctx, unsigned int num) { rtlsdr_dev_t *dev = dev_ctx->dev; if (rtlsdr_open(&dev, num) < 0) @@ -170,24 +174,26 @@ unsigned char _radio_dev_init (struct dev_ctx *dev_ctx, unsigned int num) { if (rtlsdr_reset_buffer(dev) < 0) return 0; - // dev_ctx->dev = dev; REQUIRED IN C TOO ? TEST ! + dev_ctx->dev = dev; _radio_apply_params(dev_ctx); return 1; } -unsigned char _radio_dev_free (struct dev_ctx *dev_ctx) { +STATIC unsigned char _radio_dev_free (dev_ctx_T *dev_ctx) { rtlsdr_dev_t *dev = dev_ctx->dev; if (rtlsdr_close(dev) < 0) return 0; dev = NULL; + dev_ctx->dev = dev; + return 1; } -void _radio_apply_params (struct dev_ctx *dev_ctx) { +STATIC void _radio_apply_params (dev_ctx_T *dev_ctx) { rtlsdr_dev_t *dev = dev_ctx->dev; Mode mode = dev_ctx->mode; float freq = dev_ctx->freq; @@ -203,10 +209,10 @@ void _radio_apply_params (struct dev_ctx *dev_ctx) { rtlsdr_set_center_freq(dev, freq); rtlsdr_set_sample_rate(dev, rate); - // dev_ctx->dev = dev; REQUIRED IN C TOO ? TEST ! + dev_ctx->dev = dev; } -void _radio_start_threads (struct dev_ctx *dev_ctx) { +STATIC void _radio_start_threads (dev_ctx_T *dev_ctx) { rtlsdr_dev_t *dev = dev_ctx->dev; dev_ctx->dongle = (dongle_ctx*) malloc(sizeof(dongle_ctx)); dev_ctx->demod = (demod_ctx*) malloc(sizeof(demod_ctx)); @@ -241,7 +247,7 @@ void _radio_start_threads (struct dev_ctx *dev_ctx) { pthread_create(&output->thr, NULL, _output_thread_fn, (void*)dev_ctx); } -void _radio_stop_threads (struct dev_ctx *dev_ctx) { +STATIC void _radio_stop_threads (dev_ctx_T *dev_ctx) { rtlsdr_dev_t *dev = dev_ctx->dev; dongle_ctx *dongle = dev_ctx->dongle; demod_ctx *demod = dev_ctx->demod; @@ -279,8 +285,8 @@ void _radio_stop_threads (struct dev_ctx *dev_ctx) { /* ---- LOCAL THREADED FUNCTIONS ---- */ -static void _rtlsdr_callback (unsigned char *buf, uint32_t len, void *ctx) { - struct dev_ctx *dev_ctx = (struct dev_ctx *)ctx; +STATIC void _rtlsdr_callback (unsigned char *buf, uint32_t len, void *ctx) { + dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx; dongle_ctx *dongle = dev_ctx->dongle; demod_ctx *demod = dev_ctx->demod; unsigned char tmp; @@ -315,9 +321,9 @@ static void _rtlsdr_callback (unsigned char *buf, uint32_t len, void *ctx) { pthread_signal(&demod->ok, &demod->ok_m); } /**/ -void* _dongle_thread_fn (void *ctx) { - struct dev_ctx *dev_ctx = (struct dev_ctx *)ctx; - struct dongle_ctx *dongle = dev_ctx->dongle; +STATIC void* _dongle_thread_fn (void *ctx) { + dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx; + dongle_ctx *dongle = dev_ctx->dongle; rtlsdr_read_async(dev_ctx->dev, _rtlsdr_callback, dev_ctx, 0, 0); @@ -325,7 +331,7 @@ void* _dongle_thread_fn (void *ctx) { return 0; } -void _lowpass_demod (void *ctx) { +STATIC void _lowpass_demod (void *ctx) { demod_ctx *demod = (demod_ctx *)ctx; int i=0, i2=0; @@ -345,7 +351,7 @@ void _lowpass_demod (void *ctx) { demod->buf_len = i2; } /**/ -void _lowpassreal_demod (void *ctx) { +STATIC void _lowpassreal_demod (void *ctx) { demod_ctx *demod = (demod_ctx *)ctx; int i=0, i2=0; int fast = 200000; @@ -365,12 +371,12 @@ void _lowpassreal_demod (void *ctx) { demod->res_len = i2; } /**/ -void _multiply (int ar, int aj, int br, int bj, int *cr, int *cj) { +STATIC void _multiply (int ar, int aj, int br, int bj, int *cr, int *cj) { *cr = ar*br - aj*bj; *cj = aj*br + ar*bj; } /**/ -int _polar_discriminant (int ar, int aj, int br, int bj) { +STATIC int _polar_discriminant (int ar, int aj, int br, int bj) { int cr, cj; double angle; _multiply(ar, aj, br, -bj, &cr, &cj); @@ -378,7 +384,7 @@ int _polar_discriminant (int ar, int aj, int br, int bj) { return (int)(angle / 3.14159 * (1<<14)); } /**/ -void _fm_demod (void *ctx) { +STATIC void _fm_demod (void *ctx) { demod_ctx *demod = (demod_ctx *)ctx; int16_t *buf = demod->buf; int buf_len = demod->buf_len; @@ -396,7 +402,7 @@ void _fm_demod (void *ctx) { demod->res_len = buf_len/2; } /**/ -void _am_demod (void *ctx) { +STATIC void _am_demod (void *ctx) { demod_ctx *demod = (demod_ctx *)ctx; int16_t *buf = demod->buf; int buf_len = demod->buf_len; @@ -410,8 +416,8 @@ void _am_demod (void *ctx) { demod->res_len = buf_len/2; } /**/ -void* _demod_thread_fn (void *ctx) { - struct dev_ctx *dev_ctx = (struct dev_ctx *)ctx; +STATIC void* _demod_thread_fn (void *ctx) { + dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx; demod_ctx *demod = dev_ctx->demod; output_ctx *output = dev_ctx->output; @@ -438,8 +444,8 @@ void* _demod_thread_fn (void *ctx) { return 0; } -void* _output_thread_fn (void *ctx) { - struct dev_ctx *dev_ctx = (struct dev_ctx *)ctx; +STATIC void* _output_thread_fn (void *ctx) { + dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx; output_ctx *output = dev_ctx->output; while (dev_ctx->should_run) { @@ -454,7 +460,7 @@ void* _output_thread_fn (void *ctx) { return 0; } -/* -------------- PLUGIN BINDING ------------------- */ + STATIC json_object* start (AFB_session *session, AFB_request *request, void* handle) { json_object *response; @@ -487,23 +493,171 @@ STATIC json_object* stop (AFB_session *session, AFB_request *request, void* hand } -STATIC struct { - void * somedata; -} handle; +// ******************************************************** + +// FULUP integration proposal with client session context + +// ******************************************************** + + +#define MAX_RADIO 10 + +// Structure holding existing radio with current usage status +typedef struct { + int idx; + char *name; + int used; +} radioDevT; + +// Radio plugin handle should store everething API may need +typedef struct { + radioDevT *radios[MAX_RADIO]; // pointer to existing radio + int devCount; +} pluginHandleT; + +// Client Context Structure Hold any specific to client [will be destroyed when client leave] +typedef struct { + dev_ctx_T radio; // pointer to client radio + int idx; // index of radio within global array +} ctxHandleT; + + +// It his was not a demo only, it should be smarter to enable hot plug/unplug +STATIC void updateRadioDevList(pluginHandleT *handle) { + int idx; + + // loop on existing radio if any + for (idx = 0; idx < _radio_dev_count(); idx++) { + if (idx == MAX_RADIO) break; + handle->radios[idx] = calloc(1, sizeof(radioDevT)); // use calloc to set used to FALSE + handle->radios[idx]->name = (char *) _radio_dev_name(idx); + } + handle->devCount = _radio_dev_count(); +} + + +// This is call at plugin load time [radio devices might still not be visible] +STATIC pluginHandleT* initRadioPlugin() { + + // Allocate Plugin handle + pluginHandleT *handle = calloc (1,sizeof (pluginHandleT)); // init handle with zero + + // Some initialization steps + updateRadioDevList(handle); + + return (handle); +} + +// Stop a radio free related ressource and make it avaliable for other clients +STATIC AFB_error releaseRadio (pluginHandleT* handle, ctxHandleT *ctx) { + + // change radio status + (handle->radios[ctx->idx])->used = FALSE; + + // stop related threads and free attached resources + radio_stop (&ctx->radio); + + // May be some further cleanup ???? + + return (AFB_SUCCESS); // Could it fails ???? +} + + +// Start a radio and reserve exclusive usage to requesting client +STATIC ctxHandleT *reserveRadio (pluginHandleT* handle) { + ctxHandleT *client; + int idx; + + // loop on existing radio if any + for (idx = 0; idx < _radio_dev_count(); idx++) { + if ((handle->radios[client->idx])->used = FALSE) break; + } + + // No avaliable radio return now + if (idx == MAX_RADIO) return (NULL); + + // Book radio + (handle->radios[client->idx])->used = TRUE; + + // create client handle + client = calloc (1, sizeof (ctxHandleT)); + + // stop related threads and free attached resources + _radio_start_threads (&client->radio); + + // May be some things to do ???? + + + return (client); +} + +// This is called when client session died [ex; client quit for more than 15mn] +STATIC json_object* freeRadio () { + + //releaseRadio (client->handle, client); + //free (client); +} + + +STATIC json_object* powerOnOff (AFB_request *request) { + json_object *jresp; + AFB_clientCtx *client = request->client; // get client context from request + + // Make sure binder was started with client session + if (client == NULL) { + request->errcode=MHD_HTTP_FORBIDDEN; + return (jsonNewMessage(AFB_FAIL, "Radio binder need session [--token=xxxx]")); + } + + // If we have a handle radio was on let power it down + if (client->ctx != NULL) { + dev_ctx_T *dev_ctx = (dev_ctx_T *)client->ctx; + + releaseRadio (client->plugin->handle, client->ctx); // poweroff client related radio + + jresp = json_object_new_object(); + json_object_object_add(jresp, "power", json_object_new_string ("off")); + return (jresp); + } + + // request a new client context token and check result + if (AFB_UNAUTH == ctxTokenCreate (request)) { + request->errcode=MHD_HTTP_UNAUTHORIZED; + jresp= jsonNewMessage(AFB_FAIL, "You're not authorized to request a radio [make sure you have the right authentication token"); + return (jresp); + } + + // Client is clean let's look it we have an avaliable radio to propose + + // make sure we have last hot plug dongle visible + updateRadioDevList (client->plugin->handle); + + // get try to get an unused radio + client->ctx = reserveRadio (client->plugin->handle); + if (client->ctx == NULL) { + return (jsonNewMessage(AFB_FAIL, "Sory No More Radio Avaliable")); + } + + // At this point we should have something to retreive radio status before last poweroff [but this is only a demonstrator] +} STATIC AFB_restapi pluginApis[]= { - {"start" , (AFB_apiCB)start , "Ping Application Framework", NULL}, - {"stop" , (AFB_apiCB)stop , "Ping Application Framework", NULL}, - {0,0,0} + {"power" , (AFB_apiCB)powerOnOff , "Ping Application Framework"}, + {"start" , (AFB_apiCB)start , "Ping Application Framework"}, + {"stop" , (AFB_apiCB)stop , "Ping Application Framework"}, + {NULL} }; PUBLIC AFB_plugin *radioRegister (AFB_session *session) { AFB_plugin *plugin = malloc (sizeof (AFB_plugin)); - plugin->type = AFB_PLUGIN; + plugin->type = AFB_PLUGIN_JSON; plugin->info = "Application Framework Binder - Radio plugin"; plugin->prefix = "radio"; plugin->apis = pluginApis; + + plugin->handle = initRadioPlugin(); + plugin->freeCtxCB = freeRadio; return (plugin); };