3 * Copyright 2002,2010 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
27 #include <gr_circular_file.h>
30 #ifdef HAVE_SYS_MMAN_H
33 #include <sys/types.h>
45 static const int HEADER_SIZE = 4096;
46 static const int HEADER_MAGIC = 0xEB021026;
48 static const int HD_MAGIC = 0;
49 static const int HD_HEADER_SIZE = 1; // integer offsets into header
50 static const int HD_BUFFER_SIZE = 2;
51 static const int HD_BUFFER_BASE = 3;
52 static const int HD_BUFFER_CURRENT = 4;
54 gr_circular_file::gr_circular_file (const char *filename,
55 bool writable, int size)
56 : d_fd (-1), d_header (0), d_buffer (0), d_mapped_size (0), d_bytes_read (0)
61 mm_prot = PROT_READ | PROT_WRITE;
63 d_fd = open (filename, O_CREAT | O_RDWR | O_TRUNC, 0664);
68 #ifdef HAVE_MMAP /* FIXME */
69 if(ftruncate (d_fd, size + HEADER_SIZE) != 0) {
79 d_fd = open (filename, O_RDONLY);
87 if (fstat (d_fd, &statbuf) < 0){
92 if (statbuf.st_size < HEADER_SIZE){
93 fprintf (stderr, "%s: file too small to be circular buffer\n", filename);
97 d_mapped_size = statbuf.st_size;
99 void *p = mmap (0, d_mapped_size, mm_prot, MAP_SHARED, d_fd, 0);
100 if (p == MAP_FAILED){
101 perror ("gr_circular_file: mmap failed");
105 d_header = (int *) p;
107 perror ("gr_circular_file: mmap unsupported by this system");
111 if (writable){ // init header
114 fprintf (stderr, "gr_circular_buffer: size must be > 0 when writable\n");
118 d_header[HD_MAGIC] = HEADER_MAGIC;
119 d_header[HD_HEADER_SIZE] = HEADER_SIZE;
120 d_header[HD_BUFFER_SIZE] = size;
121 d_header[HD_BUFFER_BASE] = HEADER_SIZE; // right after header
122 d_header[HD_BUFFER_CURRENT] = 0;
125 // sanity check (the asserts are a bit unforgiving...)
127 assert (d_header[HD_MAGIC] == HEADER_MAGIC);
128 assert (d_header[HD_HEADER_SIZE] == HEADER_SIZE);
129 assert (d_header[HD_BUFFER_SIZE] > 0);
130 assert (d_header[HD_BUFFER_BASE] >= d_header[HD_HEADER_SIZE]);
131 assert (d_header[HD_BUFFER_BASE] + d_header[HD_BUFFER_SIZE] <= d_mapped_size);
132 assert (d_header[HD_BUFFER_CURRENT] >= 0 &&
133 d_header[HD_BUFFER_CURRENT] < d_header[HD_BUFFER_SIZE]);
136 d_buffer = (unsigned char *) d_header + d_header[HD_BUFFER_BASE];
139 gr_circular_file::~gr_circular_file ()
142 if (munmap ((char *) d_header, d_mapped_size) < 0){
143 perror ("gr_circular_file: munmap");
151 gr_circular_file::write (void *vdata, int nbytes)
153 unsigned char *data = (unsigned char *) vdata;
154 int buffer_size = d_header[HD_BUFFER_SIZE];
155 int buffer_current = d_header[HD_BUFFER_CURRENT];
158 int n = std::min (nbytes, buffer_size - buffer_current);
159 memcpy (d_buffer + buffer_current, data, n);
162 if (buffer_current >= buffer_size)
169 d_header[HD_BUFFER_CURRENT] = buffer_current;
174 gr_circular_file::read (void *vdata, int nbytes)
176 unsigned char *data = (unsigned char *) vdata;
177 int buffer_current = d_header[HD_BUFFER_CURRENT];
178 int buffer_size = d_header[HD_BUFFER_SIZE];
181 nbytes = std::min (nbytes, buffer_size - d_bytes_read);
184 int offset = (buffer_current + d_bytes_read) % buffer_size;
185 int n = std::min (nbytes, buffer_size - offset);
186 memcpy (data, d_buffer + offset, n);
196 gr_circular_file::reset_read_pointer ()