Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GrMC4020Source.h

Go to the documentation of this file.
00001 /* -*- Mode: c++ -*- */
00002 /*
00003  * Copyright 2001 Free Software Foundation, Inc.
00004  * 
00005  * This file is part of GNU Radio
00006  * 
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2, or (at your option)
00010  * any later version.
00011  * 
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with GNU Radio; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020  * Boston, MA 02111-1307, USA.
00021  */
00022 #ifndef _GRMC4020SOURCE_H_
00023 #define _GRMC4020SOURCE_H_
00024 
00025 extern "C" {
00026 #include <sys/ioctl.h>
00027 #include <fcntl.h>
00028 #include <errno.h>
00029 #include <assert.h>
00030 }
00031 
00032 #include <VrSource.h>
00033 #include <GrMC4020Buffer.h>
00034 #include <mc4020.h>
00035 
00036 static const char         *GRMC_DEVICE_NAME = "/dev/mc4020_0";
00037 static const unsigned long GRMC_DEFAULT_CONFIG_BITMASK = MCC_CH0_EN | MCC_ALL_5V;
00038 static const double        GRMC_DEFAULT_SAMPLE_FREQ = 20e6;
00039 
00040 #define SAMPLES_PER_PAGE   (PAGE_SIZE / sizeof (oType))
00041 
00042 
00043 // FIXME ought to be configurable
00044 #define MC4020_BUFFER_SIZE      (16L << 20)     // 16 MB
00045 
00046 
00047 template<class oType> 
00048 class GrMC4020Source: public VrSource<oType> {
00049 
00050 public: 
00051   virtual const char *name() { return "GrMC4020Source"; }
00052 
00053   virtual float memoryTouched() {
00054     return 0; //no outputs are cached
00055   }
00056 
00057   virtual int work2(VrSampleRange output, void *o[]);
00058   virtual void initOutputBuffer(int n);
00059 
00060   GrMC4020Source(double sample_freq = GRMC_DEFAULT_SAMPLE_FREQ,
00061                  unsigned long a_bitmask = GRMC_DEFAULT_CONFIG_BITMASK);
00062 
00063 protected:
00064   int           device_fd;
00065   unsigned long config_bitmask;
00066   unsigned long buffersize_pages;
00067 
00068   // we own num_pages starting at page_index
00069   
00070   unsigned long page_index;     // driver page index of first page we own
00071   VrSampleIndex sample_index;   // sample index that corresponds to page_index
00072   unsigned long num_pages;      // number of driver pages we own
00073 
00074   unsigned long npages_to_free ();
00075   unsigned long index_sub (unsigned long a, unsigned long b);
00076 };
00077 
00078 template<class oType> unsigned long 
00079 GrMC4020Source<oType>::index_sub (unsigned long a, unsigned long b)
00080 {
00081   long s = a - b;
00082 
00083   if (s < 0)
00084     s += buffersize_pages;
00085 
00086   assert (s >= 0 && (unsigned long) s < buffersize_pages);
00087   return s;
00088 }
00089 
00097 template<class oType> unsigned long 
00098 GrMC4020Source<oType>::npages_to_free ()
00099 {
00100   VrSampleIndex         minRP = proc_minRP ();
00101 
00102   // round down to page boundary
00103   minRP &= ~((VrSampleIndex) SAMPLES_PER_PAGE - 1);   
00104 
00105   assert (minRP != (VrSampleIndex) -1);
00106   assert (minRP >= sample_index);
00107 
00108   return (unsigned long) (minRP - sample_index) / SAMPLES_PER_PAGE;
00109 }
00110 
00111 template<class oType> int
00112 GrMC4020Source<oType>::work2(VrSampleRange output, void *ao[])
00113 {
00114   struct mc4020_status  status;
00115   VrSampleIndex         target_index = output.index + output.size;
00116   unsigned long         npgs;
00117   int                   last_lost = 0;
00118 
00119   sync(output.index);
00120 
00121   // fprintf (stderr, "@");
00122 
00123   while ((sample_index + num_pages * SAMPLES_PER_PAGE) < target_index){
00124     npgs = npages_to_free ();
00125     
00126     // fprintf (stderr, "f: %lu\n", npgs);
00127     
00128     status.num = npgs;          // free npgs pages
00129     status.index = page_index;  // starting here
00130 
00131     // free the pages and get new active region
00132     if (ioctl(device_fd, GIOCSETGETSTATUS, &status) < 0) {
00133       perror("GrMC4020Source: failed to get mc4020 status");
00134       exit(-1);
00135     }
00136 
00137     // how many pages did the beginning of our buffer advance?
00138     //                                 new_index - old_index
00139     unsigned long delta = index_sub (status.index, page_index);
00140     assert (npgs == delta);
00141 
00142     sample_index += delta * SAMPLES_PER_PAGE;
00143 
00144     // fprintf (stderr, "G: %lu\n", index_sub (status.index + status.num, page_index + num_pages));
00145 
00146     // remember new range
00147     page_index = status.index;
00148     num_pages = status.num;
00149 
00150     // do something about overruns
00151     if(status.lost && !last_lost) {
00152       // fprintf(stderr,"GrMC4020Source: overrun\n");
00153       fputc ('O', stderr);
00154     }
00155     last_lost = status.lost;
00156   }
00157 
00158   return output.size;
00159 }
00160 
00161 
00162 template<class oType> void
00163 GrMC4020Source<oType>::initOutputBuffer (int n)
00164 {
00165   if (n != 0) {
00166     fprintf(stderr,"GrMC4020Source can only have one output buffer.\n");
00167     exit(-1);
00168   }
00169   outBuffer[0] = new GrMC4020Buffer (this, device_fd,
00170                                      buffersize_pages * PAGE_SIZE);
00171 }
00172 
00173 template<class oType>
00174 GrMC4020Source<oType>::GrMC4020Source(double sample_freq, unsigned long bitmask)
00175   : device_fd(-1), page_index(0), sample_index(0), num_pages(0)
00176 {
00177   struct mc4020_config  c;
00178   
00179   buffersize_pages = MC4020_BUFFER_SIZE / PAGE_SIZE;
00180   
00181   if ((device_fd = open(GRMC_DEVICE_NAME, O_RDONLY)) < 0) {
00182     perror(GRMC_DEVICE_NAME);
00183     exit(1);
00184   }
00185 
00186   if ((bitmask & MCC_CLK_MASK) == MCC_CLK_INTERNAL)
00187     c.scan_rate = (unsigned long) sample_freq;
00188   else
00189     c.scan_rate = 2;    // minimum divisor
00190   
00191   config_bitmask = (bitmask & ~MCC_ASRC_MASK) | MCC_ASRC_BNC;   // ensure some sanity
00192 
00193   if ((bitmask & (MCC_CH0_EN | MCC_CH1_EN | MCC_CH2_EN | MCC_CH3_EN)) == 0){
00194     fprintf (stderr, "GrMC4020Source: you must enable at least one channel\n");
00195     exit (1);
00196   }
00197 
00198   c.bitmask = config_bitmask;
00199 
00200   if (ioctl (device_fd, GIOCSETCONFIG, &c) < 0){
00201     perror ("can't set GrMC4020Source configuration (GIOCSETCONFIG)");
00202     exit (1);
00203   }
00204 
00205   if (ioctl (device_fd, GIOCSETBUFSIZE, buffersize_pages * PAGE_SIZE) < 0) {
00206     fprintf (stderr, "buffersize = %ld (%#lx)\n", MC4020_BUFFER_SIZE, MC4020_BUFFER_SIZE);
00207     perror("GrMC4020Buffer(allocateBuffer): Failed to set buffersize");
00208     exit(-1);
00209   }
00210 
00211   if (ioctl (device_fd, GIOCSTART) < 0){
00212     perror ("GIOCSTART failed");
00213     exit (1);
00214   }
00215 
00216 
00217   setSamplingFrequency (sample_freq);
00218 
00219   setOutputSize (SAMPLES_PER_PAGE);
00220 }
00221 
00222 #endif 

Generated on Tue Mar 15 23:55:33 2005 for GNU Radio by  doxygen 1.4.0