Statistics
| Branch: | Tag: | Revision:

root / gnuradio-core / src / lib / general / gr_align_on_samplenumbers_ss.cc @ 3d96f593

History | View | Annotate | Download (16.6 kB)

1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2005 Free Software Foundation, Inc.
4
 * 
5
 * This file is part of GNU Radio
6
 * 
7
 * GNU Radio is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3, or (at your option)
10
 * any later version.
11
 * 
12
 * GNU Radio is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with GNU Radio; see the file COPYING.  If not, write to
19
 * the Free Software Foundation, Inc., 51 Franklin Street,
20
 * Boston, MA 02110-1301, USA.
21
 */
22
23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
27
#include <gr_align_on_samplenumbers_ss.h>
28
#include <gr_io_signature.h>
29
#include <assert.h>
30
#include <stdexcept>
31
#include <string.h>
32
#include <cstdio>
33
34
//define ALIGN_ADVANCED_IMPLEMENTATION to have an alternative implementation of the align algoritm which exactly follows the align_interval spec.
35
//It is more resource intensive, less tested and probably not needed
36
//define ALIGN_ADVANCED_IMPLEMENTATION
37
38
//define DEBUG_TOCONSUME to see debug messages about the synchronisation part of this block
39
//define DEBUG_TOCONSUME
40
#ifdef DEBUG_TOCONSUME
41
#define tcPrintf if(dprint) printf
42
#else
43
#define tcPrintf //printf
44
#endif
45
46
#define ePrintf printf
47
48
gr_align_on_samplenumbers_ss_sptr
49
gr_make_align_on_samplenumbers_ss (int nchan, int align_interval)
50
{
51
  return gr_align_on_samplenumbers_ss_sptr (new gr_align_on_samplenumbers_ss (nchan,align_interval));
52
}
53
54
gr_align_on_samplenumbers_ss::gr_align_on_samplenumbers_ss (int nchan,int align_interval)
55
  : gr_block ("align_on_samplenumbers_ss",
56
        gr_make_io_signature (2, -1, sizeof (short)), //2, -1
57
        gr_make_io_signature (2, -1, sizeof (short))), //2,-1
58
  d_align_interval (align_interval),
59
  d_nchan(nchan),
60
  d_ninputs(0)
61
{
62
  if (d_align_interval<0)
63
    set_output_multiple (d_nchan*2);
64
  else
65
  {
66
    set_output_multiple (d_align_interval*d_nchan*2);
67
  }
68
    
69
}
70
71
gr_align_on_samplenumbers_ss::~gr_align_on_samplenumbers_ss()
72
{
73
  
74
}
75
void
76
gr_align_on_samplenumbers_ss::forecast (int noutput_items, gr_vector_int &ninput_items_required)
77
{
78
  //assert (0 == noutput_items % d_align_interval);
79
  unsigned ninputs = ninput_items_required.size();
80
  for (unsigned int i = 0; i < ninputs; i++)
81
    ninput_items_required[i] = std::max(noutput_items*d_nchan*2+ history() - 1,1024*d_nchan*2+ history() - 1);//TODO include the diffs found in determine input_items_required
82
}
83
84
bool
85
gr_align_on_samplenumbers_ss::check_topology (int ninputs, int noutputs)
86
{
87
  bool result=true;
88
  if(noutputs!=ninputs)
89
  {
90
    result=false;
91
    ePrintf("gr_align_on_samplenumbers_ss: ERROR noutputs %i != ninputs %i\n",noutputs,ninputs);
92
  }
93
  if(d_nchan<2)
94
  {
95
    result=false;
96
    ePrintf("gr_align_on_samplenumbers_ss: ERROR nchan %i<2 \n",d_nchan);
97
  }
98
  if((int)d_ninputs!=ninputs)
99
  {
100
    //Only resize and reset the status if there really changed something
101
    //Don't reset the status if the user just called stop() and start(), although maybe we should.
102
    d_state.resize(ninputs);
103
    d_ninputs=ninputs;
104
    for(unsigned int i=0;i<d_ninputs;i++)
105
    {
106
      d_state[i].sync_found=false;
107
      d_state[i].sync_end_found=false;
108
    }
109
    d_in_presync=false;
110
  }
111
  return result;
112
}
113
114
#ifdef ALIGN_ADVANCED_IMPLEMENTATION
115
int
116
gr_align_on_samplenumbers_ss::general_work (int noutput_items,
117
        gr_vector_int &ninput_items,
118
        gr_vector_const_void_star &input_items,
119
        gr_vector_void_star &output_items)
