diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/odr-padenc.cpp | 335 | ||||
-rw-r--r-- | src/pad_common.cpp | 287 | ||||
-rw-r--r-- | src/pad_common.h | 110 |
4 files changed, 406 insertions, 328 deletions
diff --git a/Makefile.am b/Makefile.am index cdbb542..ef92e64 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,6 +12,8 @@ odr_padenc_LDADD = @MAGICKWAND_LDADD@ odr_padenc_SOURCES = \ src/odr-padenc.cpp \ src/common.h \ + src/pad_common.cpp \ + src/pad_common.h \ src/charset.h \ src/crc.cpp \ src/crc.h diff --git a/src/odr-padenc.cpp b/src/odr-padenc.cpp index 1ae5a73..0766411 100644 --- a/src/odr-padenc.cpp +++ b/src/odr-padenc.cpp @@ -29,18 +29,12 @@ #include "common.h" -#include <cstdio> #include <stdlib.h> -#include <stdint.h> -#include <unistd.h> -#include <cstring> #include <string> #include <sstream> #include <iostream> #include <fstream> #include <algorithm> -#include <vector> -#include <deque> #include <list> #include <sys/types.h> #include <sys/stat.h> @@ -49,7 +43,7 @@ #include <getopt.h> #include "charset.h" -#include "crc.h" +#include "pad_common.h" #if HAVE_MAGICKWAND # include <wand/magick_wand.h> @@ -80,7 +74,6 @@ enum { CHARSET_UTF8 = 15 //!< ISO Latin Alphabet No 2 }; -typedef std::vector<uint8_t> uint8_vector_t; int verbose = 0; struct MSCDG { @@ -219,70 +212,12 @@ void createMscDG(MSCDG* msc, unsigned short int dgtype, int *cindex, unsigned sh unsigned short int lastseg, unsigned short int tid, unsigned char* data, unsigned short int datalen); -struct DATA_GROUP; DATA_GROUP* packMscDG(MSCDG* msc); struct DL_STATE; void prepend_dl_dgs(const DL_STATE& dl_state, uint8_t charset); void writeDLS(int output_fd, const std::string& dls_file, uint8_t charset, bool raw_dls, bool remove_dls); -// PAD related - -struct DATA_GROUP { - uint8_vector_t data; - int apptype_start; - int apptype_cont; - size_t written; - - DATA_GROUP(size_t len, int apptype_start, int apptype_cont) { - this->data.resize(len); - this->apptype_start = apptype_start; - this->apptype_cont = apptype_cont; - written = 0; - } - - void AppendCRC() { - uint16_t crc = 0xFFFF; - crc = odr::crc16(crc, &data[0], data.size()); - crc = ~crc; -#ifdef DEBUG - fprintf(stderr, "crc=%04x ~crc=%04x\n", crc, ~crc); -#endif - - data.push_back((crc & 0xFF00) >> 8); - data.push_back((crc & 0x00FF)); - } - - size_t Available() { - return data.size() - written; - } - - int Write(uint8_t *write_data, size_t len, int *cont_apptype) { - size_t written_now = std::min(len, Available()); - - // fill up remaining bytes with zero padding - memcpy(write_data, &data[written], written_now); - memset(write_data + written_now, 0x00, len - written_now); - - // set app type depending on progress - int apptype = written > 0 ? apptype_cont : apptype_start; - - written += written_now; - - // prevent continuation of a different DG having the same type - if (cont_apptype) - *cont_apptype = Available() > 0 ? apptype_cont : -1; - - return apptype; - } -}; - -static const size_t SHORT_PAD = 6; // F-PAD + 1x CI + 1x 3 bytes data sub-field -static const size_t VARSIZE_PAD_MIN = 8; // F-PAD + 1x CI + end marker + 1x 4 bytes data sub-field -static const size_t VARSIZE_PAD_MAX = 196; // F-PAD + 4x CI + 4x 48 bytes data sub-field -#define ALLOWED_PADLEN "6 (short X-PAD), 8 to 196 (variable size X-PAD)" - - // MOT Slideshow related static int cindex_header = 0; @@ -395,7 +330,6 @@ void MOTHeader::AddExtension(int param_id, const uint8_t* data_field, size_t dat // DLS related -static const size_t FPAD_LEN = 2; static const size_t DLS_SEG_LEN_PREFIX = 2; static const size_t DLS_SEG_LEN_CHAR_MAX = 16; enum { @@ -474,264 +408,9 @@ struct DL_STATE { }; -typedef uint8_vector_t pad_t; static bool dls_toggle = false; static DL_STATE dl_state_prev; - -class PADPacketizer { -private: - static const size_t subfield_lens[]; - - const size_t xpad_size_max; - const bool short_xpad; - const size_t max_cis; - - size_t xpad_size; - uint8_t subfields[4*48]; - size_t subfields_size; - - // PAD w/ CI list - int ci_type[4]; - size_t ci_len_index[4]; - size_t used_cis; - - // PAD w/o CI list - int last_ci_type; - size_t last_ci_size; - - size_t AddCINeededBytes(); - void AddCI(int apptype, int len_index); - - int OptimalSubFieldSizeIndex(size_t available_bytes); - int WriteDGToSubField(DATA_GROUP* dg, size_t len); - - bool AppendDG(DATA_GROUP* dg); - void AppendDGWithCI(DATA_GROUP* dg); - void AppendDGWithoutCI(DATA_GROUP* dg); - - void ResetPAD(); - pad_t* FlushPAD(); -public: - std::deque<DATA_GROUP*> queue; - - PADPacketizer(size_t pad_size); - ~PADPacketizer(); - - pad_t* GetPAD(); - - // will be removed, when pull (instead of push) approach is implemented! - void WriteAllPADs(int output_fd); -}; - - -const size_t PADPacketizer::subfield_lens[] = {4, 6, 8, 12, 16, 24, 32, 48}; - -PADPacketizer::PADPacketizer(size_t pad_size) : - xpad_size_max(pad_size - FPAD_LEN), - short_xpad(pad_size == SHORT_PAD), - max_cis(short_xpad ? 1 : 4), - last_ci_type(-1) -{ - ResetPAD(); -} - -PADPacketizer::~PADPacketizer() { - while (!queue.empty()) { - delete queue.front(); - queue.pop_front(); - } -} - - -pad_t* PADPacketizer::GetPAD() { - bool pad_flushable = false; - - // process DG queue - while (!pad_flushable && !queue.empty()) { - DATA_GROUP* dg = queue.front(); - - // repeatedly append DG - while (!pad_flushable && dg->Available() > 0) - pad_flushable = AppendDG(dg); - - if (dg->Available() == 0) { - delete dg; - queue.pop_front(); - } - } - - // (possibly empty) PAD - return FlushPAD(); -} - -void PADPacketizer::WriteAllPADs(int output_fd) { - for (;;) { - pad_t* pad = GetPAD(); - - // if only F-PAD present, abort - if (pad->back() == FPAD_LEN) { - delete pad; - break; - } - - if (write(output_fd, &(*pad)[0], pad->size()) != (signed) pad->size()) - fprintf(stderr, "ODR-PadEnc Error: Could not write PAD\n"); - - delete pad; - } -} - - -size_t PADPacketizer::AddCINeededBytes() { - // returns the amount of additional bytes needed for the next CI - - // special cases: end marker added/replaced - if (!short_xpad && used_cis == 0) - return 2; - if (!short_xpad && used_cis == (max_cis - 1)) - return 0; - return 1; -} - -void PADPacketizer::AddCI(int apptype, int len_index) { - ci_type[used_cis] = apptype; - ci_len_index[used_cis] = len_index; - - xpad_size += AddCINeededBytes(); - used_cis++; -} - - -int PADPacketizer::OptimalSubFieldSizeIndex(size_t available_bytes) { - /*! Return the index of the optimal sub-field size by stepwise search (regards only Variable Size X-PAD): - * - find the smallest sub-field able to hold (at least) all available bytes - * - find the biggest regarding sub-field we have space for (which definitely exists - otherwise previously the PAD would have been flushed) - * - if the wasted space is at least as big as the smallest possible sub-field, use a sub-field one size smaller - */ - int len_index = 0; - - while ((len_index + 1) < 8 && subfield_lens[len_index] < available_bytes) - len_index++; - while ((len_index - 1) >= 0 && (subfield_lens[len_index] + AddCINeededBytes()) > (xpad_size_max - xpad_size)) - len_index--; - if ((len_index - 1) >= 0 && ((int) subfield_lens[len_index] - (int) available_bytes) >= (int) subfield_lens[0]) - len_index--; - - return len_index; -} - -int PADPacketizer::WriteDGToSubField(DATA_GROUP* dg, size_t len) { - int apptype = dg->Write(&subfields[subfields_size], len, &last_ci_type); - subfields_size += len; - xpad_size += len; - return apptype; -} - - -bool PADPacketizer::AppendDG(DATA_GROUP* dg) { - /*! use X-PAD w/o CIs instead of X-PAD w/ CIs, if we can save some bytes or at least do not waste additional bytes - * - * Omit CI list in case: - * 1. no pending data sub-fields - * 2. last CI type valid - * 3. last CI type matching current (continuity) CI type - * 4a. short X-PAD; OR - * 4ba. size of the last X-PAD being at least as big as the available X-PAD payload in case all CIs are used AND - * 4bb. the amount of available DG bytes being at least as big as the size of the last X-PAD in case all CIs are used - */ - if ( - used_cis == 0 && - last_ci_type != -1 && - last_ci_type == dg->apptype_cont && - (short_xpad || - (last_ci_size >= (xpad_size_max - max_cis) && - dg->Available() >= (last_ci_size - max_cis))) - ) { - AppendDGWithoutCI(dg); - return true; - } else { - AppendDGWithCI(dg); - - // if no further sub-fields could be added, PAD must be flushed - if (used_cis == max_cis || subfield_lens[0] + AddCINeededBytes() > (xpad_size_max - xpad_size)) - return true; - } - return false; -} - - -void PADPacketizer::AppendDGWithCI(DATA_GROUP* dg) { - int len_index = short_xpad ? 0 : OptimalSubFieldSizeIndex(dg->Available()); - size_t len_size = short_xpad ? 3 : subfield_lens[len_index]; - - int apptype = WriteDGToSubField(dg, len_size); - AddCI(apptype, len_index); - -#ifdef DEBUG - fprintf(stderr, "PADPacketizer: added sub-field w/ CI - type: %2d, size: %2zu\n", apptype, len_size); -#endif -} - -void PADPacketizer::AppendDGWithoutCI(DATA_GROUP* dg) { -#ifdef DEBUG - int old_last_ci_type = last_ci_type; -#endif - - WriteDGToSubField(dg, last_ci_size); - -#ifdef DEBUG - fprintf(stderr, "PADPacketizer: added sub-field w/o CI - type: %2d, size: %2zu\n", old_last_ci_type, last_ci_size); -#endif -} - -void PADPacketizer::ResetPAD() { - xpad_size = 0; - subfields_size = 0; - used_cis = 0; -} - -pad_t* PADPacketizer::FlushPAD() { - pad_t* result = new pad_t(xpad_size_max + FPAD_LEN + 1); - pad_t &pad = *result; - - size_t pad_offset = xpad_size_max; - - if (subfields_size > 0) { - if (used_cis > 0) { - // X-PAD: CIs - for (size_t i = 0; i < used_cis; i++) - pad[--pad_offset] = (short_xpad ? 0 : ci_len_index[i]) << 5 | ci_type[i]; - - // X-PAD: end marker (if needed) - if (used_cis < max_cis) - pad[--pad_offset] = 0x00; - } - - // X-PAD: sub-fields (reversed on-the-fly) - for (size_t off = 0; off < subfields_size; off++) - pad[--pad_offset] = subfields[off]; - } else { - // no X-PAD - last_ci_type = -1; - } - - // zero padding - memset(&pad[0], 0x00, pad_offset); - - // F-PAD - pad[xpad_size_max + 0] = subfields_size > 0 ? (short_xpad ? 0x10 : 0x20) : 0x00; - pad[xpad_size_max + 1] = subfields_size > 0 ? (used_cis > 0 ? 0x02 : 0x00) : 0x00; - - // used PAD len - pad[xpad_size_max + FPAD_LEN] = xpad_size + FPAD_LEN; - - last_ci_size = xpad_size; - ResetPAD(); - return result; -} - - static PADPacketizer *pad_packetizer; @@ -778,7 +457,7 @@ void usage(char* name) " Default: /tmp/pad.fifo\n" " -t, --dls=FILENAME Fifo or file to read DLS text from.\n" " -p, --pad=LENGTH Set the pad length.\n" - " Possible values: " ALLOWED_PADLEN "\n" + " Possible values: %s\n" " Default: 58\n" " -c, --charset=ID ID of the character set encoding used for DLS text input.\n" " ID = 0: Complete EBU Latin based repertoire\n" @@ -791,7 +470,8 @@ void usage(char* name) " -R, --raw-slides Do not process slides. Integrity checks and resizing\n" " slides is skipped. Use this if you know what you are doing !\n" " It is useful only when -d is used\n" - " -v, --verbose Print more information to the console\n" + " -v, --verbose Print more information to the console\n", + PADPacketizer::ALLOWED_PADLEN.c_str() ); } @@ -875,10 +555,9 @@ int main(int argc, char *argv[]) } } - if (padlen != SHORT_PAD && (padlen < VARSIZE_PAD_MIN || padlen > VARSIZE_PAD_MAX)) { - fprintf(stderr, "ODR-PadEnc Error: pad length %zu invalid: Possible values: " - ALLOWED_PADLEN "\n", - padlen); + if (padlen != PADPacketizer::SHORT_PAD && (padlen < PADPacketizer::VARSIZE_PAD_MIN || padlen > PADPacketizer::VARSIZE_PAD_MAX)) { + fprintf(stderr, "ODR-PadEnc Error: pad length %zu invalid: Possible values: %s\n", + padlen, PADPacketizer::ALLOWED_PADLEN.c_str()); return 2; } diff --git a/src/pad_common.cpp b/src/pad_common.cpp new file mode 100644 index 0000000..9cbd11f --- /dev/null +++ b/src/pad_common.cpp @@ -0,0 +1,287 @@ +/* + Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/) + + Copyright (C) 2014, 2015 Matthias P. Braendli (http://opendigitalradio.org) + + Copyright (C) 2015, 2016, 2017 Stefan Pöschel (http://opendigitalradio.org) + + This program 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. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ +/*! + \file pad_common.cpp + \brief Common parts related to PAD + + \author Sergio Sagliocco <sergio.sagliocco@csp.it> + \author Matthias P. Braendli <matthias@mpb.li> + \author Stefan Pöschel <odr@basicmaster.de> +*/ + +#include "pad_common.h" + + +// --- DATA_GROUP ----------------------------------------------------------------- +DATA_GROUP::DATA_GROUP(size_t len, int apptype_start, int apptype_cont) { + this->data.resize(len); + this->apptype_start = apptype_start; + this->apptype_cont = apptype_cont; + written = 0; +} + +void DATA_GROUP::AppendCRC() { + uint16_t crc = 0xFFFF; + crc = odr::crc16(crc, &data[0], data.size()); + crc = ~crc; +#ifdef DEBUG + fprintf(stderr, "crc=%04x ~crc=%04x\n", crc, ~crc); +#endif + + data.push_back((crc & 0xFF00) >> 8); + data.push_back((crc & 0x00FF)); +} + +size_t DATA_GROUP::Available() { + return data.size() - written; +} + +int DATA_GROUP::Write(uint8_t *write_data, size_t len, int *cont_apptype) { + size_t written_now = std::min(len, Available()); + + // fill up remaining bytes with zero padding + memcpy(write_data, &data[written], written_now); + memset(write_data + written_now, 0x00, len - written_now); + + // set app type depending on progress + int apptype = written > 0 ? apptype_cont : apptype_start; + + written += written_now; + + // prevent continuation of a different DG having the same type + if (cont_apptype) + *cont_apptype = Available() > 0 ? apptype_cont : -1; + + return apptype; +} + + +// --- PADPacketizer ----------------------------------------------------------------- +const size_t PADPacketizer::SUBFIELD_LENS[] = {4, 6, 8, 12, 16, 24, 32, 48}; +const size_t PADPacketizer::FPAD_LEN = 2; +const size_t PADPacketizer::SHORT_PAD = 6; // F-PAD + 1x CI + 1x 3 bytes data sub-field +const size_t PADPacketizer::VARSIZE_PAD_MIN = 8; // F-PAD + 1x CI + end marker + 1x 4 bytes data sub-field +const size_t PADPacketizer::VARSIZE_PAD_MAX = 196; // F-PAD + 4x CI + 4x 48 bytes data sub-field +const std::string PADPacketizer::ALLOWED_PADLEN = "6 (short X-PAD), 8 to 196 (variable size X-PAD)"; + +PADPacketizer::PADPacketizer(size_t pad_size) : + xpad_size_max(pad_size - FPAD_LEN), + short_xpad(pad_size == SHORT_PAD), + max_cis(short_xpad ? 1 : 4), + last_ci_type(-1) +{ + ResetPAD(); +} + +PADPacketizer::~PADPacketizer() { + while (!queue.empty()) { + delete queue.front(); + queue.pop_front(); + } +} + + +pad_t* PADPacketizer::GetPAD() { + bool pad_flushable = false; + + // process DG queue + while (!pad_flushable && !queue.empty()) { + DATA_GROUP* dg = queue.front(); + + // repeatedly append DG + while (!pad_flushable && dg->Available() > 0) + pad_flushable = AppendDG(dg); + + if (dg->Available() == 0) { + delete dg; + queue.pop_front(); + } + } + + // (possibly empty) PAD + return FlushPAD(); +} + +void PADPacketizer::WriteAllPADs(int output_fd) { + for (;;) { + pad_t* pad = GetPAD(); + + // if only F-PAD present, abort + if (pad->back() == FPAD_LEN) { + delete pad; + break; + } + + if (write(output_fd, &(*pad)[0], pad->size()) != (signed) pad->size()) + fprintf(stderr, "ODR-PadEnc Error: Could not write PAD\n"); + + delete pad; + } +} + + +size_t PADPacketizer::AddCINeededBytes() { + // returns the amount of additional bytes needed for the next CI + + // special cases: end marker added/replaced + if (!short_xpad && used_cis == 0) + return 2; + if (!short_xpad && used_cis == (max_cis - 1)) + return 0; + return 1; +} + +void PADPacketizer::AddCI(int apptype, int len_index) { + ci_type[used_cis] = apptype; + ci_len_index[used_cis] = len_index; + + xpad_size += AddCINeededBytes(); + used_cis++; +} + + +int PADPacketizer::OptimalSubFieldSizeIndex(size_t available_bytes) { + /*! Return the index of the optimal sub-field size by stepwise search (regards only Variable Size X-PAD): + * - find the smallest sub-field able to hold (at least) all available bytes + * - find the biggest regarding sub-field we have space for (which definitely exists - otherwise previously the PAD would have been flushed) + * - if the wasted space is at least as big as the smallest possible sub-field, use a sub-field one size smaller + */ + int len_index = 0; + + while ((len_index + 1) < 8 && SUBFIELD_LENS[len_index] < available_bytes) + len_index++; + while ((len_index - 1) >= 0 && (SUBFIELD_LENS[len_index] + AddCINeededBytes()) > (xpad_size_max - xpad_size)) + len_index--; + if ((len_index - 1) >= 0 && ((int) SUBFIELD_LENS[len_index] - (int) available_bytes) >= (int) SUBFIELD_LENS[0]) + len_index--; + + return len_index; +} + +int PADPacketizer::WriteDGToSubField(DATA_GROUP* dg, size_t len) { + int apptype = dg->Write(&subfields[subfields_size], len, &last_ci_type); + subfields_size += len; + xpad_size += len; + return apptype; +} + + +bool PADPacketizer::AppendDG(DATA_GROUP* dg) { + /*! use X-PAD w/o CIs instead of X-PAD w/ CIs, if we can save some bytes or at least do not waste additional bytes + * + * Omit CI list in case: + * 1. no pending data sub-fields + * 2. last CI type valid + * 3. last CI type matching current (continuity) CI type + * 4a. short X-PAD; OR + * 4ba. size of the last X-PAD being at least as big as the available X-PAD payload in case all CIs are used AND + * 4bb. the amount of available DG bytes being at least as big as the size of the last X-PAD in case all CIs are used + */ + if ( + used_cis == 0 && + last_ci_type != -1 && + last_ci_type == dg->apptype_cont && + (short_xpad || + (last_ci_size >= (xpad_size_max - max_cis) && + dg->Available() >= (last_ci_size - max_cis))) + ) { + AppendDGWithoutCI(dg); + return true; + } else { + AppendDGWithCI(dg); + + // if no further sub-fields could be added, PAD must be flushed + if (used_cis == max_cis || SUBFIELD_LENS[0] + AddCINeededBytes() > (xpad_size_max - xpad_size)) + return true; + } + return false; +} + + +void PADPacketizer::AppendDGWithCI(DATA_GROUP* dg) { + int len_index = short_xpad ? 0 : OptimalSubFieldSizeIndex(dg->Available()); + size_t len_size = short_xpad ? 3 : SUBFIELD_LENS[len_index]; + + int apptype = WriteDGToSubField(dg, len_size); + AddCI(apptype, len_index); + +#ifdef DEBUG + fprintf(stderr, "PADPacketizer: added sub-field w/ CI - type: %2d, size: %2zu\n", apptype, len_size); +#endif +} + +void PADPacketizer::AppendDGWithoutCI(DATA_GROUP* dg) { +#ifdef DEBUG + int old_last_ci_type = last_ci_type; +#endif + + WriteDGToSubField(dg, last_ci_size); + +#ifdef DEBUG + fprintf(stderr, "PADPacketizer: added sub-field w/o CI - type: %2d, size: %2zu\n", old_last_ci_type, last_ci_size); +#endif +} + +void PADPacketizer::ResetPAD() { + xpad_size = 0; + subfields_size = 0; + used_cis = 0; +} + +pad_t* PADPacketizer::FlushPAD() { + pad_t* result = new pad_t(xpad_size_max + FPAD_LEN + 1); + pad_t &pad = *result; + + size_t pad_offset = xpad_size_max; + + if (subfields_size > 0) { + if (used_cis > 0) { + // X-PAD: CIs + for (size_t i = 0; i < used_cis; i++) + pad[--pad_offset] = (short_xpad ? 0 : ci_len_index[i]) << 5 | ci_type[i]; + + // X-PAD: end marker (if needed) + if (used_cis < max_cis) + pad[--pad_offset] = 0x00; + } + + // X-PAD: sub-fields (reversed on-the-fly) + for (size_t off = 0; off < subfields_size; off++) + pad[--pad_offset] = subfields[off]; + } else { + // no X-PAD + last_ci_type = -1; + } + + // zero padding + memset(&pad[0], 0x00, pad_offset); + + // F-PAD + pad[xpad_size_max + 0] = subfields_size > 0 ? (short_xpad ? 0x10 : 0x20) : 0x00; + pad[xpad_size_max + 1] = subfields_size > 0 ? (used_cis > 0 ? 0x02 : 0x00) : 0x00; + + // used PAD len + pad[xpad_size_max + FPAD_LEN] = xpad_size + FPAD_LEN; + + last_ci_size = xpad_size; + ResetPAD(); + return result; +} diff --git a/src/pad_common.h b/src/pad_common.h new file mode 100644 index 0000000..064774c --- /dev/null +++ b/src/pad_common.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 2014 CSP Innovazione nelle ICT s.c.a r.l. (http://rd.csp.it/) + + Copyright (C) 2014, 2015 Matthias P. Braendli (http://opendigitalradio.org) + + Copyright (C) 2015, 2016, 2017 Stefan Pöschel (http://opendigitalradio.org) + + This program 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. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*/ +/*! + \file pad_common.h + \brief Common parts related to PAD + + \author Sergio Sagliocco <sergio.sagliocco@csp.it> + \author Matthias P. Braendli <matthias@mpb.li> + \author Stefan Pöschel <odr@basicmaster.de> +*/ + +#include <cstdio> +#include <vector> +#include <deque> +#include <cstring> +#include <string> +#include <stdint.h> +#include <unistd.h> + +#include "crc.h" + + + +typedef std::vector<uint8_t> uint8_vector_t; +typedef uint8_vector_t pad_t; + + + +// --- DATA_GROUP ----------------------------------------------------------------- +struct DATA_GROUP { + uint8_vector_t data; + int apptype_start; + int apptype_cont; + size_t written; + + DATA_GROUP(size_t len, int apptype_start, int apptype_cont); + void AppendCRC(); + size_t Available(); + int Write(uint8_t *write_data, size_t len, int *cont_apptype); +}; + + +// --- PADPacketizer ----------------------------------------------------------------- +class PADPacketizer { +private: + const size_t xpad_size_max; + const bool short_xpad; + const size_t max_cis; + + size_t xpad_size; + uint8_t subfields[4*48]; + size_t subfields_size; + + // PAD w/ CI list + int ci_type[4]; + size_t ci_len_index[4]; + size_t used_cis; + + // PAD w/o CI list + int last_ci_type; + size_t last_ci_size; + + size_t AddCINeededBytes(); + void AddCI(int apptype, int len_index); + + int OptimalSubFieldSizeIndex(size_t available_bytes); + int WriteDGToSubField(DATA_GROUP* dg, size_t len); + + bool AppendDG(DATA_GROUP* dg); + void AppendDGWithCI(DATA_GROUP* dg); + void AppendDGWithoutCI(DATA_GROUP* dg); + + void ResetPAD(); + pad_t* FlushPAD(); +public: + static const size_t SUBFIELD_LENS[]; + static const size_t FPAD_LEN; + static const size_t SHORT_PAD; + static const size_t VARSIZE_PAD_MIN; + static const size_t VARSIZE_PAD_MAX; + static const std::string ALLOWED_PADLEN; + + std::deque<DATA_GROUP*> queue; + + PADPacketizer(size_t pad_size); + ~PADPacketizer(); + + pad_t* GetPAD(); + + // will be removed, when pull (instead of push) approach is implemented! + void WriteAllPADs(int output_fd); +}; |