summaryrefslogtreecommitdiffstats
path: root/src/ParserConfigfile.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli (think) <matthias@mpb.li>2012-08-23 20:20:30 +0200
committerMatthias P. Braendli (think) <matthias@mpb.li>2012-08-23 20:20:30 +0200
commit3b9073ec178d1ebd8563d94ebbb9b95726e31835 (patch)
tree895ed780d41501089e1464efd20482ab9a0e4c1c /src/ParserConfigfile.cpp
parent37f3f44cc1c0f5cf3a9b3f0ffc32f638b281994e (diff)
downloaddabmux-3b9073ec178d1ebd8563d94ebbb9b95726e31835.tar.gz
dabmux-3b9073ec178d1ebd8563d94ebbb9b95726e31835.tar.bz2
dabmux-3b9073ec178d1ebd8563d94ebbb9b95726e31835.zip
crc-dabmux: configuration file support for ensemble definitionr5
Diffstat (limited to 'src/ParserConfigfile.cpp')
-rw-r--r--src/ParserConfigfile.cpp655
1 files changed, 655 insertions, 0 deletions
diff --git a/src/ParserConfigfile.cpp b/src/ParserConfigfile.cpp
new file mode 100644
index 0000000..24b9f22
--- /dev/null
+++ b/src/ParserConfigfile.cpp
@@ -0,0 +1,655 @@
+/*
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011, 2012 Her Majesty the Queen in Right of Canada (Communications
+ Research Center Canada)
+
+ Written by
+ Matthias P. Braendli, matthias.braendli@mpb.li, 2012
+
+ The command-line parser reads settings from a configuration file
+ whose definition is given in doc/example.config
+ */
+/*
+ This file is part of CRC-DabMux.
+
+ CRC-DabMux 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-DabMux 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-DabMux. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "ParserConfigfile.h"
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/info_parser.hpp>
+#include <exception>
+#include <iostream>
+#include <vector>
+#include <stdint.h>
+#include <string>
+#include <map>
+#include <cstring>
+#include "dabOutput.h"
+#include "dabInput.h"
+#include "utils.h"
+#include "dabInputFile.h"
+#include "dabInputFifo.h"
+#include "dabInputMpegFile.h"
+#include "dabInputMpegFifo.h"
+#include "dabInputDabplusFile.h"
+#include "dabInputDabplusFifo.h"
+#include "dabInputPacketFile.h"
+#include "dabInputEnhancedPacketFile.h"
+#include "dabInputEnhancedFifo.h"
+#include "dabInputUdp.h"
+#include "dabInputBridgeUdp.h"
+#include "dabInputSlip.h"
+#include "dabInputTest.h"
+#include "dabInputPrbs.h"
+#include "dabInputRawFile.h"
+#include "dabInputRawFifo.h"
+#include "dabInputDmbFile.h"
+#include "dabInputDmbUdp.h"
+#include "DabMux.h"
+
+
+#ifdef _WIN32
+# pragma warning ( disable : 4103 )
+# include "Eti.h"
+# pragma warning ( default : 4103 )
+#else
+# include "Eti.h"
+#endif
+
+
+#ifdef _WIN32
+# include <time.h>
+# include <process.h>
+# include <io.h>
+# include <conio.h>
+# include <winsock2.h> // For types...
+typedef u_char uint8_t;
+typedef WORD uint16_t;
+typedef DWORD32 uint32_t;
+
+# ifndef __MINGW32__
+# include "xgetopt.h"
+# endif
+# define read _read
+# define snprintf _snprintf
+# define sleep(a) Sleep((a) * 1000)
+#else
+# include <unistd.h>
+# include <sys/time.h>
+# include <sys/wait.h>
+# include <sys/ioctl.h>
+# include <sys/times.h>
+#endif
+
+using namespace std;
+
+void parse_configfile(string configuration_file,
+ vector<dabOutput*> &outputs,
+ dabEnsemble* ensemble,
+ bool* enableTist,
+ unsigned* FICL,
+ bool* factumAnalyzer,
+ unsigned long* limit
+ )
+{
+ using boost::property_tree::ptree;
+ using boost::property_tree::ptree_error;
+ ptree pt;
+
+ read_info(configuration_file, pt);
+ /******************** READ GENERAL OPTIONS *****************/
+ ptree pt_general = pt.get_child("general");
+
+ /* Dab mode logic */
+ ensemble->mode = pt_general.get("dabmode", 2);
+ if ((ensemble->mode < 1) || (ensemble->mode > 4)) {
+ throw runtime_error("Mode must be between 1-4");
+ }
+ if (ensemble->mode == 4) {
+ ensemble->mode = 0;
+ }
+
+ if (ensemble->mode == 3) {
+ *FICL = 32;
+ }
+ else {
+ *FICL = 24;
+ }
+
+ /* Number of frames to generate */
+ *limit = pt_general.get("nbframes", 0);
+
+ /* Enable TCPLog conditionally */
+ if (pt_general.get("tcplog", 0)) {
+ etiLog.open("createETI", 0, 12222);
+ }
+
+ *factumAnalyzer = pt_general.get("writescca", false);
+
+ *enableTist = pt_general.get("tist", false);
+
+ /******************** READ ENSEMBLE PARAMETERS *************/
+ ptree pt_ensemble = pt.get_child("ensemble");
+
+ /* Ensemble ID */
+ ensemble->id = pt_ensemble.get("id", 0);
+
+ /* Extended Country Code */
+ ensemble->ecc = pt_ensemble.get("ecc", 0);
+
+ string label = pt_ensemble.get("label", "");
+ memset(ensemble->label.text, 0, 16);
+ label.copy(ensemble->label.text, 16);
+ ensemble->label.flag = 0xff00;
+
+ /******************** READ SERVICES PARAMETERS *************/
+
+ map<string, dabService*> allservices;
+
+ /* For each service, we keep a separate SCIdS counter */
+ map<dabService*, int> SCIdS_per_service;
+
+ ptree pt_services = pt.get_child("services");
+ for (ptree::iterator it = pt_services.begin();
+ it != pt_services.end(); it++) {
+ string serviceuid = it->first;
+ ptree pt_service = it->second;
+ dabService* service = new dabService();
+ ensemble->services.push_back(service);
+
+ memset(service->label.text, 0, 16);
+ try {
+ string servicelabel = pt_service.get<string>("label");
+ servicelabel.copy(service->label.text, 16);
+ }
+ catch (ptree_error &e)
+ {
+ sprintf(service->label.text, "CRC-Service%i",
+ (int)ensemble->services.size());
+ }
+ service->label.flag = 0xe01f;
+
+ service->id = pt_service.get("id", DEFAULT_SERVICE_ID + ensemble->services.size());
+ service->pty = pt_service.get("pty", 0);
+ service->language = pt_service.get("language", 0);
+
+ // keep service in map, and check for uniqueness of the UID
+ if (allservices.count(serviceuid) == 0) {
+ allservices[serviceuid] = service;
+
+ // Set the service's SCIds to zero
+ SCIdS_per_service[service] = 0;
+ }
+ else {
+ stringstream ss;
+ ss << "Service with uid " << serviceuid << " not unique!";
+ throw runtime_error(ss.str());
+ }
+ }
+
+
+ /******************** READ SUBCHAN PARAMETERS **************/
+ map<string, dabSubchannel*> allsubchans;
+
+ ptree pt_subchans = pt.get_child("subchannels");
+ for (ptree::iterator it = pt_subchans.begin(); it != pt_subchans.end(); it++) {
+ string subchanuid = it->first;
+ dabSubchannel* subchan = new dabSubchannel();
+
+ ensemble->subchannels.push_back(subchan);
+
+ try {
+ setup_subchannel_from_ptree(subchan, it->second, ensemble, subchanuid);
+ }
+ catch (runtime_error &e) {
+ etiLog.printHeader(TcpLog::ERR,
+ "%s", e.what());
+ throw e;
+ }
+
+
+ // keep subchannels in map, and check for uniqueness of the UID
+ if (allsubchans.count(subchanuid) == 0) {
+ allsubchans[subchanuid] = subchan;
+ }
+ else {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid << " not unique!";
+ throw runtime_error(ss.str());
+ }
+ }
+
+ /******************** READ COMPONENT PARAMETERS ************/
+ map<string, dabComponent*> allcomponents;
+ ptree pt_components = pt.get_child("components");
+ for (ptree::iterator it = pt_components.begin(); it != pt_components.end(); it++) {
+ string componentuid = it->first;
+ ptree pt_comp = it->second;
+
+ dabService* service;
+ try {
+ // Those two uids serve as foreign keys to select the service+subchannel
+ string service_uid = pt_comp.get<string>("service");
+ if (allservices.count(service_uid) != 1) {
+ stringstream ss;
+ ss << "Component with uid " << componentuid << " is refers to unknown service "
+ << service_uid << " !";
+ throw runtime_error(ss.str());
+ }
+ service = allservices[service_uid];
+ }
+ catch (ptree_error &e) {
+ stringstream ss;
+ ss << "Component with uid " << componentuid << " is missing service definition!";
+ throw runtime_error(ss.str());
+ }
+
+ dabSubchannel* subchannel;
+ try {
+ string subchan_uid = pt_comp.get<string>("subchannel");
+ if (allsubchans.count(subchan_uid) != 1) {
+ stringstream ss;
+ ss << "Component with uid " << componentuid << " is refers to unknown subchannel "
+ << subchan_uid << " !";
+ throw runtime_error(ss.str());
+ }
+ subchannel = allsubchans[subchan_uid];
+ }
+ catch (ptree_error &e) {
+ stringstream ss;
+ ss << "Component with uid " << componentuid << " is missing subchannel definition!";
+ throw runtime_error(ss.str());
+ }
+
+ dabComponent* component = new dabComponent();
+
+ memset(component, 0, sizeof(dabComponent));
+ memset(component->label.text, 0, 16);
+ component->label.flag = 0xffff;
+ component->serviceId = service->id;
+ component->subchId = subchannel->id;
+ component->SCIdS = SCIdS_per_service[service]++;
+
+ ensemble->components.push_back(component);
+
+ }
+
+
+ /******************** READ OUTPUT PARAMETERS ***************/
+ map<string, dabOutput*> alloutputs;
+ ptree pt_outputs = pt.get_child("outputs");
+ for (ptree::iterator it = pt_outputs.begin(); it != pt_outputs.end(); it++) {
+ string outputuid = it->first;
+ string uri = pt_outputs.get<string>(outputuid);
+
+ dabOutput* output = new dabOutput();
+
+ outputs.push_back(output);
+
+ memset(output, 0, sizeof(dabOutput));
+ output->outputProto = NULL;
+ output->outputName = NULL;
+ output->data = NULL;
+ output->operations = dabOutputDefaultOperations;
+
+ int proto_pos = uri.find("://");
+ if (proto_pos == std::string::npos) {
+ stringstream ss;
+ ss << "Output with uid " << outputuid << " no protocol defined!";
+ throw runtime_error(ss.str());
+ } else {
+
+ char* uri_c = new char[512];
+ memset(uri_c, 0, 512);
+ uri.copy(uri_c, 511);
+
+ uri_c[proto_pos] = '\0';
+
+ output->outputProto = uri_c;
+ output->outputName = output->outputProto + proto_pos + 3;
+ }
+
+ // keep outputs in map, and check for uniqueness of the uid
+ if (alloutputs.count(outputuid) == 0) {
+ alloutputs[outputuid] = output;
+ }
+ else {
+ stringstream ss;
+ ss << "output with uid " << outputuid << " not unique!";
+ throw runtime_error(ss.str());
+ }
+ }
+
+}
+
+void setup_subchannel_from_ptree(dabSubchannel* subchan,
+ boost::property_tree::ptree &pt,
+ dabEnsemble* ensemble,
+ string subchanuid)
+{
+ using boost::property_tree::ptree;
+ using boost::property_tree::ptree_error;
+
+ string type;
+ /* Read type first */
+ try {
+ type = pt.get<string>("type");
+ }
+ catch (ptree_error &e) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid << " has no type defined!";
+ throw runtime_error(ss.str());
+ }
+
+ string inputfile = "";
+ // fail if no inputfile given unless type is test
+ if (type != "test") {
+ try {
+ inputfile = pt.get<string>("inputfile");
+ }
+ catch (ptree_error &e) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid << " has no type defined!";
+ throw runtime_error(ss.str());
+ }
+ }
+
+ char* inputName = new char[512];
+ memset(inputName, 0, 512);
+ inputfile.copy(inputName, 511);
+
+ subchan->inputName = inputName;
+
+
+ dabProtection* protection = &subchan->protection;
+
+ if (0) {
+#if defined(HAVE_INPUT_FILE) && defined(HAVE_FORMAT_MPEG)
+ } else if (type == "audio") {
+ subchan->inputProto = "file";
+ subchan->type = 0;
+ subchan->bitrate = 0;
+ subchan->operations = dabInputMpegFileOperations;
+#endif // defined(HAVE_INPUT_FILE) && defined(HAVE_FORMAT_MPEG)
+#if defined(HAVE_FORMAT_DABPLUS)
+ } else if (type == "dabplus") {
+ subchan->type = 0;
+ subchan->bitrate = 32;
+
+ char* proto;
+
+ proto = strstr(inputName, "://");
+ if (proto == NULL) {
+ subchan->inputProto = "file";
+ } else {
+ subchan->inputProto = inputName;
+ subchan->inputName = proto + 3;
+ *proto = 0;
+ }
+
+ if (0) {
+#if defined(HAVE_INPUT_FILE)
+ } else if (strcmp(subchan->inputProto, "file") == 0) {
+ subchan->operations = dabInputDabplusFileOperations;
+#endif // defined(HAVE_INPUT_FILE)
+ } else {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": Invalid protocol for DAB+ input (" <<
+ subchan->inputProto << ")" << endl;
+ throw runtime_error(ss.str());
+ }
+#endif // defined(HAVE_FORMAT_DABPLUS)
+ } else if (type == "bridge") {
+ char* proto;
+
+ proto = strstr(inputName, "://");
+ if (proto == NULL) {
+ subchan->inputProto = "udp";
+ } else {
+ subchan->inputProto = inputName;
+ subchan->inputName = proto + 3;
+ *proto = 0;
+ }
+ if (0) {
+#if defined(HAVE_FORMAT_BRIDGE)
+#if defined(HAVE_INPUT_UDP)
+ } else if (strcmp(subchan->inputProto, "udp") == 0) {
+ subchan->operations = dabInputBridgeUdpOperations;
+#endif // defined(HAVE_INPUT_UDP)
+#if defined(HAVE_INPUT_SLIP)
+ } else if (strcmp(subchan->inputProto, "slip") == 0) {
+ subchan->operations = dabInputSlipOperations;
+#endif // defined(HAVE_INPUT_SLIP)
+#endif // defined(HAVE_FORMAT_BRIDGE)
+ }
+ } else if (type == "data") {
+ char* proto;
+
+ proto = strstr(inputName, "://");
+ if (proto == NULL) {
+ subchan->inputProto = "udp";
+ } else {
+ subchan->inputProto = inputName;
+ subchan->inputName = proto + 3;
+ *proto = 0;
+ }
+ if (0) {
+#if defined(HAVE_INPUT_UDP)
+ } else if (strcmp(subchan->inputProto, "udp") == 0) {
+ subchan->operations = dabInputUdpOperations;
+#endif
+#if defined(HAVE_INPUT_PRBS) && defined(HAVE_FORMAT_RAW)
+ } else if (strcmp(subchan->inputProto, "prbs") == 0) {
+ subchan->operations = dabInputPrbsOperations;
+#endif
+#if defined(HAVE_INPUT_FILE) && defined(HAVE_FORMAT_RAW)
+ } else if (strcmp(subchan->inputProto, "file") == 0) {
+ subchan->operations = dabInputRawFileOperations;
+#endif
+ } else if (strcmp(subchan->inputProto, "fifo") == 0) {
+ subchan->operations = dabInputRawFifoOperations;
+ } else {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": Invalid protocol for data input (" <<
+ subchan->inputProto << ")" << endl;
+ throw runtime_error(ss.str());
+ }
+
+ subchan->type = 1;
+ subchan->bitrate = DEFAULT_DATA_BITRATE;
+#if defined(HAVE_INPUT_TEST) && defined(HAVE_FORMAT_RAW)
+ } else if (type == "test") {
+ subchan->inputProto = "test";
+ subchan->type = 1;
+ subchan->bitrate = DEFAULT_DATA_BITRATE;
+ subchan->operations = dabInputTestOperations;
+#endif // defined(HAVE_INPUT_TEST)) && defined(HAVE_FORMAT_RAW)
+#ifdef HAVE_FORMAT_PACKET
+ } else if (type == "packet") {
+ subchan->inputProto = "file";
+ subchan->type = 3;
+ subchan->bitrate = DEFAULT_PACKET_BITRATE;
+#ifdef HAVE_INPUT_FILE
+ subchan->operations = dabInputPacketFileOperations;
+#elif defined(HAVE_INPUT_FIFO)
+ subchan->operations = dabInputFifoOperations;
+#else
+# pragma error("Must defined at least one packet input")
+#endif // defined(HAVE_INPUT_FILE)
+#ifdef HAVE_FORMAT_EPM
+ } else if (type == "enhancedpacked") {
+ subchan->inputProto = "file";
+ subchan->type = 3;
+ subchan->bitrate = DEFAULT_PACKET_BITRATE;
+ subchan->operations = dabInputEnhancedPacketFileOperations;
+#endif // defined(HAVE_FORMAT_EPM)
+#endif // defined(HAVE_FORMAT_PACKET)
+#ifdef HAVE_FORMAT_DMB
+ } else if (type == "dmb") {
+ char* proto;
+
+ proto = strstr(inputName, "://");
+ if (proto == NULL) {
+ subchan->inputProto = "udp";
+ } else {
+ subchan->inputProto = inputName;
+ subchan->inputName = proto + 3;
+ *proto = 0;
+ }
+ if (strcmp(subchan->inputProto, "udp") == 0) {
+ subchan->operations = dabInputDmbUdpOperations;
+ } else if (strcmp(subchan->inputProto, "file") == 0) {
+ subchan->operations = dabInputDmbFileOperations;
+ } else {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ ": Invalid protocol for DMB input (" <<
+ subchan->inputProto << ")" << endl;
+ throw runtime_error(ss.str());
+ }
+
+ subchan->type = 1;
+ subchan->bitrate = DEFAULT_DATA_BITRATE;
+#endif
+ } else {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid << " has unknown type!";
+ throw runtime_error(ss.str());
+ }
+ subchan->operations.init(&subchan->data);
+ subchan->startAddress = 0;
+
+ if (type == "audio") {
+ protection->form = 0;
+ protection->level = 2;
+ protection->shortForm.tableSwitch = 0;
+ protection->shortForm.tableIndex = 0;
+ } else {
+ protection->level = 2;
+ protection->form = 1;
+ protection->longForm.option = 0;
+ }
+
+ /* Get bitrate */
+ try {
+ subchan->bitrate = pt.get<int>("bitrate");
+ if ((subchan->bitrate & 0x7) != 0) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid << ": Bitrate (" << subchan->bitrate << " not a multiple of 8!";
+ throw runtime_error(ss.str());
+ }
+ }
+ catch (ptree_error &e) {}
+
+#if defined(HAVE_INPUT_FIFO) && defined(HAVE_INPUT_FILE)
+ /* Get nonblock */
+ bool nonblock = pt.get("nonblock", false);
+ if (nonblock) {
+ switch (subchan->type) {
+#ifdef HAVE_FORMAT_PACKET
+ case 3:
+ subchan->operations.clean(&subchan->data);
+ if (subchan->operations == dabInputPacketFileOperations) {
+ subchan->operations = dabInputFifoOperations;
+#ifdef HAVE_FORMAT_EPM
+ } else if (subchan->operations == dabInputEnhancedPacketFileOperations) {
+ subchan->operations = dabInputEnhancedFifoOperations;
+#endif // defined(HAVE_FORMAT_EPM)
+ } else {
+ etiLog.printHeader(TcpLog::ERR,
+ "Error, wrong packet subchannel operations!\n");
+ throw runtime_error("Error, wrong packet subchannel operations!\n");
+ }
+ subchan->operations.init(&subchan->data);
+ subchan->inputProto = "fifo";
+ break;
+#endif // defined(HAVE_FORMAT_PACKET)
+#ifdef HAVE_FORMAT_MPEG
+ case 0:
+ subchan->operations.clean(&subchan->data);
+ if (subchan->operations == dabInputMpegFileOperations) {
+ subchan->operations = dabInputMpegFifoOperations;
+ } else if (subchan->operations ==
+ dabInputDabplusFileOperations) {
+ subchan->operations = dabInputDabplusFifoOperations;
+ } else {
+ etiLog.printHeader(TcpLog::ERR,
+ "Error, wrong audio subchannel operations!\n");
+ throw runtime_error(
+ "Error, wrong audio subchannel operations!\n");
+ }
+ subchan->operations.init(&subchan->data);
+ subchan->inputProto = "fifo";
+ break;
+#endif // defined(HAVE_FORMAT_MPEG)
+ default:
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ " non-blocking I/O only available for audio or packet services!";
+ throw runtime_error(ss.str());
+ }
+#endif // defined(HAVE_INPUT_FIFO) && defined(HAVE_INPUT_FILE)
+ }
+
+
+ /* Get id */
+
+ try {
+ subchan->id = pt.get<int>("subchid");
+ }
+ catch (ptree_error &e) {
+ for (int i = 0; i < 64; ++i) { // Find first free subchannel
+ vector<dabSubchannel*>::iterator subchannel = getSubchannel(ensemble->subchannels, i);
+ if (subchannel == ensemble->subchannels.end()) {
+ subchannel = ensemble->subchannels.end() - 1;
+ subchan->id = i;
+ break;
+ }
+ }
+ }
+
+ /* Get protection */
+ try {
+ int level = pt.get<int>("protection");
+
+ if (protection->form == 0) {
+ if ((level < 0) || (level > 4)) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ "protection level must be between "
+ "1 to 5 inclusively (current = " << level << " )";
+ throw runtime_error(ss.str());
+ }
+ }
+ else {
+ if ((level < 0) || (level > 3)) {
+ stringstream ss;
+ ss << "Subchannel with uid " << subchanuid <<
+ "protection level must be between "
+ "1 to 4 inclusively (current = " << level << " )";
+ throw runtime_error(ss.str());
+ }
+ }
+ protection->level = level;
+ }
+ catch (ptree_error &e) {}
+
+}