Subversion Repositories svnkaklik

Rev

Rev 560 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log

Rev Author Line No. Line
558 kaklik 1
///////////////////////////////////////////////////////////////////////////////////
2
//                        A small demo of sonar.
3
// Program allow distance measuring.
4
// Uses cross-correlation algorithm to find echos
5
//
6
// Author: kaklik  (kaklik@mlab.cz)
7
//
8
///////////////////////////////////////////////////////////////////////////////////
9
 
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <string.h>
13
#include <sched.h>
14
#include <errno.h>
15
#include <getopt.h>
16
#include <alsa/asoundlib.h>
17
#include <sys/time.h>
18
#include <math.h>
19
 
561 kaklik 20
#define SOUND_SPEED	340.0	// sound speed in air in metrs per second
21
#define MAX_RANGE	10.0	// maximal working radius in meters
22
 
558 kaklik 23
static char *device = "plughw:0,0";			/* playback device */
24
static snd_pcm_format_t format = SND_PCM_FORMAT_S16;	/* sample format */
561 kaklik 25
static unsigned int rate = 96000;			/* stream rate */
26
static unsigned int buffer_time = MAX_RANGE / SOUND_SPEED * 1e6;		/* ring buffer length in us */
27
static unsigned int period_time = MAX_RANGE / SOUND_SPEED * 1e5;		/* period time in us */
558 kaklik 28
static int resample = 1;				/* enable alsa-lib resampling */
29
 
30
#define SIGNAL_SAMPLES 100000
31
 
32
unsigned int chirp_size;
33
 
34
int period=0;
35
int cperiod=0;
561 kaklik 36
short *chirp;
558 kaklik 37
short signal[1000000];		// record 6s of input samples
38
 
39
static snd_pcm_sframes_t buffer_size;	// size of buffer at sound card
40
static snd_pcm_sframes_t period_size;	//samples per frame
41
static snd_output_t *output = NULL;
42
 
43
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, unsigned int channels)
44
{
561 kaklik 45
    unsigned int rrate;
46
    snd_pcm_uframes_t size;
47
    int err, dir;
558 kaklik 48
 
561 kaklik 49
    /* choose all parameters */
50
    err = snd_pcm_hw_params_any(handle, params);
51
    if (err < 0)
52
    {
53
        printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
54
        return err;
55
    }
56
    /* set hardware resampling */
57
    err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
58
    if (err < 0)
59
    {
60
        printf("Resampling setup failed for playback: %s\n", snd_strerror(err));
61
        return err;
62
    }
63
    /* set the interleaved read/write format */
64
    err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
65
    if (err < 0)
66
    {
67
        printf("Access type not available for playback: %s\n", snd_strerror(err));
68
        return err;
69
    }
70
    /* set the sample format */
71
    err = snd_pcm_hw_params_set_format(handle, params, format);
72
    if (err < 0)
73
    {
74
        printf("Sample format not available for playback: %s\n", snd_strerror(err));
75
        return err;
76
    }
77
    /* set the count of channels */
78
    err = snd_pcm_hw_params_set_channels(handle, params, channels);
79
    if (err < 0)
80
    {
81
        printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
82
        return err;
83
    }
84
    /* set the stream rate */
85
    rrate = rate;
86
    err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
87
    if (err < 0)
88
    {
89
        printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
90
        return err;
91
    }
92
    if (rrate != rate)
93
    {
94
        printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
95
        return -EINVAL;
96
    }
97
    else printf("Rate set to %i Hz\n", rate, err);
98
    /* set the buffer time */
99
    err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
100
    if (err < 0)
101
    {
102
        printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
103
        return err;
104
    }
105
    err = snd_pcm_hw_params_get_buffer_size(params, &size);
106
    if (err < 0)
107
    {
108
        printf("Unable to get buffer size for playback: %s\n", snd_strerror(err));
109
        return err;
110
    }
111
    buffer_size = size;
112
    printf("Bufffer size set to:  %d  Requested buffer time: %ld \n", (int) buffer_size, (long) buffer_time);
113
 
114
 
115
    /// set the period time
116
    err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
117
    if (err < 0)
118
    {
119
        printf("Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
120
        return err;
121
    }
122
 
123
    err = snd_pcm_hw_params_get_period_size(params, &size, &dir);
124
    if (err < 0)
125
    {
126
        printf("Unable to get period size for playback: %s\n", snd_strerror(err));
127
        return err;
128
    }
129
    period_size = size;
130
    printf("Period size set to:  %d Requested period time: %ld \n", (int) period_size, (long) period_time);
131
 
132
    /* write the parameters to device */
133
    err = snd_pcm_hw_params(handle, params);
134
    if (err < 0)
135
    {
136
        printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
137
        return err;
138
    }
139
    return 0;
558 kaklik 140
}
141
 
142
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
143
{
561 kaklik 144
    int err;
558 kaklik 145
 
561 kaklik 146
    /* get the current swparams */
147
    err = snd_pcm_sw_params_current(handle, swparams);
148
    if (err < 0)
149
    {
150
        printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
151
        return err;
152
    }
153
    // start the transfer when the buffer is almost full: never fou our case 
154
    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 2 * buffer_size);
155
    if (err < 0)
156
    {
157
        printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
158
        return err;
159
    }
160
 
161
    err = snd_pcm_sw_params_set_period_event(handle, swparams, 1);
162
    if (err < 0)
163
    {
164
        printf("Unable to set period event: %s\n", snd_strerror(err));
165
        return err;
166
    }
167
 
168
    /* write the parameters to the playback device */
169
    err = snd_pcm_sw_params(handle, swparams);
170
    if (err < 0)
171
    {
172
        printf("Unable to set sw params for playback: %s\n", snd_strerror(err));
173
        return err;
174
    }
175
    return 0;
558 kaklik 176
}
177
 
