[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Discuss-gnuradio] MC4020: computer freeze fix
From: |
Sérgio Rui Silva |
Subject: |
[Discuss-gnuradio] MC4020: computer freeze fix |
Date: |
Wed, 18 Jun 2003 20:09:41 +0100 (WEST) |
User-agent: |
PT Multimedia Webmail program |
Fixed the computer freezing problem related to the MC4020
acquisiton board. I send the files with a modified version of the
mc4020-read-adc program, the GrMC4020Source class and a
example program to test the new MC4020 source.
I didn't notice anything wrong with the drivers, it's the way
programs that use them terminate that is the problem... I'm certain
that there is a better way to fix this...
I was having the same problem with the MC4020 acquisiton board
described in this mailing-list. I have dual Athlon MP 2400+, 1GB ,
MSI K7D Master and Promise Ultra133TX2 IDE controller.
I'm running Linux Gentoo with Kernel 2.4.21/GCC 3.2.1. After
wondering why the test-adc program worked fine and all other
freezed my computer at the second run I found that making the
following changes made the trick:
-> the devide must be properly stopped
-> a pause of 1 second is needed before the device stop (don't
know exactly why...)
-> the device must be properly closed
I hope this works for you...
Sérgio Rui Silva
---------------------------------------------------------------------------------------
Words of wisdom:
"Never underestimate the bandwidth of a station wagon full of
tapes hurtling down the highway"
Andrew S. Tanenbaun
-------------------------------------------------------------------------------------
--
SAPO ADSL.PT, apanhe já o comboio da Banda Larga. Kit SAPO ADSL.PT - Grátis
http://adsl.sapo.pt
/* -*- Mode: c++ -*- */
/*
* Copyright 2001 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Sample application to illustrate the use of a GrSimpleScopeSink.
* The input here is provided by the VrSigSource signal generator.
*/
#include <GrMC4020Source.h>
#include <VrFileSource.h>
#include <GrFFTSink.h>
#include <VrFixOffset.h>
#include <VrConnect.h>
#include <VrMultiTask.h>
#include "VrGUI.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <atsc_consts.h>
#define SAMPLING_FREQUENCY 20e6
#define DAUGHTER_CARD_SAMPLING_FREQUENCY (ATSC_SYMBOL_RATE * 2)
#define IOTYPE short
static void
usage (const char *name)
{
fprintf (stderr, "usage: %s [-f <filename>] [-r] [-n] [-x]\n", name);
fprintf (stderr, " -f <filename> : read from file instead of ADC\n");
fprintf (stderr, " -r : continuously repeat the file contents (loop)\n");
fprintf (stderr, " -n : don't subtract the ADC DC offset\n");
fprintf (stderr, " -D : clock input from daughter card\n");
exit (1);
}
int main(int argc, char **argv) {
VrGUI *guimain = new VrGUI(argc, argv);
VrGUILayout *horiz = guimain->top->horizontal();
VrGUILayout *vert = horiz->vertical();
GrMC4020Source<short> *source;
VrSink<IOTYPE> *sink;
VrFixOffset<short,IOTYPE> *offset_fixer;
int c;
char *filename = 0; // if 0, then use ADC for input
bool repeat_p = false; // continuous loop through file
bool fix_offset_p = true; // subtract constant ADC DC offset?
bool clk_from_daughter_card_p = false;
while ((c = getopt (argc, argv, "rf:nD")) != EOF){
switch (c){
case 'f':
filename = optarg;
break;
case 'r':
repeat_p = true;
break;
case 'n':
fix_offset_p = false;
break;
case 'D':
clk_from_daughter_card_p = true;
break;
case '?':
default:
usage (argv[0]);
break;
}
}
/*
if(filename)
source = new VrFileSource<short>(SAMPLING_FREQUENCY, filename, repeat_p);
else {
*/
if (clk_from_daughter_card_p)
source = new GrMC4020Source<short>(DAUGHTER_CARD_SAMPLING_FREQUENCY,
MCC_CH0_EN
| MCC_ALL_1V
| MCC_CLK_AD_START_TRIG_IN);
else
source = new GrMC4020Source<short>(SAMPLING_FREQUENCY,
MCC_CH0_EN
| MCC_ALL_1V
| MCC_CLK_INTERNAL);
//}
sink = new GrFFTSink<IOTYPE>(vert, 20, 100, 1024);
if (fix_offset_p){
offset_fixer = new VrFixOffset<short,IOTYPE>();
NWO_CONNECT (source, offset_fixer);
NWO_CONNECT (offset_fixer, sink);
}
else
NWO_CONNECT (source, sink);
VrMultiTask *m = new VrMultiTask ();
m->add (sink);
m->start();
guimain->start();
int i = 1000;
while (i--) {
guimain->processEvents(10 /*ms*/);
m->process();
}
// This is important:
delete source; // <--
// The class destructor MUST be called so the device can be properly stopped
and closed
}
/* -*- Mode: c++ -*- */
/*
* Copyright 2001 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified in 18/6/2003 by Sergio Rui Silva to fix a computer
* freezing causing bug. Remember that all programs using this class MUST
* call the destructor in their end so the device can be properly stopped and
closed.
*/
#ifndef _GRMC4020SOURCE_H_
#define _GRMC4020SOURCE_H_
extern "C" {
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
}
#include <VrSource.h>
#include <GrMC4020Buffer.h>
static const char *GRMC_DEVICE_NAME = "/dev/mc4020_0";
static const unsigned long GRMC_DEFAULT_CONFIG_BITMASK = MCC_CH0_EN |
MCC_ALL_5V;
static const double GRMC_DEFAULT_SAMPLE_FREQ = 20e6;
#define SAMPLES_PER_PAGE (PAGE_SIZE / sizeof (oType))
// FIXME ought to be configurable
#define MC4020_BUFFER_SIZE (16L << 20) // 16 MB
template<class oType>
class GrMC4020Source: public VrSource<oType> {
public:
virtual const char *name() { return "GrMC4020Source"; }
virtual float memoryTouched() {
return 0; //no outputs are cached
}
virtual int work2(VrSampleRange output, void *o[]);
virtual void initOutputBuffer(int n);
GrMC4020Source(double sample_freq = GRMC_DEFAULT_SAMPLE_FREQ,
unsigned long a_bitmask = GRMC_DEFAULT_CONFIG_BITMASK);
~GrMC4020Source();
protected:
int device_fd;
unsigned long config_bitmask;
unsigned long buffersize_pages;
// we own num_pages starting at page_index
unsigned long page_index; // driver page index of first page we own
VrSampleIndex sample_index; // sample index that corresponds to page_index
unsigned long num_pages; // number of driver pages we own
unsigned long npages_to_free ();
unsigned long index_sub (unsigned long a, unsigned long b);
};
template<class oType> unsigned long
GrMC4020Source<oType>::index_sub (unsigned long a, unsigned long b)
{
long s = a - b;
if (s < 0)
s += buffersize_pages;
assert (s >= 0 && (unsigned long) s < buffersize_pages);
return s;
}
/*!
* Determine how many pages at the beginning of the region that
* the driver has allocated to us we no longer need. The earliest
* VrSampleIndex in use is given by proc_minRP(). We use this and
* sample_index (the VrSampleIndex of the beginning of the active portion
* of the driver buffer) to see if we can return some pages to the driver.
*/
template<class oType> unsigned long
GrMC4020Source<oType>::npages_to_free ()
{
VrSampleIndex minRP = proc_minRP ();
// round down to page boundary
minRP &= ~((VrSampleIndex) SAMPLES_PER_PAGE - 1);
assert (minRP != (VrSampleIndex) -1);
assert (minRP >= sample_index);
return (unsigned long) (minRP - sample_index) / SAMPLES_PER_PAGE;
}
template<class oType> int
GrMC4020Source<oType>::work2(VrSampleRange output, void *ao[])
{
struct mc4020_status status;
VrSampleIndex target_index = output.index + output.size;
unsigned long npgs;
int last_lost = 0;
sync(output.index);
// fprintf (stderr, "@");
while ((sample_index + num_pages * SAMPLES_PER_PAGE) < target_index){
npgs = npages_to_free ();
// fprintf (stderr, "f: %lu\n", npgs);
status.num = npgs; // free npgs pages
status.index = page_index; // starting here
// free the pages and get new active region
if (ioctl(device_fd, GIOCSETGETSTATUS, &status) < 0) {
perror("GrMC4020Source: failed to get mc4020 status");
exit(-1);
}
// how many pages did the beginning of our buffer advance?
// new_index - old_index
unsigned long delta = index_sub (status.index, page_index);
assert (npgs == delta);
sample_index += delta * SAMPLES_PER_PAGE;
// fprintf (stderr, "G: %lu\n", index_sub (status.index + status.num,
page_index + num_pages));
// remember new range
page_index = status.index;
num_pages = status.num;
// do something about overruns
if(status.lost && !last_lost) {
// fprintf(stderr,"GrMC4020Source: overrun\n");
fputc ('O', stderr);
}
last_lost = status.lost;
}
return output.size;
}
template<class oType> void
GrMC4020Source<oType>::initOutputBuffer (int n)
{
if (n != 0) {
fprintf(stderr,"GrMC4020Source can only have one output buffer.\n");
exit(-1);
}
outBuffer[0] = new GrMC4020Buffer (this, device_fd,
buffersize_pages * PAGE_SIZE);
}
template<class oType>
GrMC4020Source<oType>::GrMC4020Source(double sample_freq, unsigned long bitmask)
: device_fd(-1), page_index(0), sample_index(0), num_pages(0)
{
printf("Starting MC4020...\n");
struct mc4020_config c;
buffersize_pages = MC4020_BUFFER_SIZE / PAGE_SIZE;
if ((device_fd = open(GRMC_DEVICE_NAME, O_RDONLY)) < 0) {
perror(GRMC_DEVICE_NAME);
exit(1);
}
if ((bitmask & MCC_CLK_MASK) == MCC_CLK_INTERNAL)
c.scan_rate = (unsigned long) sample_freq;
else
c.scan_rate = 2; // minimum divisor
config_bitmask = (bitmask & ~MCC_ASRC_MASK) | MCC_ASRC_BNC; // ensure some
sanity
if ((bitmask & (MCC_CH0_EN | MCC_CH1_EN | MCC_CH2_EN | MCC_CH3_EN)) == 0){
fprintf (stderr, "GrMC4020Source: you must enable at least one channel\n");
exit (1);
}
c.bitmask = config_bitmask;
if (ioctl (device_fd, GIOCSETCONFIG, &c) < 0){
perror ("can't set GrMC4020Source configuration (GIOCSETCONFIG)");
exit (1);
}
if (ioctl (device_fd, GIOCSETBUFSIZE, buffersize_pages * PAGE_SIZE) < 0) {
fprintf (stderr, "buffersize = %ld (%#lx)\n", MC4020_BUFFER_SIZE,
MC4020_BUFFER_SIZE);
perror("GrMC4020Buffer(allocateBuffer): Failed to set buffersize");
exit(-1);
}
if (ioctl (device_fd, GIOCSTART) < 0){
perror ("GIOCSTART failed");
exit (1);
}
setSamplingFrequency (sample_freq);
setOutputSize (SAMPLES_PER_PAGE);
}
template<class oType>
GrMC4020Source<oType>::~GrMC4020Source() {
printf("Shutting down MC4020...\n");
sleep(1);
//Stop receive
if((ioctl(device_fd, GIOCSTOP)) < 0)
perror("Failed to stop receive!...");
else
printf("Stop receive...\n");
//Munmap and Close
/*
if(munmap(readbuf,buffersize*PAGE_SIZE)<0)
perror("Failed to munmap buffer");
else
print("Success: munmap\n");
*/
if(close(device_fd)<0)
perror("Failed to close fd!...\n");
else
printf("MC4020 closed...\n");
}
#endif
/*
* Copyright 2001 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "mc4020.h"
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/times.h>
#define TRUE 1
#define FALSE 0
#define DEFAULT_CHANNEL MCC_CH0_EN
#define BUFFERSIZE_IN_SECONDS (0.5)
char *dev = "/dev/mc4020_0";
#define INFINITE_COUNT ((long long) -1)
struct optvals {
int source;
int range;
int chan[4];
unsigned long freq;
long long count; // # of samples
int binary_p; // TRUE if binary, else ascii
int fix_offset_p; // TRUE if fix_offset, else dont
int verbose;
int help;
int threshold;
int clock_source;
int acquire_to_mem; // TRUE if we should acquire all data
// to mem prior to writing to disk
};
inline static long
lmin (long a, long b)
{
return a < b ? a : b;
}
static void
usage (struct option *option)
{
int i;
int len = 0;
fprintf (stderr,
"usage: mc4020-read-adc [-a] [-b] [-v] [-c <count>] [-f <freq>]\n");
for (i = 0; option[i].name != 0; i++){
if (len == 0){
fprintf (stderr, "\t");
len = 8;
}
fprintf (stderr, "[--%s", option[i].name);
len += strlen (option[i].name) + 1;
switch (option[i].has_arg){
default:
case no_argument:
fprintf (stderr, "] ");
len += 2;
break;
case required_argument:
fprintf (stderr, "=<value>] ");
len += 10;
break;
case optional_argument:
fprintf (stderr, "[=<value>]]");
len += 12;
break;
}
if (len >= 64){
fprintf (stderr, "\n");
len = 0;
}
}
if (len != 0)
fprintf (stderr, "\n");
}
// return pointer to statically allocated optvals struct iff successful,
// else NULL
struct optvals *
parse_args (int argc, char **argv)
{
static struct optvals opt;
static struct option long_options[] = {
// these options set a flag
{ "src-bnc", no_argument, &opt.source, MCC_ASRC_BNC },
{ "src-gnd", no_argument, &opt.source, MCC_ASRC_CAL_AGND },
{ "src-0.625", no_argument, &opt.source, MCC_ASRC_CAL_0_625 },
{ "src-4.375", no_argument, &opt.source, MCC_ASRC_CAL_4_375 },
{ "src-hdr", no_argument, &opt.source, MCC_ASRC_CAL_HDR },
{ "ch0", no_argument, &opt.chan[0], 1 },
{ "ch1", no_argument, &opt.chan[1], 1 },
{ "ch2", no_argument, &opt.chan[2], 1 },
{ "ch3", no_argument, &opt.chan[3], 1 },
{ "5v", no_argument, &opt.range, MCC_ALL_5V },
{ "1v", no_argument, &opt.range, MCC_ALL_1V },
{ "ascii", no_argument, &opt.binary_p, FALSE },
{ "binary", no_argument, &opt.binary_p, TRUE },
{ "fix-offset",no_argument, &opt.fix_offset_p, TRUE },
{ "nofix-offset",no_argument, &opt.fix_offset_p, FALSE },
{ "help", no_argument, &opt.help, TRUE },
{ "verbose", no_argument, &opt.verbose, TRUE },
{ "clk-internal", no_argument, &opt.clock_source,
MCC_CLK_INTERNAL },
{ "clk-ext-bnc", no_argument, &opt.clock_source, MCC_CLK_EXT_BNC
},
{ "clk-ad-start-trig-in", no_argument, &opt.clock_source,
MCC_CLK_AD_START_TRIG_IN },
{ "ext-bnc-threshold-0v", no_argument, &opt.threshold,
MCC_EXT_BNC_THRESH_ZERO },
{ "ext-bnc-threshold-2.5v", no_argument, &opt.threshold,
MCC_EXT_BNC_THRESH_2_5V },
{ "acquire-to-mem-then-write", no_argument, &opt.acquire_to_mem, TRUE
},
{ "noacquire-to-mem-then-write", no_argument, &opt.acquire_to_mem, FALSE
},
// these options take an arg
{ "count", required_argument, 0, 'c' },
{ "freq", required_argument, 0, 'f' },
{ 0, 0, 0, 0 }
};
int c;
memset (&opt, 0, sizeof (opt));
opt.source = MCC_ASRC_BNC;
opt.range = MCC_ALL_5V;
opt.freq = 20000000;
opt.count = INFINITE_COUNT;
opt.binary_p = FALSE;
opt.fix_offset_p = TRUE;
opt.verbose = FALSE;
opt.clock_source = MCC_CLK_INTERNAL;
opt.threshold = MCC_EXT_BNC_THRESH_ZERO;
while (1){
int option_index = 0;
c = getopt_long (argc, argv, "abvf:c:",
long_options, &option_index);
if (c == -1) // end of options
break;
switch (c){
case 0:
// if this option sets a flag, do nothing else now.
break;
case 'a':
opt.binary_p = FALSE;
break;
case 'b':
opt.binary_p = TRUE;
break;
case 'v':
opt.verbose = TRUE;
break;
case 'f':
opt.freq = strtol (optarg, 0, 0);
break;
case 'c':
opt.count = (long long) strtod (optarg, 0);
break;
case '?':
// getopt_long already printed an error message
usage (long_options);
return 0;
default:
abort ();
}
}
if (opt.help){
usage (long_options);
return 0;
}
if (opt.count == INFINITE_COUNT && opt.acquire_to_mem){
fprintf (stderr, "can't use --acquire-to-mem-then-write without specifying
--count\n");
usage (long_options);
return 0;
}
return &opt;
}
static void
fill_config (struct mc4020_config *c, int source, int range,
int chan[4], unsigned long freq, int clock_source, int threshold)
{
memset (c, 0, sizeof (*c));
c->scan_rate = freq;
c->bitmask = source | range | clock_source | threshold;
if (chan[0]) c->bitmask |= MCC_CH0_EN;
if (chan[1]) c->bitmask |= MCC_CH1_EN;
if (chan[2]) c->bitmask |= MCC_CH2_EN;
if (chan[3]) c->bitmask |= MCC_CH3_EN;
if ((c->bitmask & (MCC_CH0_EN | MCC_CH1_EN | MCC_CH2_EN | MCC_CH3_EN)) == 0)
c->bitmask |= DEFAULT_CHANNEL;
}
static int
double_mmap (int fd, unsigned long bufsize, void **bufptr)
{
int fdz;
char *start = 0;
fdz = open ("/dev/zero", O_RDONLY);
if (fdz < 0){
perror ("/dev/zero");
return 0;
}
start = (char *) mmap (0, bufsize * 2, PROT_NONE, MAP_SHARED, fdz, 0);
if (start == MAP_FAILED || munmap (start, bufsize * 2) == -1){
perror ("Could not allocate mmap buffer");
return 0;
}
close (fdz);
if ((mmap (start, bufsize, PROT_READ,
MAP_FIXED | MAP_SHARED, fd, 0)) == MAP_FAILED
|| (mmap (start + bufsize, bufsize, PROT_READ,
MAP_FIXED | MAP_SHARED, fd, 0)) == MAP_FAILED){
perror ("Could not mmap ADC buffer");
return 0;
}
*bufptr = start;
return 1;
}
typedef int (*formatter_t)(int outfd,
FILE *outfp,
const char *buf,
unsigned long count);
int
format_binary_nofix_offset (int outfd, FILE *outfp, const char *buf,
unsigned long count)
{
int n;
while (count > 0){
n = write (outfd, buf, count);
if (n < 0){
perror ("write error");
return FALSE;
}
count -= n;
buf += n;
}
return TRUE;
}
#define TMPSIZE (32 * 1024)
int
format_binary_fix_offset (int outfd, FILE *outfp, const char *buf,
unsigned long count)
{
int n, m, i;
const short *sp;
short tmp[TMPSIZE];
while (count > 0){
m = lmin (sizeof (short) * TMPSIZE, count);
sp = (const short *) buf;
for (i = 0; i < m / sizeof (short); i++)
tmp[i] = sp[i] - 0x0800;
n = write (outfd, tmp, m);
if (n < 0){
perror ("write error");
return FALSE;
}
count -= n;
buf += n;
}
return TRUE;
}
#if 0 // these work but are really slooooow
int
format_ascii_nofix_offset (int outfd, FILE *outfp, const char *buf,
unsigned long count)
{
int i;
const short *sp = (const short *) buf;
for (i = 0; i < count / sizeof (short); i++)
fprintf (outfp, "%4d\n", sp[i]);
return TRUE;
}
int
format_ascii_fix_offset (int outfd, FILE *outfp, const char *buf,
unsigned long count)
{
int i;
const short *sp = (const short *) buf;
for (i = 0; i < count / sizeof (short); i++)
fprintf (outfp, "%5d\n", sp[i] - 0x0800);
return TRUE;
}
#else
// convert a signed integer into ascii.
// The integer is known to be in the range -9999 <= v <= 9999
//
// writes 6 bytes into buf.
// format is equivalent to sprintf (buf, "%5d\n", v) but without
// the trailing null
inline static void
convert_1 (char *buf, int v)
{
unsigned u, r;
int i;
char sign;
buf[5] = '\n';
if (v == 0){
buf[0] = ' ';
buf[1] = ' ';
buf[2] = ' ';
buf[3] = ' ';
buf[4] = '0';
return;
}
sign = ' ';
u = v;
if (v < 0){
u = -v;
sign = '-';
}
i = 4;
while (u != 0){
r = u % 10;
u = u / 10;
buf[i--] = r + '0';
}
buf[i--] = sign;
while (i >= 0)
buf[i--] = ' ';
}
#define SAMPLES_PER_BLK 4096
int
format_ascii_fix_either (int outfd, FILE *outfp,
const char *inbuf, unsigned long count,
int offset)
{
int i;
const short *sp = (const short *) inbuf;
char outbuf[6*SAMPLES_PER_BLK];
char *op;
count /= sizeof (short); // convert to sample count
// do a block's worth
while (count >= SAMPLES_PER_BLK){
op = outbuf;
for (i = 0; i < SAMPLES_PER_BLK; i++){
convert_1 (op, (sp[i] & 0x0fff) - offset);
op += 6;
}
if (!format_binary_nofix_offset (outfd, outfp, outbuf, sizeof (outbuf)))
return FALSE;
count -= SAMPLES_PER_BLK;
sp += SAMPLES_PER_BLK;
}
// finish up any fragment of a block
if (count > 0){
op = outbuf;
for (i = 0; i < count; i++){
convert_1 (op, (sp[i] & 0x0fff) - offset);
op += 6;
}
if (!format_binary_nofix_offset (outfd, outfp,
outbuf, count * 6))
return FALSE;
}
return TRUE;
}
int
format_ascii_nofix_offset (int outfd, FILE *outfp, const char *buf,
unsigned long count)
{
return format_ascii_fix_either (outfd, outfp, buf, count, 0);
}
int
format_ascii_fix_offset (int outfd, FILE *outfp, const char *buf,
unsigned long count)
{
return format_ascii_fix_either (outfd, outfp, buf, count, 0x0800);
}
#endif
static char *
allocate_buffer (size_t size, int verbose)
{
char *ram_buf = 0;
size_t i;
int page_size = getpagesize ();
ram_buf = malloc (size);
if (ram_buf == 0){
perror ("Can't allocate ram buffer");
return 0;
}
if (mlock (ram_buf, size) == -1){
if (errno == EPERM)
fprintf (stderr,
"Unable to mlock buffer. Run as root if you're getting overruns.\n");
else
perror ("mlock");
/*
* We failed to mlock, at least try to fault the buffer in...
*/
if (verbose)
fprintf (stderr, "Faulting in ram buffer...");
for (i = 0; i < size; i += page_size)
ram_buf[i] = 1;
if (verbose)
fprintf (stderr, "Done!\n");
}
return ram_buf;
}
#if 0
static void
deallocate_buffer (char *buf, size_t size)
{
munlock (buf, size);
free (buf);
}
#endif
static int
drop_privs (void)
{
if (setgid (getgid ()) < 0){
perror ("setgid");
return FALSE;
}
if (setuid (getuid ()) < 0){
perror ("setuid");
return FALSE;
}
return TRUE;
}
int
main_loop (int infd, int outfd,
char *buf, long long total_count, int verbose,
formatter_t formatter, char *ram_buf)
{
struct mc4020_status status;
clock_t start_ticks, stop_ticks;
struct tms start_tms, stop_tms;
long ticks_per_second = sysconf (_SC_CLK_TCK);
int page_size = getpagesize ();
double elapsed_time;
char *p;
FILE *outfp;
long long count = 0;
long total_lost = 0;
if ((outfp = fdopen (outfd, "w")) == 0){
perror ("fdopen");
return FALSE;
}
memset (&status, 0, sizeof (status));
start_ticks = times (&start_tms);
while (total_count == INFINITE_COUNT || count < total_count){
unsigned long n;
if (ioctl (infd, GIOCSETGETSTATUS, &status) < 0){
perror ("giocsetgetstatus");
return FALSE;
}
if (status.lost){
total_lost++;
if (verbose)
fprintf (stderr, "O");
}
if (status.num){
// printf ("%6d\t%6d\t%d\n", status.index, status.num, status.lost);
p = &buf[status.index * page_size];
n = status.num * page_size;
if (total_count != INFINITE_COUNT){
if (total_count - count < n)
n = total_count - count;
}
if (ram_buf){
// defer formatting and i/o, just copy to ram
memcpy (&ram_buf[count], p, n);
}
else {
if (!formatter (outfd, outfp, p, n))
return FALSE;
}
count += n;
/* fprintf (stderr, status.lost ? "n" : "N"); */
}
else { // status.num == 0
/* fprintf (stderr, status.lost ? "z" : "Z"); */
}
}
stop_ticks = times (&stop_tms);
elapsed_time = (stop_ticks - start_ticks) / (double) ticks_per_second;
if (verbose){
fprintf (stderr,
"transfered %lld bytes in %.2f seconds, %.3g bytes/sec\n",
count, elapsed_time, count / elapsed_time);
}
if (total_lost != 0){ // always show overruns
if (total_lost == 1)
fprintf (stderr, "warning: 1 overrun\n");
else
fprintf (stderr, "warning: %ld overruns\n", total_lost);
}
if (ram_buf){
// now handle deferred formatting and i/o
if (!formatter (outfd, outfp, ram_buf, count))
return FALSE;
}
return total_lost == 0;
}
int
main (int argc, char **argv)
{
int fd;
struct mc4020_config config;
char *data;
struct optvals *opt;
long bufsize;
int nchans;
formatter_t formatter;
char *ram_buf = 0;
opt = parse_args (argc, argv);
if (opt == 0)
return 1;
fill_config (&config, opt->source, opt->range, opt->chan, opt->freq,
opt->clock_source, opt->threshold);
fd = open (dev, O_RDONLY);
if (fd < 0){
perror (dev);
return 1;
}
if (ioctl (fd, GIOCSETCONFIG, &config) < 0){
perror ("giocsetconfig");
return 1;
}
if (opt->clock_source != MCC_CLK_INTERNAL)
opt->freq = 20000000; // use this value for bufsize calculation
// compute a reasonable buffersize ...
nchans = opt->chan[0] + opt->chan[1] + opt->chan[2] + opt->chan[3];
bufsize = nchans * opt->freq * sizeof (short) * BUFFERSIZE_IN_SECONDS;
bufsize = (bufsize + MCBUF_MULTIPLE - 1) & ~(MCBUF_MULTIPLE - 1);
if (bufsize < MCBUF_MINIMUM)
bufsize = MCBUF_MINIMUM;
if (opt->verbose)
fprintf (stderr, "bufsize: %ld (0x%lx)\n", bufsize, bufsize);
if (ioctl (fd, GIOCSETBUFSIZE, bufsize) < 0){
perror ("setbufsize");
return 1;
}
/*
* Ideally, we'd like to do this up top, and then drop privs earlier,
* but it turns out that we really need to get the kernel buffers allocated
* in GIOCSETBUFSIZE before me malloc and mlock a GB or so of memory.
* [Some of the driver's kernel buffers need to be contiguous.]
*/
if (opt->acquire_to_mem){
assert (opt->count >= 0);
if (opt->count >= ((long long) 1) << 31){
/* I'm sure this will be proven wrong eventually... */
fprintf (stderr, "When using acquire_to_mem, count must be <= 2^31\n");
exit (1);
}
ram_buf = allocate_buffer (opt->count * sizeof (short), opt->verbose);
if (ram_buf == 0)
exit (1);
}
if (!drop_privs ()) // drop any setuid / setgid privs
exit (1);
if (!double_mmap (fd, bufsize, (void **) &data))
return 1;
if (opt->binary_p){
if (opt->fix_offset_p)
formatter = format_binary_fix_offset;
else
formatter = format_binary_nofix_offset;
}
else {
if (opt->fix_offset_p)
formatter = format_ascii_fix_offset;
else
formatter = format_ascii_nofix_offset;
}
if (ioctl (fd, GIOCSTART, 0) < 0){
perror ("giocstart");
return 1;
}
//sleep(1);
{
long long byte_count = opt->count;
if (byte_count != INFINITE_COUNT)
byte_count *= sizeof (short);
if (main_loop (fd, 1, data, byte_count, opt->verbose, formatter, ram_buf)
== 0)
printf("Error in the main loop!...\n");
/*
return 0;
else
return 1;
*/
}
sleep(1);
//Stop receive
if((ioctl(fd, GIOCSTOP)) < 0) {
perror("Failed to stop receive");
}
else
fprintf(stderr,"Success: stop receive\n");
//Munmap and Close
/*
if(munmap(readbuf,buffersize*PAGE_SIZE)<0) {
perror("Failed to munmap buffer");
}
else
fprintf(stderr,"Success: munmap\n");
*/
if(close(fd)<0) {
perror("Failed to close fd");
}
else
fprintf(stderr,"Success: close\n");
return 0;
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Discuss-gnuradio] MC4020: computer freeze fix,
Sérgio Rui Silva <=