00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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;
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
00069
00070 unsigned long page_index;
00071 VrSampleIndex sample_index;
00072 unsigned long num_pages;
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
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
00122
00123 while ((sample_index + num_pages * SAMPLES_PER_PAGE) < target_index){
00124 npgs = npages_to_free ();
00125
00126
00127
00128 status.num = npgs;
00129 status.index = page_index;
00130
00131
00132 if (ioctl(device_fd, GIOCSETGETSTATUS, &status) < 0) {
00133 perror("GrMC4020Source: failed to get mc4020 status");
00134 exit(-1);
00135 }
00136
00137
00138
00139 unsigned long delta = index_sub (status.index, page_index);
00140 assert (npgs == delta);
00141
00142 sample_index += delta * SAMPLES_PER_PAGE;
00143
00144
00145
00146
00147 page_index = status.index;
00148 num_pages = status.num;
00149
00150
00151 if(status.lost && !last_lost) {
00152
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;
00190
00191 config_bitmask = (bitmask & ~MCC_ASRC_MASK) | MCC_ASRC_BNC;
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