Fix plugins loading, cleanup and dispatch Radio API code
[src/app-framework-binder.git] / plugins / radio / radio-rtlsdr.c
1 /*
2  * Copyright (C) 2015 "IoT.bzh"
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "radio-api.h"
19 #include "radio-rtlsdr.h"
20
21 /* ------------- RADIO RTLSDR IMPLEMENTATION ---------------- */
22
23 /* --- PUBLIC FUNCTIONS --- */
24
25 /* Radio initialization should be done only when user start the radio and not at plugin initialization
26    Making this call too early would impose to restart the binder to detect a radio */
27 PUBLIC unsigned char _radio_on (unsigned int num, radioCtxHandleT *ctx) {
28  
29     if (num >= _radio_dev_count())
30         return 0;
31     
32     if (init_dev_count < _radio_dev_count()) {
33         init_dev_count = _radio_dev_count();
34         dev_ctx = (dev_ctx_T**) realloc (dev_ctx, init_dev_count * sizeof(dev_ctx_T));           
35     }
36
37     dev_ctx[num] = (dev_ctx_T*) malloc (sizeof(dev_ctx_T));
38     dev_ctx[num]->dev = NULL;
39     dev_ctx[num]->mode = ctx->mode;
40     dev_ctx[num]->freq = ctx->freq;
41     dev_ctx[num]->mute = ctx->mute;
42     dev_ctx[num]->should_run = 0;
43     dev_ctx[num]->dongle = NULL;
44     dev_ctx[num]->demod = NULL;
45     dev_ctx[num]->output = NULL;
46     _radio_dev_init(dev_ctx[num], num);
47     
48     return 1;
49 }
50
51 PUBLIC void _radio_off (unsigned int num) {
52
53     if (num >= _radio_dev_count())
54         return;
55
56     if (dev_ctx[num]) {
57         _radio_dev_free(dev_ctx[num]);
58         free(dev_ctx[num]);
59     }
60     /* free(dev_ctx); */
61 }
62
63 PUBLIC void _radio_set_mode (unsigned int num, Mode mode) {
64     if (!dev_ctx || !dev_ctx[num])
65         return;
66
67     dev_ctx[num]->mode = mode;
68     _radio_apply_params(dev_ctx[num]);
69 }
70
71 PUBLIC void _radio_set_freq (unsigned int num, float freq) {
72     if (!dev_ctx || !dev_ctx[num])
73         return;
74
75     dev_ctx[num]->freq = freq;
76     _radio_apply_params(dev_ctx[num]);
77 }
78
79 PUBLIC void _radio_set_mute (unsigned int num, unsigned char mute) {
80     if (!dev_ctx || !dev_ctx[num])
81         return;
82
83     dev_ctx[num]->mute = mute;
84     _radio_apply_params(dev_ctx[num]);
85 }
86
87 PUBLIC void _radio_play (unsigned int num) {
88     if (!dev_ctx || !dev_ctx[num])
89         return;
90
91     _radio_start_threads(dev_ctx[num]);
92 }
93
94 PUBLIC void _radio_stop (unsigned int num) {
95     if (!dev_ctx || !dev_ctx[num])
96         return;
97
98     _radio_stop_threads(dev_ctx[num]);
99 }
100
101 PUBLIC unsigned int _radio_dev_count () {
102     return rtlsdr_get_device_count();
103 }
104
105 PUBLIC const char* _radio_dev_name (unsigned int num) {
106     return rtlsdr_get_device_name(num);
107 }
108
109
110 /* --- LOCAL HELPER FUNCTIONS --- */
111
112 STATIC unsigned char _radio_dev_init (dev_ctx_T *dev_ctx, unsigned int num) {
113     rtlsdr_dev_t *dev = dev_ctx->dev;
114
115     if (rtlsdr_open(&dev, num) < 0)
116         return 0;
117
118     rtlsdr_set_tuner_gain_mode(dev, 0);
119
120     if (rtlsdr_reset_buffer(dev) < 0)
121         return 0;
122
123     dev_ctx->dev = dev;
124
125     _radio_apply_params(dev_ctx);
126
127     return 1;
128 }
129
130 STATIC unsigned char _radio_dev_free (dev_ctx_T *dev_ctx) {
131     rtlsdr_dev_t *dev = dev_ctx->dev;
132
133     if (rtlsdr_close(dev) < 0)
134         return 0;
135     dev = NULL;
136
137     dev_ctx->dev = dev;
138
139     return 1;
140 }
141
142 STATIC void _radio_apply_params (dev_ctx_T *dev_ctx) {
143     rtlsdr_dev_t *dev = dev_ctx->dev;
144     Mode mode = dev_ctx->mode;
145     float freq = dev_ctx->freq;
146     int rate;
147
148     freq *= 1000000;
149     rate = ((1000000 / 200000) + 1) * 200000;
150
151     if (mode == FM)
152         freq += 16000;
153     freq += rate / 4;
154
155     rtlsdr_set_center_freq(dev, freq);
156     rtlsdr_set_sample_rate(dev, rate);
157
158     dev_ctx->dev = dev;
159 }
160
161 STATIC void _radio_start_threads (dev_ctx_T *dev_ctx) {
162     rtlsdr_dev_t *dev = dev_ctx->dev;
163     dev_ctx->dongle = (dongle_ctx*) malloc(sizeof(dongle_ctx));
164     dev_ctx->demod = (demod_ctx*) malloc(sizeof(demod_ctx));
165     dev_ctx->output = (output_ctx*) malloc(sizeof(output_ctx));
166
167     dongle_ctx *dongle = dev_ctx->dongle;
168     demod_ctx *demod = dev_ctx->demod;
169     output_ctx *output = dev_ctx->output;
170
171     pthread_rwlock_init(&demod->lck, NULL);
172     pthread_cond_init(&demod->ok, NULL);
173     pthread_mutex_init(&demod->ok_m, NULL);
174     pthread_rwlock_init(&output->lck, NULL);
175     pthread_cond_init(&output->ok, NULL);
176     pthread_mutex_init(&output->ok_m, NULL);
177
178     dev_ctx->should_run = 1;
179
180      /* dongle thread */
181     dongle->thr_finished = 0;
182     pthread_create(&dongle->thr, NULL, _dongle_thread_fn, (void*)dev_ctx);
183
184      /* demod thread */
185     demod->pre_r = demod->pre_j = 0;
186     demod->now_r = demod->now_j = 0;
187     demod->index = demod->pre_index = demod->now_index = 0;
188     demod->thr_finished = 0;
189     pthread_create(&demod->thr, NULL, _demod_thread_fn, (void*)dev_ctx);
190
191      /* output thread */
192     output->thr_finished = 0;
193     pthread_create(&output->thr, NULL, _output_thread_fn, (void*)dev_ctx);
194 }
195
196 STATIC void _radio_stop_threads (dev_ctx_T *dev_ctx) {
197     rtlsdr_dev_t *dev = dev_ctx->dev;
198     dongle_ctx *dongle = dev_ctx->dongle;
199     demod_ctx *demod = dev_ctx->demod;
200     output_ctx *output = dev_ctx->output;
201
202     if (!dongle || !demod || !output)
203         return;
204
205      /* stop each "while" loop in threads */
206     dev_ctx->should_run = 0;
207
208     rtlsdr_cancel_async(dev);
209     pthread_signal(&demod->ok, &demod->ok_m);
210     pthread_signal(&output->ok, &output->ok_m);
211
212     while (!dongle->thr_finished ||
213            !demod->thr_finished ||
214            !output->thr_finished)
215         usleep(100000);
216
217     pthread_join(dongle->thr, NULL);
218     pthread_join(demod->thr, NULL);
219     pthread_join(output->thr, NULL);
220     pthread_rwlock_destroy(&demod->lck);
221     pthread_cond_destroy(&demod->ok);
222     pthread_mutex_destroy(&demod->ok_m);
223     pthread_rwlock_destroy(&output->lck);
224     pthread_cond_destroy(&output->ok);
225     pthread_mutex_destroy(&output->ok_m);
226
227     free(dongle); dev_ctx->dongle = NULL;
228     free(demod); dev_ctx->demod = NULL;
229     free(output); dev_ctx->output = NULL;
230 }
231
232  /* ---- LOCAL THREADED FUNCTIONS ---- */
233
234 STATIC void _rtlsdr_callback (unsigned char *buf, uint32_t len, void *ctx) {
235     dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx;
236     dongle_ctx *dongle = dev_ctx->dongle;
237     demod_ctx *demod = dev_ctx->demod;
238     unsigned char tmp;
239     int i;
240
241     if (!dev_ctx->should_run)
242         return;
243
244      /* rotate 90° */
245     for (i = 0; i < (int)len; i += 8) {
246         tmp = 255 - buf[i+3];
247         buf[i+3] = buf[i+2];
248         buf[i+2] = tmp;
249
250         buf[i+4] = 255 - buf[i+4];
251         buf[i+5] = 255 - buf[i+5];
252
253         tmp = 255 - buf[i+6];
254         buf[i+6] = buf[i+7];
255         buf[i+7] = tmp;
256     }
257
258      /* write data */
259     for (i = 0; i < (int)len; i++)
260         dongle->buf[i] = (int16_t)buf[i] - 127;
261
262      /* lock demod thread, write to it, unlock */
263        pthread_rwlock_wrlock(&demod->lck);
264     memcpy(demod->buf, dongle->buf, 2 * len);
265     demod->buf_len = len;
266        pthread_rwlock_unlock(&demod->lck);
267        pthread_signal(&demod->ok, &demod->ok_m);
268 }
269  /**/
270 STATIC void* _dongle_thread_fn (void *ctx) {
271     dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx;
272     dongle_ctx *dongle = dev_ctx->dongle;
273
274     rtlsdr_read_async(dev_ctx->dev, _rtlsdr_callback, dev_ctx, 0, 0);
275
276     dongle->thr_finished = 1;
277     return 0;
278 }
279
280 STATIC void _lowpass_demod (void *ctx) {
281     demod_ctx *demod = (demod_ctx *)ctx;
282     int i=0, i2=0;
283
284     while (i < demod->buf_len) {
285         demod->now_r += demod->buf[i];
286         demod->now_j += demod->buf[i+1];
287         i += 2;
288         demod->index++;
289         if (demod->index < ((1000000 / 200000) + 1))
290             continue;
291         demod->buf[i2] = demod->now_r;
292         demod->buf[i2+1] = demod->now_j;
293         demod->index = 0;
294         demod->now_r = demod->now_j = 0;
295         i2 += 2;
296     }
297     demod->buf_len = i2;
298 }
299  /**/
300 STATIC void _lowpassreal_demod (void *ctx) {
301     demod_ctx *demod = (demod_ctx *)ctx;
302     int i=0, i2=0;
303     int fast = 200000;
304     int slow = 48000;
305
306     while (i < demod->res_len) {
307         demod->now_index += demod->res[i];
308         i++;
309         demod->pre_index += slow;
310         if (demod->pre_index < fast)
311             continue;
312         demod->res[i2] = (int16_t)(demod->now_index / (fast/slow));
313         demod->pre_index -= fast;
314         demod->now_index = 0;
315         i2 += 1;
316     }
317     demod->res_len = i2;
318 }
319  /**/
320 STATIC void _multiply (int ar, int aj, int br, int bj, int *cr, int *cj) {
321     *cr = ar*br - aj*bj;
322     *cj = aj*br + ar*bj;
323 }
324  /**/
325 STATIC int _polar_discriminant (int ar, int aj, int br, int bj) {
326     int cr, cj;
327     double angle;
328     _multiply(ar, aj, br, -bj, &cr, &cj);
329     angle = atan2((double)cj, (double)cr);
330     return (int)(angle / 3.14159 * (1<<14));
331 }
332  /**/
333 STATIC void _fm_demod (void *ctx) {
334     demod_ctx *demod = (demod_ctx *)ctx;
335     int16_t *buf = demod->buf;
336     int buf_len = demod->buf_len;
337     int pcm, i;
338
339     pcm = _polar_discriminant(buf[0], buf[1], demod->pre_r, demod->pre_j);
340     demod->res[0] = (int16_t)pcm;
341
342     for (i = 2; i < (buf_len-1); i += 2) {
343         pcm = _polar_discriminant(buf[i], buf[i+1], buf[i-2], buf[i-1]);
344         demod->res[i/2] = (int16_t)pcm;
345     }
346     demod->pre_r = buf[buf_len - 2];
347     demod->pre_j = buf[buf_len - 1];
348     demod->res_len = buf_len/2;
349 }
350  /**/
351 STATIC void _am_demod (void *ctx) {
352     demod_ctx *demod = (demod_ctx *)ctx;
353     int16_t *buf = demod->buf;
354     int buf_len = demod->buf_len;
355     int pcm, i;
356
357     for (i = 0; i < buf_len; i += 2) {
358         pcm = buf[i] * buf[i];
359         pcm += buf[i+1] * buf[i+1];
360         demod->res[i/2] = (int16_t)sqrt(pcm);
361     }
362     demod->res_len = buf_len/2;
363 }
364  /**/
365 STATIC void* _demod_thread_fn (void *ctx) {
366     dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx;
367     demod_ctx *demod = dev_ctx->demod;
368     output_ctx *output = dev_ctx->output;
369
370     while(dev_ctx->should_run) {
371             pthread_wait(&demod->ok, &demod->ok_m);
372             pthread_rwlock_wrlock(&demod->lck);
373         _lowpass_demod(demod);
374         if (dev_ctx->mode == FM)
375             _fm_demod(demod);
376         else
377             _am_demod(demod);
378         _lowpassreal_demod(demod);
379            pthread_rwlock_unlock(&demod->lck);
380
381          /* lock demod thread, write to it, unlock */
382            pthread_rwlock_wrlock(&output->lck);
383         memcpy(output->buf, demod->res, 2 * demod->res_len);
384         output->buf_len = demod->res_len;
385            pthread_rwlock_unlock(&output->lck);
386            pthread_signal(&output->ok, &output->ok_m);
387     }
388
389     demod->thr_finished = 1;
390     return 0;
391 }
392
393 STATIC void* _output_thread_fn (void *ctx) {
394     dev_ctx_T *dev_ctx = (dev_ctx_T *)ctx;
395     output_ctx *output = dev_ctx->output;
396
397     while (dev_ctx->should_run) {
398            pthread_wait(&output->ok, &output->ok_m);
399            pthread_rwlock_rdlock(&output->lck);
400         //if (!dev_ctx->mute)
401         //    mRadio->PlayAlsa((void*)&output->buf, output->buf_len);
402            pthread_rwlock_unlock(&output->lck);
403     }
404
405     output->thr_finished = 1;
406     return 0;
407 }