diff options
Diffstat (limited to 'src/ParserConfigfile.cpp')
-rw-r--r-- | src/ParserConfigfile.cpp | 655 |
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) {} + +} |