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