Add Middleware and change Hashtable techno
[src/app-framework-binder.git] / src / radio-api.c
1 /*
2  * Copyright (C) 2015 "IoT.bzh"
3  * Author "Manuel Bachmann"
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "local-def.h"
21
22 /* -------------- RADIO DEFINITIONS ------------------ */
23
24 #include <math.h>
25 #include <pthread.h>
26 #include <rtl-sdr.h>
27
28 #define pthread_signal(n, m) pthread_mutex_lock(m); pthread_cond_signal(n); pthread_mutex_unlock(m)
29 #define pthread_wait(n, m) pthread_mutex_lock(m); pthread_cond_wait(n, m); pthread_mutex_unlock(m)
30 #define BUF_LEN 16*16384
31
32 typedef enum { FM, AM } Mode;
33 typedef struct dongle_ctx dongle_ctx;
34 typedef struct demod_ctx demod_ctx;
35 typedef struct output_ctx output_ctx;
36 typedef struct dev_ctx dev_ctx_T;
37
38 struct dongle_ctx {
39     pthread_t thr;
40     unsigned char thr_finished;
41     uint16_t buf[BUF_LEN];
42     uint32_t buf_len;
43 };
44
45 struct demod_ctx {
46     pthread_t thr;
47     unsigned char thr_finished;
48     pthread_rwlock_t lck;
49     pthread_cond_t ok;
50     pthread_mutex_t ok_m;
51     int pre_r, pre_j, now_r, now_j, index;
52     int pre_index, now_index;
53     int16_t buf[BUF_LEN];
54     int buf_len;
55     int16_t res[BUF_LEN];
56     int res_len;
57 };
58
59 struct output_ctx {
60     pthread_t thr;
61     unsigned char thr_finished;
62     pthread_rwlock_t lck;
63     pthread_cond_t ok;
64     pthread_mutex_t ok_m;
65     int16_t buf[BUF_LEN];
66     int buf_len;
67 };
68
69 struct dev_ctx {
70     int used;  // radio is free ???
71     rtlsdr_dev_t* dev;
72     Mode mode;
73     float freq;
74     unsigned char mute;
75     unsigned char should_run;
76      /* thread contexts */
77     dongle_ctx *dongle;
78     demod_ctx *demod;
79     output_ctx *output;
80 };
81
82
83 STATIC void* _dongle_thread_fn (void *);
84 STATIC void* _demod_thread_fn (void *);
85 STATIC void* _output_thread_fn (void *);
86 STATIC unsigned int _radio_dev_count (void);
87 STATIC const char* _radio_dev_name (unsigned int);
88 STATIC unsigned char _radio_dev_init (struct dev_ctx *, unsigned int);
89 STATIC unsigned char _radio_dev_free (struct dev_ctx *);
90 STATIC void _radio_apply_params (struct dev_ctx *);
91 STATIC void _radio_start_threads (struct dev_ctx *);
92 STATIC void _radio_stop_threads (struct dev_ctx *);
93
94 static unsigned int init_dev_count;
95 static struct dev_ctx **dev_ctx;
96
97 /* ------------- RADIO IMPLEMENTATION ----------------- */
98
99
100 // Radio initialization should be done only when user start the radio and not at plugin initialization
101 // Making this call too early would impose to restart the binder to detect a radio.
102 STATIC void initRadio () {
103  
104     init_dev_count = _radio_dev_count();
105     int i;
106
107     dev_ctx = (dev_ctx_T**) malloc(init_dev_count * sizeof(dev_ctx_T));
108
109     for (i = 0; i < init_dev_count; i++) {
110         dev_ctx[i] = (dev_ctx_T*) malloc(sizeof(dev_ctx_T));
111         dev_ctx[i]->dev = NULL;
112         dev_ctx[i]->mode = FM;
113         dev_ctx[i]->freq = 100.0;
114         dev_ctx[i]->mute = 0;
115         dev_ctx[i]->should_run = 0;
116         dev_ctx[i]->dongle = NULL;
117         dev_ctx[i]->demod = NULL;
118         dev_ctx[i]->output = NULL;
119         _radio_dev_init(dev_ctx[i], i);
120     }
121 }
122
123 STATIC void radio_off () {
124     int i;
125
126     for (i = 0; i < init_dev_count; i++) {
127         _radio_dev_free(dev_ctx[i]);
128         free(dev_ctx[i]);
129     }
130     free(dev_ctx);
131 }
132
133 STATIC void radio_set_mode (dev_ctx_T *dev_ctx, Mode mode) {
134     dev_ctx->mode = mode;
135     _radio_apply_params(dev_ctx);
136 }
137
138 STATIC void radio_set_freq (dev_ctx_T *dev_ctx, float freq) {
139     dev_ctx->freq = freq;
140     _radio_apply_params(dev_ctx);
141 }
142
143 STATIC void radio_set_mute (dev_ctx_T *dev_ctx, unsigned char mute) {
144     dev_ctx->mute = mute;
145     _radio_apply_params(dev_ctx);
146 }
147
148 STATIC void radio_play (dev_ctx_T *dev_ctx) {
149     _radio_start_threads(dev_ctx);
150 }
151
152 STATIC void radio_stop (dev_ctx_T *dev_ctx) {
153     _radio_stop_threads(dev_ctx);
154 }
155
156  /* --- HELPER FUNCTIONS --- */
157
158 STATIC unsigned int _radio_dev_count () {
159     return rtlsdr_get_device_count();
160 }
161
162 STATIC const char* _radio_dev_name (unsigned int num) {
163     return rtlsdr_get_device_name(num);
164 }
165
166 STATIC unsigned char _radio_dev_init (dev_ctx_T *dev_ctx, unsigned int num) {
167     rtlsdr_dev_t *dev = dev_ctx->dev;
168
169     if (rtlsdr_open(&dev, num) < 0)
170         return 0;
171
172     rtlsdr_set_tuner_gain_mode(dev, 0);
173
174     if (rtlsdr_reset_buffer(dev) < 0)
175         return 0;
176
177     dev_ctx->dev = dev;
178
179     _radio_apply_params(dev_ctx);
180
181     return 1;
182 }
183
184 STATIC unsigned char _radio_dev_free (dev_ctx_T *dev_ctx) {
185     rtlsdr_dev_t *dev = dev_ctx->dev;
186
187     if (rtlsdr_close(dev) < 0)
188         return 0;
189     dev = NULL;
190
191     dev_ctx->dev = dev;
192
193     return 1;
194 }
195
196 STATIC void _radio_apply_params (dev_ctx_T *dev_ctx) {
197     rtlsdr_dev_t *dev = dev_ctx->dev;
198     Mode mode = dev_ctx->mode;
199     float freq = dev_ctx->freq;
200     int rate;
201
202     freq *= 1000000;
203     rate = ((1000000 / 200000) + 1) * 200000;
204
205     if (mode == FM)
206         freq += 16000;
207     freq += rate / 4;
208
209     rtlsdr_set_center_freq(dev, freq);
210     rtlsdr_set_sample_rate(dev, rate);
211
212     dev_ctx->dev = dev;
213 }
214
215 STATIC void _radio_start_threads (dev_ctx_T *dev_ctx) {
216     rtlsdr_dev_t *dev = dev_ctx->dev;
217     dev_ctx->dongle = (dongle_ctx*) malloc(sizeof(dongle_ctx));
218     dev_ctx->demod = (demod_ctx*) malloc(sizeof(demod_ctx));
219     dev_ctx->output = (output_ctx*) malloc(sizeof(output_ctx));
220
221     dongle_ctx *dongle = dev_ctx->dongle;
222     demod_ctx *demod = dev_ctx->demod;
223     output_ctx *output = dev_ctx->output;
224
225     pthread_rwlock_init(&demod->lck, NULL);
226     pthread_cond_init(&demod->ok, NULL);
227     pthread_mutex_init(&demod->ok_m, NULL);
228     pthread_rwlock_init(&output->lck, NULL);
229     pthread_cond_init(&output->ok, NULL);
230     pthread_mutex_init(&output->ok_m, NULL);
231
232     dev_ctx->should_run = 1;
233
234      /* dongle thread */
235     dongle->thr_finished = 0;
236     pthread_create(&dongle->thr, NULL, _dongle_thread_fn, (void*)dev_ctx);
237
238      /* demod thread */
239     demod->pre_r = demod->pre_j = 0;
240     demod->now_r = demod->now_j = 0;
241     demod->index = demod->pre_index = demod->now_index = 0;
242     demod->thr_finished = 0;
243     pthread_create(&demod->thr, NULL, _demod_thread_fn, (void*)dev_ctx);
244
245      /* output thread */
246     output->thr_finished = 0;
247     pthread_create(&output->thr, NULL, _output_thread_fn, (void*)dev_ctx);
248 }
249
250 STATIC void _radio_stop_threads (dev_ctx_T *dev_ctx) {
251     rtlsdr_dev_t *dev = dev_ctx->dev;
252     dongle_ctx *dongle = dev_ctx->dongle;
253     demod_ctx *demod = dev_ctx->demod;
254     output_ctx *output = dev_ctx->output;
255
256     if (!dongle || !demod || !output)
257         return;
258
259      /* stop each "while" loop in threads */
260     dev_ctx->should_run = 0;
261
262     rtlsdr_cancel_async(dev);
263     pthread_signal(&demod->ok, &demod->ok_m);
264     pthread_signal(&output->ok, &output->ok_m);
265
266     while (!dongle->thr_finished ||
267            !demod->thr_finished ||
268            !output->thr_finished)
269         usleep(100000);
270
271     pthread_join(dongle->thr, NULL);
272     pthread_join(demod->thr, NULL);
273     pthread_join(output->thr, NULL);
274     pthread_rwlock_destroy(&demod->lck);
275     pthread_cond_destroy(&demod->ok);
276     pthread_mutex_destroy(&demod->ok_m);
277     pthread_rwlock_destroy(&output->lck);
278     pthread_cond_destroy(&output->ok);
279     pthread_mutex_destroy(&output->ok_m);
280
281     free(dongle); dev_ctx->dongle = NULL;
282     free(demod); dev_ctx->demod = NULL;
283     free(output); dev_ctx->output = NULL;
284 }
285
286  /* ---- LOCAL THREADED FUNCTIONS ---- */
287
288 STATIC void _rtlsdr_callback (unsigned char *buf, uint32_t len, void *ctx) {
289     dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx;
290     dongle_ctx *dongle = dev_ctx->dongle;
291     demod_ctx *demod = dev_ctx->demod;
292     unsigned char tmp;
293     int i;
294
295     if (!dev_ctx->should_run)
296         return;
297
298      /* rotate 90° */
299     for (i = 0; i < (int)len; i += 8) {
300         tmp = 255 - buf[i+3];
301         buf[i+3] = buf[i+2];
302         buf[i+2] = tmp;
303
304         buf[i+4] = 255 - buf[i+4];
305         buf[i+5] = 255 - buf[i+5];
306
307         tmp = 255 - buf[i+6];
308         buf[i+6] = buf[i+7];
309         buf[i+7] = tmp;
310     }
311
312      /* write data */
313     for (i = 0; i < (int)len; i++)
314         dongle->buf[i] = (int16_t)buf[i] - 127;
315
316      /* lock demod thread, write to it, unlock */
317        pthread_rwlock_wrlock(&demod->lck);
318     memcpy(demod->buf, dongle->buf, 2 * len);
319     demod->buf_len = len;
320        pthread_rwlock_unlock(&demod->lck);
321        pthread_signal(&demod->ok, &demod->ok_m);
322 }
323  /**/
324 STATIC void* _dongle_thread_fn (void *ctx) {
325     dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx;
326     dongle_ctx *dongle = dev_ctx->dongle;
327
328     rtlsdr_read_async(dev_ctx->dev, _rtlsdr_callback, dev_ctx, 0, 0);
329
330     dongle->thr_finished = 1;
331     return 0;
332 }
333
334 STATIC void _lowpass_demod (void *ctx) {
335     demod_ctx *demod = (demod_ctx *)ctx;
336     int i=0, i2=0;
337
338     while (i < demod->buf_len) {
339         demod->now_r += demod->buf[i];
340         demod->now_j += demod->buf[i+1];
341         i += 2;
342         demod->index++;
343         if (demod->index < ((1000000 / 200000) + 1))
344             continue;
345         demod->buf[i2] = demod->now_r;
346         demod->buf[i2+1] = demod->now_j;
347         demod->index = 0;
348         demod->now_r = demod->now_j = 0;
349         i2 += 2;
350     }
351     demod->buf_len = i2;
352 }
353  /**/
354 STATIC void _lowpassreal_demod (void *ctx) {
355     demod_ctx *demod = (demod_ctx *)ctx;
356     int i=0, i2=0;
357     int fast = 200000;
358     int slow = 48000;
359
360     while (i < demod->res_len) {
361         demod->now_index += demod->res[i];
362         i++;
363         demod->pre_index += slow;
364         if (demod->pre_index < fast)
365             continue;
366         demod->res[i2] = (int16_t)(demod->now_index / (fast/slow));
367         demod->pre_index -= fast;
368         demod->now_index = 0;
369         i2 += 1;
370     }
371     demod->res_len = i2;
372 }
373  /**/
374 STATIC void _multiply (int ar, int aj, int br, int bj, int *cr, int *cj) {
375     *cr = ar*br - aj*bj;
376     *cj = aj*br + ar*bj;
377 }
378  /**/
379 STATIC int _polar_discriminant (int ar, int aj, int br, int bj) {
380     int cr, cj;
381     double angle;
382     _multiply(ar, aj, br, -bj, &cr, &cj);
383     angle = atan2((double)cj, (double)cr);
384     return (int)(angle / 3.14159 * (1<<14));
385 }
386  /**/
387 STATIC void _fm_demod (void *ctx) {
388     demod_ctx *demod = (demod_ctx *)ctx;
389     int16_t *buf = demod->buf;
390     int buf_len = demod->buf_len;
391     int pcm, i;
392
393     pcm = _polar_discriminant(buf[0], buf[1], demod->pre_r, demod->pre_j);
394     demod->res[0] = (int16_t)pcm;
395
396     for (i = 2; i < (buf_len-1); i += 2) {
397         pcm = _polar_discriminant(buf[i], buf[i+1], buf[i-2], buf[i-1]);
398         demod->res[i/2] = (int16_t)pcm;
399     }
400     demod->pre_r = buf[buf_len - 2];
401     demod->pre_j = buf[buf_len - 1];
402     demod->res_len = buf_len/2;
403 }
404  /**/
405 STATIC void _am_demod (void *ctx) {
406     demod_ctx *demod = (demod_ctx *)ctx;
407     int16_t *buf = demod->buf;
408     int buf_len = demod->buf_len;
409     int pcm, i;
410
411     for (i = 0; i < buf_len; i += 2) {
412         pcm = buf[i] * buf[i];
413         pcm += buf[i+1] * buf[i+1];
414         demod->res[i/2] = (int16_t)sqrt(pcm);
415     }
416     demod->res_len = buf_len/2;
417 }
418  /**/
419 STATIC void* _demod_thread_fn (void *ctx) {
420     dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx;
421     demod_ctx *demod = dev_ctx->demod;
422     output_ctx *output = dev_ctx->output;
423
424     while(dev_ctx->should_run) {
425             pthread_wait(&demod->ok, &demod->ok_m);
426             pthread_rwlock_wrlock(&demod->lck);
427         _lowpass_demod(demod);
428         if (dev_ctx->mode == FM)
429             _fm_demod(demod);
430         else
431             _am_demod(demod);
432         _lowpassreal_demod(demod);
433            pthread_rwlock_unlock(&demod->lck);
434
435          /* lock demod thread, write to it, unlock */
436            pthread_rwlock_wrlock(&output->lck);
437         memcpy(output->buf, demod->res, 2 * demod->res_len);
438         output->buf_len = demod->res_len;
439            pthread_rwlock_unlock(&output->lck);
440            pthread_signal(&output->ok, &output->ok_m);
441     }
442
443     demod->thr_finished = 1;
444     return 0;
445 }
446
447 STATIC void* _output_thread_fn (void *ctx) {
448     dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx;
449     output_ctx *output = dev_ctx->output;
450
451     while (dev_ctx->should_run) {
452            pthread_wait(&output->ok, &output->ok_m);
453            pthread_rwlock_rdlock(&output->lck);
454         //if (!dev_ctx->mute)
455         //    mRadio->PlayAlsa((void*)&output->buf, output->buf_len);
456            pthread_rwlock_unlock(&output->lck);
457     }
458
459     output->thr_finished = 1;
460     return 0;
461 }
462
463
464
465 STATIC json_object* start (AFB_session *session, AFB_request *request, void* handle) {
466     json_object *response;
467     char query [512];
468
469     // request all query key/value
470     getQueryAll (request, query, sizeof(query));
471
472     // check if we have some post data
473     if (request->post == NULL)  request->post="NoData";
474
475     // return response to caller
476     response = jsonNewMessage(AFB_SUCCESS, "Start Radio plugin query={%s} PostData: \'%s\' ", query, request->post);
477
478     //if (verbose) fprintf(stderr, "%d: \n", pingcount);
479     return (response);
480 }
481
482 STATIC json_object* stop (AFB_session *session, AFB_request *request, void* handle) {
483     json_object *response;
484     char query [512];
485
486     getQueryAll (request, query, sizeof(query));
487
488     if (request->post == NULL)  request->post="NoData";
489
490     response = jsonNewMessage(AFB_SUCCESS, "Stop Radio plugin query={%s} PostData: \'%s\' ", query, request->post);
491
492     return (response);
493 }
494
495
496 // ********************************************************
497
498 // FULUP integration proposal with client session context
499
500 // ********************************************************
501
502
503 #define MAX_RADIO 10
504
505 // Structure holding existing radio with current usage status
506 typedef struct {
507     int   idx;
508     char *name;
509     int  used;
510 } radioDevT;
511
512 // Radio plugin handle should store everething API may need
513 typedef struct {
514   radioDevT *radios[MAX_RADIO];  // pointer to existing radio
515   int devCount;
516 } pluginHandleT;
517
518 // Client Context Structure Hold any specific to client [will be destroyed when client leave]
519 typedef struct {
520     dev_ctx_T radio;       // pointer to client radio
521     int idx;               // index of radio within global array
522 } ctxHandleT;
523
524
525 // It his was not a demo only, it should be smarter to enable hot plug/unplug
526 STATIC void updateRadioDevList(pluginHandleT *handle) {
527   int idx;  
528
529   // loop on existing radio if any
530   for (idx = 0; idx < _radio_dev_count(); idx++) {
531       if (idx == MAX_RADIO) break;
532       handle->radios[idx] = calloc(1, sizeof(radioDevT)); // use calloc to set used to FALSE
533       handle->radios[idx]->name = (char *) _radio_dev_name(idx); 
534   }
535   handle->devCount = _radio_dev_count();
536 }
537
538
539 // This is call at plugin load time [radio devices might still not be visible]
540 STATIC pluginHandleT* initRadioPlugin() {
541
542   // Allocate Plugin handle  
543   pluginHandleT *handle = calloc (1,sizeof (pluginHandleT)); // init handle with zero
544
545   // Some initialization steps
546   updateRadioDevList(handle);
547
548   return (handle);
549 }
550
551 // Stop a radio free related ressource and make it avaliable for other clients
552 STATIC AFB_error releaseRadio (pluginHandleT* handle, ctxHandleT *ctx) {
553     
554    // change radio status
555    (handle->radios[ctx->idx])->used = FALSE;
556
557    // stop related threads and free attached resources
558    radio_stop (&ctx->radio);
559
560    // May be some further cleanup ????
561
562    return (AFB_SUCCESS); // Could it fails ????
563 }
564
565
566 // Start a radio and reserve exclusive usage to requesting client
567 STATIC ctxHandleT  *reserveRadio (pluginHandleT* handle) {
568     ctxHandleT *client;
569     int idx;
570     
571    // loop on existing radio if any
572     for (idx = 0; idx < _radio_dev_count(); idx++) {
573         if ((handle->radios[client->idx])->used = FALSE) break;
574     }
575     
576     // No avaliable radio return now
577     if (idx == MAX_RADIO) return (NULL);
578     
579    // Book radio
580    (handle->radios[client->idx])->used = TRUE;
581    
582    // create client handle 
583    client = calloc (1, sizeof (ctxHandleT));
584    
585    // stop related threads and free attached resources
586    _radio_start_threads (&client->radio);
587    
588    // May be some things to do ????
589    
590    
591    return (client);
592 }
593
594 // This is called when client session died [ex; client quit for more than 15mn]
595 STATIC json_object* freeRadio () {
596     
597     //releaseRadio (client->handle, client);
598     //free (client);
599 }
600
601
602 STATIC json_object* powerOnOff (AFB_request *request) {
603     json_object *jresp;
604     AFB_clientCtx *client = request->client; // get client context from request
605    
606     // Make sure binder was started with client session
607     if (client == NULL) {
608         request->errcode=MHD_HTTP_FORBIDDEN;
609         return (jsonNewMessage(AFB_FAIL, "Radio binder need session [--token=xxxx]"));        
610     }
611      
612     // If we have a handle radio was on let power it down
613     if (client->ctx != NULL) {
614         dev_ctx_T *dev_ctx = (dev_ctx_T *)client->ctx;
615
616         releaseRadio (client->plugin->handle, client->ctx);  // poweroff client related radio
617         
618         jresp = json_object_new_object();
619         json_object_object_add(jresp, "power", json_object_new_string ("off"));        
620         return (jresp);
621     }
622         
623     // request a new client context token and check result 
624     if (AFB_UNAUTH == ctxTokenCreate (request)) {
625         request->errcode=MHD_HTTP_UNAUTHORIZED;
626         jresp= jsonNewMessage(AFB_FAIL, "You're not authorized to request a radio [make sure you have the right authentication token");
627         return (jresp);
628     }
629     
630     // Client is clean let's look it we have an avaliable radio to propose
631     
632     // make sure we have last hot plug dongle visible
633     updateRadioDevList (client->plugin->handle); 
634     
635     // get try to get an unused radio
636     client->ctx = reserveRadio (client->plugin->handle);  
637     if (client->ctx == NULL) {
638        return (jsonNewMessage(AFB_FAIL, "Sory No More Radio Avaliable")); 
639     }  
640     
641     // At this point we should have something to retreive radio status before last poweroff [but this is only a demonstrator]
642 }
643
644
645 STATIC  AFB_restapi pluginApis[]= {
646   {"power"  , (AFB_apiCB)powerOnOff , "Ping Application Framework"},
647   {"start"  , (AFB_apiCB)start      , "Ping Application Framework"},
648   {"stop"   , (AFB_apiCB)stop       , "Ping Application Framework"},
649   {NULL}
650 };
651
652 PUBLIC AFB_plugin *radioRegister (AFB_session *session) {
653     AFB_plugin *plugin = malloc (sizeof (AFB_plugin));
654     plugin->type  = AFB_PLUGIN_JSON;
655     plugin->info  = "Application Framework Binder - Radio plugin";
656     plugin->prefix  = "radio";
657     plugin->apis  = pluginApis;
658     
659     plugin->handle = initRadioPlugin();
660     plugin->freeCtxCB = freeRadio;
661
662     return (plugin);
663 };