561 kaklik 178
struct async_private_data
179
{
180
    signed short *samples;
181
    snd_pcm_channel_area_t *areas;
182
    unsigned int period;
558 kaklik 183
};
184
 
185
 
186
////// SIGNAL GENERATION STUFF
561 kaklik 187
unsigned int linear_windowed_chirp(short *pole)
558 kaklik 188
{
561 kaklik 189
    unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1;
558 kaklik 190
 
561 kaklik 191
    static const float f0 = 1000;		//starting frequency
192
    static const float fmax = 7000;		//ending frequency
193
    static const float Tw = 0.002;
194
    static float k;
558 kaklik 195
 
561 kaklik 196
    unsigned int n=0;
197
    double t;
198
    unsigned int chirp_samples;		// number of samples per period
558 kaklik 199
 
561 kaklik 200
    k=2*(fmax-f0)/Tw;
201
    chirp_samples = ceil(rate*Tw);
558 kaklik 202
 
561 kaklik 203
    for (n=0;n<=chirp_samples;n++)
204
    {
205
        t = (double) n / (double)rate;
206
        pole[n] = (short) floor( (0.35875 - 0.48829*cos(2*M_PI*t*1/Tw) + 0.14128*cos(2*M_PI*2*t*1/Tw) - 0.01168*cos(2*M_PI*3*t*1/Tw))*maxval*sin(2*M_PI*(t)*(f0+(k/2)*(t))) );
207
    }
208
    return (chirp_samples);
558 kaklik 209
}
210
 
211
/////////// CALL BACK STUFF ///////////////////
212
static void async_playback_callback(snd_async_handler_t *ahandler)
213
{
561 kaklik 214
    snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
215
    snd_pcm_sframes_t avail;
216
    int err;
558 kaklik 217
 
561 kaklik 218
    avail = snd_pcm_avail_update(handle);
219
    while ((avail >= period_size) && ((period*period_size) < chirp_size) )
220
    {
221
 
222
        err = snd_pcm_writei(handle, (chirp+period*period_size), period_size);
223
        if (err < 0)
224
        {
225
            printf("Write error: %s\n", snd_strerror(err));
226
            exit(EXIT_FAILURE);
227
        }
228
        if (err != period_size)
229
        {
230
            printf("Write error: written %i expected %li\n", err, period_size);
231
            exit(EXIT_FAILURE);
232
        }
233
        avail = snd_pcm_avail_update(handle);
234
        period++;
235
    }
558 kaklik 236
}
237
 
