/*
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Her Majesty the Queen in Right of Canada (Communications Research
Center Canada)
*/
/*
This file is part of CRC-DADMOD.
CRC-DADMOD 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 3 of the
License, or (at your option) any later version.
CRC-DADMOD 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 CRC-DADMOD. If not, see .
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "porting.h"
#include "DabModulator.h"
#include "InputMemory.h"
#include "OutputFile.h"
#include "PcDebug.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_NETINET_IN_H
# include
#endif
#ifdef HAVE_DECL__MM_MALLOC
# include
#else
# define memalign(a, b) malloc(b)
#endif
typedef std::complex complexf;
bool running = true;
void signalHandler(int signalNb)
{
PDEBUG("signalHandler(%i)\n", signalNb);
running = false;
}
void printUsage(char* progName, FILE* out = stderr)
{
fprintf(out, "Usage:\n");
fprintf(out, "\t%s"
" [input [output]]"
" [-a amplitude]"
" [-c clockrate]"
" [-f]"
" [-g gainMode]"
" [-h]"
" [-l]"
" [-m dabMode]"
" [-r samplingRate]"
"\n", progName);
fprintf(out, "Where:\n");
fprintf(out, "input: ETI input filename (default: stdin).\n");
fprintf(out, "output: COFDM output filename (default: stdout).\n");
fprintf(out, "-a: Apply amplitude gain.\n");
fprintf(out, "-c: Set the DAC clock rate.\n");
fprintf(out, "-f: (deprecated) Set fifo input.\n");
fprintf(out, "-g: Set computation gain mode: "
"%u FIX, %u MAX, %u VAR\n", GAIN_FIX, GAIN_MAX, GAIN_VAR);
fprintf(out, "-h: Print this help.\n");
fprintf(out, "-l: Loop file when reach end of file.\n");
fprintf(out, "-m: Set DAB mode: (0: auto, 1-4: force).\n");
fprintf(out, "-r: Set output sampling rate (default: 2048000).\n");
}
void printVersion(FILE *out = stderr)
{
fprintf(out, "Welcome to %s %s, compiled at %s, %s\n\n",
PACKAGE, VERSION, __DATE__, __TIME__);
fprintf(out, "CRC-DABMOD is copyright (C) Her Majesty the Queen in Right of Canada,\n"
" 2009, 2010, 2011, 2012 Communications Research Centre (CRC).\n"
"\n"
" This program is available free of charge and is licensed to you on a\n"
" non-exclusive basis; you may not redistribute it.\n"
"\n"
" This program is provided \"AS IS\" in the hope that it will be useful, but\n"
" WITHOUT ANY WARRANTY with respect to its accurancy or usefulness; witout\n"
" even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n"
" PURPOSE and NONINFRINGEMENT.\n"
"\n"
" In no event shall CRC be LIABLE for any LOSS, DAMAGE or COST that may be\n"
" incurred in connection with the use of this software.\n"
"\n"
"CRC-DABMOD makes use of the following open source packages:\n"
" Kiss FFT v1.2.9 (Revised BSD) - http://kissfft.sourceforge.net/\n"
);
}
int main(int argc, char* argv[])
{
int ret = 0;
bool loop = false;
char* inputName;
char* outputName;
FILE* inputFile = NULL;
uint32_t sync = 0;
uint32_t nbFrames = 0;
uint32_t frame = 0;
uint16_t frameSize = 0;
size_t outputRate = 2048000;
size_t clockRate = 0;
unsigned dabMode = 0;
float amplitude = 1.0f;
GainMode gainMode = GAIN_VAR;
Buffer data;
Flowgraph* flowgraph = NULL;
DabModulator* modulator = NULL;
InputMemory* input = NULL;
OutputFile* output = NULL;
signal(SIGINT, signalHandler);
while (true) {
int c = getopt(argc, argv, "a:c:fg:hlm:r:V");
if (c == -1) {
break;
}
switch (c) {
case 'a':
amplitude = strtof(optarg, NULL);
break;
case 'c':
clockRate = strtol(optarg, NULL, 0);
break;
case 'f':
fprintf(stderr, "Option -f deprecated!\n");
break;
case 'g':
gainMode = (GainMode)strtol(optarg, NULL, 0);
break;
case 'l':
loop = true;
break;
case 'm':
dabMode = strtol(optarg, NULL, 0);
break;
case 'r':
outputRate = strtol(optarg, NULL, 0);
break;
case 'V':
printVersion();
goto END_MAIN;
break;
case '?':
case 'h':
printUsage(argv[0]);
goto END_MAIN;
break;
default:
fprintf(stderr, "Option '%c' not coded yet!\n", c);
ret = -1;
goto END_MAIN;
}
}
// Setting ETI input filename
if (optind < argc) {
inputName = argv[optind++];
} else {
inputName = (char*)"/dev/stdin";
}
// Setting COFDM output filename
if (optind < argc) {
outputName = argv[optind++];
} else {
outputName = (char*)"/dev/stdout";
}
// Checking unused arguments
if (optind != argc) {
fprintf(stderr, "Invalid arguments:");
while (optind != argc) {
fprintf(stderr, " %s", argv[optind++]);
}
fprintf(stderr, "\n");
printUsage(argv[0]);
ret = -1;
goto END_MAIN;
}
// Print settings
fprintf(stderr, "Input\n");
fprintf(stderr, " Name: %s\n", inputName);
fprintf(stderr, "Output\n");
fprintf(stderr, " Name: %s\n", outputName);
fprintf(stderr, " Sampling rate: ");
if (outputRate > 1000) {
if (outputRate > 1000000) {
fprintf(stderr, "%.3g mHz\n", outputRate / 1000000.0f);
} else {
fprintf(stderr, "%.3g kHz\n", outputRate / 1000.0f);
}
} else {
fprintf(stderr, "%zu Hz\n", outputRate);
}
// Opening ETI input file
inputFile = fopen(inputName, "r");
if (inputFile == NULL) {
fprintf(stderr, "Unable to open input file!\n");
perror(inputName);
ret = -1;
goto END_MAIN;
}
// Opening COFDM output file
if (outputName != NULL) {
output = new OutputFile(outputName);
}
flowgraph = new Flowgraph();
data.setLength(6144);
input = new InputMemory(&data);
modulator = new DabModulator(outputRate, clockRate, dabMode, gainMode, amplitude);
flowgraph->connect(input, modulator);
flowgraph->connect(modulator, output);
try {
while (running) {
enum EtiStreamType {
ETI_STREAM_TYPE_NONE = 0,
ETI_STREAM_TYPE_RAW,
ETI_STREAM_TYPE_STREAMED,
ETI_STREAM_TYPE_FRAMED,
};
EtiStreamType streamType = ETI_STREAM_TYPE_NONE;
struct stat inputFileStat;
fstat(fileno(inputFile), &inputFileStat);
size_t inputFileLength = inputFileStat.st_size;
if (fread(&sync, sizeof(sync), 1, inputFile) != 1) {
fprintf(stderr, "Unable to read sync in input file!\n");
perror(inputName);
ret = -1;
goto END_MAIN;
}
if ((sync == 0x49c5f8ff) || (sync == 0xb63a07ff)) {
streamType = ETI_STREAM_TYPE_RAW;
if (inputFileLength > 0) {
nbFrames = inputFileLength / 6144;
} else {
nbFrames = (uint32_t)-1;
}
if (fseek(inputFile, -sizeof(sync), SEEK_CUR) != 0) {
if (fread(data.getData(), 6144 - sizeof(sync), 1, inputFile)
!= 1) {
fprintf(stderr, "Unable to seek in input file!\n");
ret = -1;
goto END_MAIN;
}
}
goto START;
}
nbFrames = sync;
if (fread(&frameSize, sizeof(frameSize), 1, inputFile) != 1) {
fprintf(stderr, "Unable to read frame size in input file!\n");
perror(inputName);
ret = -1;
goto END_MAIN;
}
sync >>= 16;
sync &= 0xffff;
sync |= ((uint32_t)frameSize) << 16;
if ((sync == 0x49c5f8ff) || (sync == 0xb63a07ff)) {
streamType = ETI_STREAM_TYPE_STREAMED;
frameSize = nbFrames & 0xffff;
if (inputFileLength > 0) {
nbFrames = inputFileLength / (frameSize + 2);
} else {
nbFrames = (uint32_t)-1;
}
if (fseek(inputFile, -6, SEEK_CUR) != 0) {
if (fread(data.getData(), frameSize - 4, 1, inputFile)
!= 1) {
fprintf(stderr, "Unable to seek in input file!\n");
ret = -1;
goto END_MAIN;
}
}
goto START;
}
if (fread(&sync, sizeof(sync), 1, inputFile) != 1) {
fprintf(stderr, "Unable to read nb frame in input file!\n");
perror(inputName);
ret = -1;
goto END_MAIN;
}
if ((sync == 0x49c5f8ff) || (sync == 0xb63a07ff)) {
streamType = ETI_STREAM_TYPE_FRAMED;
if (fseek(inputFile, -6, SEEK_CUR) != 0) {
if (fread(data.getData(), frameSize - 4, 1, inputFile)
!= 1) {
fprintf(stderr, "Unable to seek in input file!\n");
ret = -1;
goto END_MAIN;
}
}
goto START;
}
for (size_t i = 10; i < 6144 + 10; ++i) {
sync >>= 8;
sync &= 0xffffff;
if (fread((uint8_t*)&sync + 3, 1, 1, inputFile) != 1) {
fprintf(stderr, "Unable to read in input file!\n");
ret = 1;
goto END_MAIN;
}
if ((sync == 0x49c5f8ff) || (sync == 0xb63a07ff)) {
streamType = ETI_STREAM_TYPE_RAW;
if (inputFileLength > 0) {
nbFrames = (inputFileLength - i) / 6144;
} else {
nbFrames = (uint32_t)-1;
}
if (fseek(inputFile, -sizeof(sync), SEEK_CUR) != 0) {
if (fread(data.getData(), 6144 - sizeof(sync), 1, inputFile)
!= 1) {
fprintf(stderr, "Unable to seek in input file!\n");
ret = -1;
goto END_MAIN;
}
}
goto START;
}
}
fprintf(stderr, "Bad input file format!\n");
ret = -1;
goto END_MAIN;
START:
fprintf(stderr, "Input file format: ");
switch (streamType) {
case ETI_STREAM_TYPE_RAW:
fprintf(stderr, "raw");
break;
case ETI_STREAM_TYPE_STREAMED:
fprintf(stderr, "streamed");
break;
case ETI_STREAM_TYPE_FRAMED:
fprintf(stderr, "framed");
break;
default:
fprintf(stderr, "unknown\n");
ret = -1;
goto END_MAIN;
}
fprintf(stderr, "\n");
fprintf(stderr, "Input file length: %zu\n", inputFileLength);
fprintf(stderr, "Input file nb frames: %u\n", nbFrames);
for (frame = 0; frame < nbFrames; ++frame) {
if (!running) {
break;
}
PDEBUG("*****************************************\n");
PDEBUG("* Reading frame %u\n", frame);
PDEBUG("*****************************************\n");
if (streamType == ETI_STREAM_TYPE_RAW) {
frameSize = 6144;
} else {
if (fread(&frameSize, sizeof(frameSize), 1, inputFile)
!= 1) {
PDEBUG("End of file!\n");
goto END_MAIN;
}
}
PDEBUG("Frame size: %i\n", frameSize);
if (fread(data.getData(), frameSize, 1, inputFile) != 1) {
fprintf(stderr,
"Unable to read %i data bytes in input file!\n",
frameSize);
perror(inputName);
ret = -1;
goto END_MAIN;
}
memset(&((uint8_t*)data.getData())[frameSize], 0x55, 6144 - frameSize);
////////////////////////////////////////////////////////////////
// Proccessing data
////////////////////////////////////////////////////////////////
flowgraph->run();
}
fprintf(stderr, "End of file reached.\n");
if (!loop) {
running = false;
} else {
fprintf(stderr, "Rewinding file.\n");
rewind(inputFile);
}
}
} catch (std::exception& e) {
fprintf(stderr, "EXCEPTION: %s\n", e.what());
ret = -1;
goto END_MAIN;
}
END_MAIN:
////////////////////////////////////////////////////////////////////////
// Cleaning things
////////////////////////////////////////////////////////////////////////
fprintf(stderr, "\n\n");
fprintf(stderr, "%u DAB frames encoded\n", frame);
fprintf(stderr, "%f seconds encoded\n", (float)frame * 0.024f);
fprintf(stderr, "\nCleaning flowgraph...\n");
delete flowgraph;
// Cif
fprintf(stderr, "\nCleaning buffers...\n");
fprintf(stderr, "\nClosing input file...\n");
if (inputFile != NULL) {
fclose(inputFile);
}
return ret;
}