120
{
121
#ifdef DEBUG_TOCONSUME
122
  static int dcount=0;
123
  bool dprint=false;
124
  dcount++;
125
  if(dcount>200)
126
  {
127
    dcount=0;
128
    dprint=true;
129
  } 
130
#endif
131
  const size_t item_size = output_signature()->sizeof_stream_item (0);
132
  const unsigned ninputs = input_items.size();
133
  const unsigned noutputs = output_items.size();
134
135
  int align_interval=d_align_interval*2*d_nchan;
136
  if(d_align_interval<0)
137
  {
138
    //align once per noutput_items
139
    align_interval=noutput_items;
140
    align_interval=align_interval/(2*d_nchan);
141
    align_interval=align_interval*(2*d_nchan);
142
  }
143
144
  int min_ninput_items=noutput_items;//numeric_limits<int>::max();
145
  int noutput_items_produced=0;
146
  for(unsigned int i=0;i<ninputs;i++)
147
  { 
148
    d_state[i].ninput_items=ninput_items[i];
149
    d_state[i].ninput_items_used=0;
150
    min_ninput_items=std::min(ninput_items[i],min_ninput_items);
151
  }
152
  for(int j=0;j<noutput_items-align_interval+1;j+=align_interval)
153
  {
154
    int common_end;
155
    if(min_ninput_items>=align_interval)
156
      common_end=align_interval;
157
    else
158
    {
159
      common_end=min_ninput_items/(d_nchan*2);
160
      common_end=common_end*(d_nchan*2);
161
    }
162
    if (common_end<=0) break;
163
    
164
    bool all_diffs_zero=true;
165
    //bool sync_found=false;
166
    int diff_comp_end_max=0;
167
    for(unsigned int i=0;i<ninputs;i++)
168
    {
169
      unsigned short * uin=&(((unsigned short*)input_items[i])[d_state[i].ninput_items_used]);
170
      unsigned int  x_high16bits = uin[0];
171
      unsigned int  x_low16bits = uin[1];
172
      d_state[i].ucounter_begin = x_high16bits<<16 | x_low16bits;
173
      d_state[i].diff=d_state[0].ucounter_begin-d_state[i].ucounter_begin;//Result is a signed value,Will wrap around on 32 bit boundary
174
      int common_last=std::max(common_end-d_nchan*2,0);
175
      x_high16bits = uin[d_nchan*2];
176
      x_low16bits = uin[d_nchan*2+1];
177
      unsigned int ucounter_begin2 = x_high16bits<<16 | x_low16bits;
178
#ifdef DEBUG_TOCONSUME
179
      if((d_state[i].ucounter_begin+1)!=(ucounter_begin2))
180
        if(ucounter_begin2==0)
181
          ePrintf("SYNC counters are 0\n");
182
        else
183
           ePrintf("Error: counter not continuous.\n ucounter_begin[%i]=%i +1 !=  ucounter_begin2=%i\n",i,d_state[i].ucounter_begin,ucounter_begin2);
184
#endif
185
      x_high16bits = uin[common_last];
186
      x_low16bits = uin[common_last+1];
187
      d_state[i].ucounter_end = x_high16bits<<16 | x_low16bits;
188
      d_state[i].diff_end=d_state[0].ucounter_end-d_state[i].ucounter_end;//Result is a signed value,Will wrap around on 32 bit boundary
189
      d_state[i].diff_comp_end=d_state[i].ucounter_end-d_state[0].ucounter_end;
190
      diff_comp_end_max=std::max(d_state[i].diff_comp_end,diff_comp_end_max);
191
#ifdef DEBUG_TOCONSUME
192
      if(d_state[i].diff>256000000 || d_state[i].diff_end>256000000 || d_state[i].diff_comp_end>256000000)
193
      {
194
        tcPrintf("diff[%i]=%i diff_end=%i diff_comp_end=%i\n",i,d_state[i].diff,d_state[i].diff_end,d_state[i].diff_comp_end);
195
      }
196
#endif
197
      all_diffs_zero=all_diffs_zero && (0==d_state[i].diff_end);
198
      if(d_state[i].ucounter_end<d_state[i].ucounter_begin+(unsigned)(common_last/(d_nchan*2))) //(unsigned)(common_last/(d_nchan*2)))
199
      {
200
        //printf("sync 1 ");// found ucounter_end[%i]=%i ucounter_begin[%i]=%i \n",i,d_state[i].ucounter_end,i,d_state[i].ucounter_begin);
201
        //sync_found=true;//sync_found or 32 bit counter  wraparound (0xffffffff -> 0x00000000)
202
        if(!d_in_presync)
203
        {
204
#ifdef DEBUG_TOCONSUME
205
          printf("presync START with %i\n",i);
206
#endif
207
         for(unsigned int k=0;k<ninputs;k++)
208
         {
209
          d_state[k].sync_found=false;
210
          d_state[i].sync_end_found=false;
211
         }
212
         d_in_presync=true;
213
         d_state[i].sync_found=true;    
214
        } else
215
        {
216
          //d_in_presync=true;
217
#ifdef DEBUG_TOCONSUME
218
          if(d_state[i].sync_found)
219
            printf("presync CONTINUE with %i\n",i);
220
          else
221
            printf("presync NEXT with %i\n",i);
222
#endif
223
          d_state[i].sync_found=true;  
224
          d_state[i].sync_end_found=false;  
225
        }             
226
      } else
227
      {
228
        if(d_in_presync && d_state[i].sync_found)
229
        {
230
          d_state[i].sync_end_found=true;
231
          bool all_syncs_found=true;
232
          for(unsigned int k=0;k<ninputs;k++)
233
            all_syncs_found=all_syncs_found && d_state[k].sync_end_found;
234
          d_in_presync=!all_syncs_found;
235
          if(!d_in_presync)
236
          {
237
            for(unsigned int k=0;k<ninputs;k++)
238
            {
239
              d_state[k].sync_found=false;
240
              d_state[i].sync_end_found=false;
241
            }
242
#ifdef DEBUG_TOCONSUME
243
            printf("presync END\n");
244
#endif
245
          }
246
        }
247
      }
248
    }
249
    if(d_in_presync || all_diffs_zero)
250
    {
251
      for(unsigned int i=0;i<ninputs;i++)
252
      {
253
         memcpy(&(((unsigned short*)output_items[i])[j]),&(((const unsigned short*)input_items[i])[d_state[i].ninput_items_used]),common_end*item_size);
254
         //consume(i,common_end);
255
         d_state[i].ninput_items-=common_end;
256
         d_state[i].ninput_items_used+=common_end;
257
         min_ninput_items=std::min(d_state[i].ninput_items,min_ninput_items);
258
#ifdef DEBUG_TOCONSUME
259
         if(common_end<256)
260
           tcPrintf("common_end %i\n",common_end);
261
#endif
262
      }
263
      //min_ninput_items-=common_end;
264
      noutput_items_produced+=common_end;
265
      //return common_end;
266
    } else
267
    {
268
      //printf("sync 2");
269
      for(unsigned int i=0;i<ninputs;i++)
270
      {
271
        int toconsume=std::min((d_state[i].diff_end+diff_comp_end_max)*d_nchan*2,d_state[i].ninput_items);
272
        toconsume=toconsume/(d_nchan*2);
273
        toconsume=toconsume*(d_nchan*2);
274
        d_state[i].ninput_items-=toconsume;
275
        d_state[i].ninput_items_used+=toconsume;
276
        min_ninput_items=std::min(d_state[i].ninput_items,min_ninput_items);
277
#ifdef DEBUG_TOCONSUME
278
      static int toconsume_counter=0;
279
      toconsume_counter++;
280
      //if(toconsume_counter>10)
281
      {
282
        tcPrintf("toconsume=%i diff_end[%i]*d_nchan*2=%i diff_comp_end_max*d_nchan*2=%i ninput_items[%i]=%i\n",toconsume,i,d_state[i].diff_end*d_nchan*2,diff_comp_end_max*d_nchan*2,i,ninput_items[i]);
283
        toconsume_counter=0;
284
      }
285
#endif
286
        //printf("toconsume[%i]=%i\n",i,toconsume);
287
        //consume(i,toconsume);//skip the difference in samplenumber items
288
      }
289
      //return 0;
290
    }
291
  }
292
  for(unsigned int i=0;i<ninputs;i++)
293
    consume(i,d_state[i].ninput_items_used);
294
#ifdef DEBUG_TOCONSUME
295
  if(noutput_items_produced<256)
296
    tcPrintf("noutput_items_produced %i\n",noutput_items_produced);
297
#endif
298
  return noutput_items_produced;
299
}
300
301
302
#else /*ALIGN_ADVANCED_IMPLEMENTATION*/
303
int
304
gr_align_on_samplenumbers_ss::general_work (int noutput_items,
305
        gr_vector_int &ninput_items,
306
        gr_vector_const_void_star &input_items,
307
        gr_vector_void_star &output_items)