238
static void async_capture_callback(snd_async_handler_t *ahandler)
239
{
561 kaklik 240
    snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
241
    snd_pcm_sframes_t avail;
242
    int err;
558 kaklik 243
 
561 kaklik 244
    avail = snd_pcm_avail_update(handle);
245
    while ((avail >= period_size) /*&& ((period*period_size) < (CHIRP_SIZE-100))*/ )    // segmentation fault checking disabled
246
    {
247
 
248
        err = snd_pcm_readi(handle, (signal+cperiod*period_size), period_size);
249
        if (err < 0)
250
        {
251
            printf("Read error: %s\n", snd_strerror(err));
252
            exit(EXIT_FAILURE);
253
        }
254
        if (err != period_size)
255
        {
256
            printf("Read error: red %i expected %li\n", err, period_size);
257
            exit(EXIT_FAILURE);
258
        }
259
        avail = snd_pcm_avail_update(handle);
260
        cperiod++;
261
    }
558 kaklik 262
}
263
 
264
 
265
int main(int argc, char *argv[])
266
{
561 kaklik 267
    snd_pcm_t *playback_handle, *capture_handle;
268
    int err;
269
    snd_pcm_hw_params_t *hwparams;
270
    snd_pcm_sw_params_t *swparams;
271
    signed short *frame;  // pointer to array of samples
272
    unsigned int chn;
273
    snd_pcm_channel_area_t *areas;
558 kaklik 274
 
561 kaklik 275
    struct async_private_data data;
276
    snd_async_handler_t *chandler, *phandler;
277
    int count;
278
    unsigned int i,j,m,n;
279
    unsigned int delay[10];	//store delay of signifed correlation
280
    long int l,r;  // store correlation at strict time
281
    long int correlationl[SIGNAL_SAMPLES]; //array to store correlation curve
282
    long int correlationr[SIGNAL_SAMPLES]; //array to store correlation curve
283
    int L_signal[SIGNAL_SAMPLES];
284
    int R_signal[SIGNAL_SAMPLES];
558 kaklik 285
 
561 kaklik 286
    FILE *out;
558 kaklik 287
 
561 kaklik 288
    snd_pcm_hw_params_alloca(&hwparams);
289
    snd_pcm_sw_params_alloca(&swparams);
558 kaklik 290
 
561 kaklik 291
    printf("Simple PC sonar ver. 000000001 starting work.. \n");
558 kaklik 292
 
293
//open and set playback device
561 kaklik 294
    if ((err = snd_pcm_open(&playback_handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
295
    {
296
        printf("Playback open error: %s\n", snd_strerror(err));
297
        return 0;
298
    }
558 kaklik 299
 
561 kaklik 300
    if ((err = set_hwparams(playback_handle, hwparams, 1)) < 0)
301
    {
302
        printf("Setting of hwparams failed: %s\n", snd_strerror(err));
303
        exit(EXIT_FAILURE);
304
    }
305
    if ((err = set_swparams(playback_handle, swparams)) < 0)
306
    {
307
        printf("Setting of swparams failed: %s\n", snd_strerror(err));
308
        exit(EXIT_FAILURE);
309
    }
310
 
558 kaklik 311
//open and set capture device
561 kaklik 312
    if ((err = snd_pcm_open(&capture_handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0)
313
    {
314
        printf("Playback open error: %s\n", snd_strerror(err));
315
        return 0;
316
    }
558 kaklik 317
 
561 kaklik 318
    if ((err = set_hwparams(capture_handle, hwparams, 2)) < 0)
319
    {
320
        printf("Setting of hwparams failed: %s\n", snd_strerror(err));
321
        exit(EXIT_FAILURE);
322
    }
323
    if ((err = set_swparams(capture_handle, swparams)) < 0)
324
    {
325
        printf("Setting of swparams failed: %s\n", snd_strerror(err));
326
        exit(EXIT_FAILURE);
327
    }
328
 
560 kaklik 329
// generate ping pattern
561 kaklik 330
    chirp = malloc(2*period_size * sizeof(short));
331
    chirp_size = linear_windowed_chirp(chirp);
558 kaklik 332
 
561 kaklik 333
// register playback callback
334
/*    err = snd_async_add_pcm_handler(&phandler, playback_handle, async_playback_callback, &data); // fill by dummy &data
335
    if (err < 0)
336
    {
337
        printf("Unable to register async handler\n");
338
        exit(EXIT_FAILURE);
339
    }*/
558 kaklik 340
 
561 kaklik 341
//    for (period = 0; period < 2; period++)
558 kaklik 342
 
561 kaklik 343
    err = snd_pcm_writei(playback_handle, chirp, period_size);
344
    if (err < 0)
345
    {
346
        printf("Initial write error: %s\n", snd_strerror(err));
347
        exit(EXIT_FAILURE);
348
    }
349
/*        if (err != period_size)
350
        {
351
            printf("Initial write error: written %i expected %li\n", err, period_size);
352
            exit(EXIT_FAILURE);
353
        }*/
560 kaklik 354
 
561 kaklik 355
// register capture callback
356
/*    err = snd_async_add_pcm_handler(&chandler, capture_handle, async_capture_callback, &data); // fill by dummy &data
357
    if (err < 0)
358
    {
359
        printf("Unable to register async handler\n");
360
        exit(EXIT_FAILURE);
361
    }*/
560 kaklik 362
 
561 kaklik 363
    snd_pcm_link(capture_handle,playback_handle); //link capture and playback together
558 kaklik 364
 
365
//start sream
561 kaklik 366
/*    if ((err = snd_pcm_prepare (capture_handle)) < 0)
367
    {
368
        fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
369
                 snd_strerror (err));
370
        exit (1);
371
    }
372
    else printf("Capture device prepared...\n");*/
558 kaklik 373
 
561 kaklik 374
    err = snd_pcm_start(playback_handle);
375
    if (err < 0)
376
    {
377
        printf("Start error: %s\n", snd_strerror(err));
378
        exit(EXIT_FAILURE);
379
    }
380
    else printf("Waiting for transmitt all samples\n");
558 kaklik 381
 
561 kaklik 382
    while ( snd_pcm_avail(capture_handle) < period_size )
383
    {
384
        usleep(1000);
385
        printf(".");
386
    }
558 kaklik 387
 
561 kaklik 388
    err = snd_pcm_drop(capture_handle);
389
    if (err < 0)
390
    {
391
        printf("Stop error: %s\n", snd_strerror(err));
392
        exit(EXIT_FAILURE);
393
    }
558 kaklik 394
 
395
 
561 kaklik 396
    j=0;
397
    for (i=0;i < SIGNAL_SAMPLES;i++)
398
    {
399
        L_signal[i]=signal[j];
400
        R_signal[i]=signal[j+1];
401
        j+=2;
402
    }
558 kaklik 403
 
561 kaklik 404
    printf("Data transmitted... \ncorrelating...\n");
405
    for (n=0; n < (SIGNAL_SAMPLES - chirp_size);n++)
406
    {
407
        l=0;
408
        r=0;
409
        for (m=0;m < chirp_size;m++)
410
        {
558 kaklik 411
            l += chirp[m]*L_signal[m+n];	// correlate with left channel
412
            r += chirp[m]*R_signal[m+n];	// correlate with right channel
561 kaklik 413
        }
414
        correlationl[n]=l;
415
        correlationr[n]=r;
416
    }
558 kaklik 417
 
561 kaklik 418
    printf("Searching echos...\n");
419
    r=0;
420
    l=0;
421
    for (n=0; n < (SIGNAL_SAMPLES - chirp_size);n++) 			//najde nejvetsi korelace
422
    {
423
        if (l < correlationl[n])
424
        {
425
            delay[1] = n;
426
            l = correlationl[n];
427
        }
428
        if (r < correlationr[n])
429
        {
430
            delay[2] = n;
431
            r = correlationr[n];
432
        }
433
    }
558 kaklik 434
 
561 kaklik 435
    printf("\nWriting output file...\n");
436
    out=fopen("/tmp/sonar.txt","w");
437
    j=0;
438
    for (i=0;i<=period_size;i++)
439
    {
440
        fprintf(out,"%6d %6d %6d %6d %9ld %9ld\n",i,chirp[i],L_signal[i],R_signal[i],correlationl[i], correlationr[i]);
441
        j+=2;
442
    }
443
    fclose(out);
558 kaklik 444
 
561 kaklik 445
    printf("\nEcho zacina na: %d vzorku.\n", delay[1]);
446
    printf("Casove na: %f s\n", ((float)delay[1]/rate));
447
    printf("vzdalenost: %f m\n", (SOUND_SPEED*(float)delay[1]/rate));
558 kaklik 448
 
561 kaklik 449
    snd_pcm_close(playback_handle);
450
    snd_pcm_close(capture_handle);
451
    return 0;
558 kaklik 452
}
453