308
{
309
#ifdef DEBUG_TOCONSUME
310
  static int dcount=0;
311
  bool dprint=false;
312
  dcount++;
313
  if(dcount>2000)
314
  {
315
    dcount=0;
316
    dprint=true;
317
  } 
318
#endif
319
  const size_t item_size = output_signature()->sizeof_stream_item (0);
320
  const unsigned ninputs = input_items.size();
321
  
322
  int common_end=noutput_items;
323
  //int diff_min=INT_MAX;
324
  //int diff_max=INT_MIN;
325
  for(unsigned int i=0;i<ninputs;i++)
326
  {
327
    unsigned short * uin=(unsigned short*)input_items[i];
328
    unsigned int  x_high16bits = uin[0];
329
    unsigned int  x_low16bits = uin[1];
330
    d_state[i].ucounter_begin = x_high16bits<<16 | x_low16bits;
331
    d_state[i].diff=d_state[0].ucounter_end-d_state[i].ucounter_end;//Result is a signed value,Will wrap around on 32 bit boundary
332
    x_high16bits = uin[d_nchan*2];
333
    x_low16bits = uin[d_nchan*2+1];
334
    unsigned int ucounter_begin2 = x_high16bits<<16 | x_low16bits;
335
    if((d_state[i].ucounter_begin+1)!=(ucounter_begin2)){
336
      if(ucounter_begin2==0)
337
      {
338
#ifdef DEBUG_TOCONSUME
339
        ePrintf("SYNC counters are 0\n");
340
#endif
341
      }
342
      else
343
      {
344
        ePrintf("Error: counter not continuous.\n ucounter_begin[%i]=%i +1 !=  ucounter_begin2=%i\n",i,d_state[i].ucounter_begin,ucounter_begin2);
345
      }
346
    }
347
      
348
    //diff_comp[i]=ucounter[i]-ucounter[0];
349
    //diff_min=std::min(diff[i],diff_min);
350
    //diff_max=std::max(diff[i],diff_max);
351
    common_end=std::max(std::min(ninput_items[i],common_end),0);
352
  }
353
  common_end=common_end/(d_nchan*2);
354
  common_end=common_end*(d_nchan*2);
355
#ifdef DEBUG_TOCONSUME
356
  if(common_end<d_nchan*2)
357
  {
358
    printf(" common_end %i\n",common_end);
359
    for(int j=0;j<ninputs;j++)
360
      printf("ninput_items[%i]=%i\n",j,ninput_items[j]);
361
  }
362
#endif
363
  bool all_diffs_zero=true;
364
  bool sync_found=false;
365
  int diff_comp_end_max=0;
366
  for(unsigned int i=0;i<ninputs;i++)
367
  {
368
    unsigned short * uin=(unsigned short*)input_items[i];
369
    int common_last=common_end-(d_nchan*2);
370
    unsigned int  x_high16bits = uin[common_last];
371
    unsigned int  x_low16bits = uin[common_last+1];
372
    d_state[i].ucounter_end = x_high16bits<<16 | x_low16bits;
373
    d_state[i].diff_end=d_state[0].ucounter_end-d_state[i].ucounter_end;//Result is a signed value,Will wrap around on 32 bit boundary
374
    d_state[i].diff_comp_end=d_state[i].ucounter_end-d_state[0].ucounter_end;
375
    //diff_end_min=std::min(diff_end[i],diff_end_min);
376
    //diff_end_max=std::max(diff_end[i],diff_end_max);
377
    diff_comp_end_max=std::max(d_state[i].diff_comp_end,diff_comp_end_max);
378
#ifdef DEBUG_TOCONSUME
379
    if(d_state[i].diff_end!=d_state[i].diff)
380
    {
381
      //samples_lost_or_syncstart=true;
382
      printf("Us%i %i %i ",i,d_state[i].diff_end,d_state[i].diff);
383
    }
384
#endif
385
    all_diffs_zero=all_diffs_zero && (0==d_state[i].diff_end);
386
    if((d_state[i].ucounter_end<d_state[i].ucounter_begin+(unsigned)(common_last/(d_nchan*2))) || (0==d_state[i].ucounter_end) || (0==d_state[i].ucounter_begin)) //(unsigned)(common_last/(d_nchan*2)))
387
    {
388
      sync_found=true;//sync_found or 32 bit counter  wraparound (0xffffffff -> 0x00000000)
389
#ifdef DEBUG_TOCONSUME
390
      tcPrintf("SYNC diff_end[%i]=%i ucounter_end[%i]=%i ucounter_begin[%i]=%i \n",i,d_state[i].diff_end,i,d_state[i].ucounter_end,i,d_state[i].ucounter_begin);
391
      tcPrintf("ucounter_end=%i < %i = ucounter_begin+(unsigned)(common_last/(d_nchan*2) \n",d_state[i].ucounter_end,d_state[i].ucounter_begin+(unsigned)(common_last/(d_nchan*2)));
392
393
      printf("ucounter_end[%i]=%i ucounter_begin[%i]=%i\n",i,d_state[i].ucounter_end,i,d_state[i].ucounter_begin);      
394
      int expected_sync_position=common_last - d_state[i].ucounter_end*(d_nchan*2);
395
      if(0==uin[expected_sync_position] && 0==uin[expected_sync_position+1])
396
      {
397
        printf("sync found on input %i at position %i \n",i,expected_sync_position);
398
        //sync_start[i]=expected_sync_position;
399
      } else
400
      {
401
        printf("sync found on input %i position unclear, expected at %i value there %i\n",i,expected_sync_position,uin[expected_sync_position]<<16 | uin[expected_sync_position+1]);
402
        //sync_start[i]=-1;
403
      }
404
    } else
405
    {
406
      tcPrintf("NOsync diff_end[%i]=%i ucounter_end[%i]=%i ucounter_begin[%i]=%i \n",i,d_state[i].diff_end,i,d_state[i].ucounter_end,i,d_state[i].ucounter_begin);
407
#endif    
408
    }
409
  }
410
  bool problem=false;
411
  for(unsigned int i=0;i<ninputs;i++)
412
    if((d_state[i].diff_end+diff_comp_end_max) >0x4000000)
413
      {
414
        problem=true;
415
        ePrintf("Warning: counter diff greater as 64 Million\n");
416
        ePrintf("         You might want to swap master and slave.\n");
417
        ePrintf("          i=%i,d_state[i].diff_end+diff_comp_end_max=%i,d_state[i].diff_end=%i,diff_comp_end_max=%i,ucounter[i]=%i,ucounter[0]=%i\n",
418
                          i,d_state[i].diff_end+diff_comp_end_max,d_state[i].diff_end,diff_comp_end_max,d_state[i].ucounter_end,d_state[0].ucounter_end);
419
        //ePrintf("        toconsume=%i\n",toconsume); 
420
      }
421
  if(sync_found || all_diffs_zero || problem)
422
  {
423
#ifdef DEBUG_TOCONSUME
424
    if(all_diffs_zero) tcPrintf("ZERO\n");
425
    if(sync_found) tcPrintf("SYNC\n");
426
#endif
427
    for(unsigned int i=0;i<ninputs;i++)
428
    {
429
       memcpy(output_items[i],input_items[i],common_end*item_size);
430
       consume(i,common_end);
431
#ifdef DEBUG_TOCONSUME
432
      if(common_end<256)
433
        tcPrintf("common_end %i\n",common_end);
434
#endif
435
    }
436
    return common_end;
437
  } else
438
  {
439
    //int minconsume=0;//common_end/(2*d_nchan*2);
440
    //min_consume=min_consume*d_nchan*2;  
441
    for(unsigned int i=0;i<ninputs;i++)
442
    {
443
      int toconsume=std::min((d_state[i].diff_end+diff_comp_end_max)*d_nchan*2,ninput_items[i]);
444
      toconsume=toconsume/(d_nchan*2);
445
      toconsume=toconsume*(d_nchan*2);
446
#ifdef DEBUG_TOCONSUME
447
      //printf("dcount %i\n",dcount);
448
      static int toconsume_counter=0;
449
      toconsume_counter++;
450
      //if(toconsume_counter>10)
451
      {
452
        tcPrintf("toconsume=%i diff_end[[%i]*d_nchan*2=%i diff_comp_end_max)*d_nchan*2=%i ninput_items[%i]=%i\n",
453
                  toconsume,i,d_state[i].diff_end*d_nchan*2,diff_comp_end_max*d_nchan*2,i,ninput_items[i]);
454
        toconsume_counter=0;
455
      }
456
#endif
457
      consume(i,toconsume);//skip the difference in samplenumber items
458
      //printf("toconsume%i %i diff_comp_end_max %i diff_end[[%i] %i\n",i,toconsume,diff_comp_end_max,i,d_state[i].diff_end);
459
    }
460
    return 0;
461
  }
462
  return -1;//Should never come here
463
}
464
#endif /*ALIGN_ADVANCED_IMPLEMENTATION*/