X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Examples%2FDVBAdapter%2FULEdec.cc;h=fed227e60956860102fe7e78f7010b4eba01bbbf;hb=6df7613bc4c5a8c27a6af11450d2cb8fbb6ea3a6;hp=2d2fd34481534432b9c345ddafe4a86c827fb1bb;hpb=2c4c9deecc7491fbfc916aeb41074dcb76e8a2c2;p=senf.git diff --git a/Examples/DVBAdapter/ULEdec.cc b/Examples/DVBAdapter/ULEdec.cc index 2d2fd34..fed227e 100644 --- a/Examples/DVBAdapter/ULEdec.cc +++ b/Examples/DVBAdapter/ULEdec.cc @@ -1,127 +1,280 @@ // $Id$ // -// Copyright (C) 2006 -// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) -// Kompetenzzentrum fuer Satelitenkommunikation (SatCom) -// Stefan Bund +// Copyright (C) 2007 +// Fraunhofer Institute for Open Communication Systems (FOKUS) // -// 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 2 of the License, or -// (at your option) any later version. +// The contents of this file are subject to the Fraunhofer FOKUS Public License +// Version 1.0 (the "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// http://senf.berlios.de/license.html // -// 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. +// The Fraunhofer FOKUS Public License Version 1.0 is based on, +// but modifies the Mozilla Public License Version 1.1. +// See the full license text for the amendments. // -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the -// Free Software Foundation, Inc., -// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// Software distributed under the License is distributed on an "AS IS" basis, +// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +// for the specific language governing rights and limitations under the License. +// +// The Original Code is Fraunhofer FOKUS code. +// +// The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. +// (registered association), Hansastraße 27 c, 80686 Munich, Germany. +// All Rights Reserved. +// +// Contributor(s): +// Thorsten Horstmann + // Definition of non-inline non-template functions -#include -#include -#include -#include -#include -#include - -#include "Scheduler/Scheduler.hh" -#include "Packets/DefaultBundle/EthernetPacket.hh" -#include "Packets/MPEGDVBBundle/TransportPacket.hh" -#include "Utils/membind.hh" -#include "Socket/Protocols/DVB/DVBDemuxHandles.hh" -#include "Packets/ParseInt.hh" -#include "Packets/Packet.hh" -#include "Packets/PacketData.hh" +#include "ULEdec.hh" + +#include +#include +#include +#include +#include +#include #define PID 271 +#define TRANSPORT_PACKET_SIZE 188 +// max. payload_pointer = ts packet payload size ( = ts packet size - ts header - payload_pointer) +// - 2 bytes min. sndu header +#define MAX_PAYLOAD_POINTER ( TRANSPORT_PACKET_SIZE - 4 - 1 - 2 ) #define prefix_ -///////////////////////////////cc.p//////////////////////////////////////// +//-///////////////////////////////////////////////////////////////////////////////////////////////// + + +ULEdec::ULEdec(unsigned short adapter, unsigned short device) + : demuxHandle( adapter, device ), dvrHandle( adapter, device ) +{ + struct dmx_pes_filter_params pes_filter; + memset(&pes_filter, 0, sizeof (struct dmx_pes_filter_params)); + pes_filter.pid = PID; + pes_filter.input = DMX_IN_FRONTEND; + pes_filter.output = DMX_OUT_TS_TAP; + pes_filter.pes_type = DMX_PES_OTHER; + pes_filter.flags = DMX_IMMEDIATE_START; + demuxHandle.protocol().setPESFilter( &pes_filter ); + + senf::Scheduler::instance().add( + dvrHandle, senf::membind(&ULEdec::handleEvent, this)); -namespace { + this->receiver_state = Idle; + this->priv_sndu_type_1 = false; +} - static const unsigned BLOCK_SIZE = 16; +void ULEdec::handleEvent(senf::Scheduler::EventId event) +{ + senf::TransportPacket ts_packet ( + senf::TransportPacket::create(188, senf::noinit)); + dvrHandle.read( ts_packet.data() ); - template - void hexdump(Iterator i, Iterator const & i_end, std::ostream& stream) + // Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control. + if ( (ts_packet->sync_byte() != senf::TransportPacketType::SYNC_BYTE) || + (ts_packet->transport_error_indicator() == true) || + (ts_packet->transport_scrmbl_ctrl() != 0)) { - unsigned offset (0); - std::string ascii; - for (; i != i_end; ++i, ++offset) { - switch (offset % BLOCK_SIZE) { - case 0: - if (!ascii.empty()) { - stream << " " << ascii << "\n"; - ascii = ""; + std::cerr << "invalid ts packet\n"; + // drop partly decoded SNDU, reset state, resync on PUSI. + return; + } + + handleTSPacket(ts_packet); +} + +void ULEdec::handleTSPacket(senf::TransportPacket ts_packet) +{ + senf::PacketData & payloadData (ts_packet.next().data()); + iterator payload_iter = payloadData.begin(); + iterator payload_end = payloadData.end(); + + std::cout << "New TS Packet:\n" + << "----------------------------------------------------------------------------\n"; + senf::hexdump(payload_iter, payload_end, std::cout); + std::cout << "----------------------------------------------------------------------------\n"; + + // Synchronize continuity counter + this->priv_tscc = ts_packet->continuity_counter(); + + switch (ts_packet->pusi()) { + case 0: { + switch (this->receiver_state) { + case Idle: + return; + case Reassembly: + payload_iter = readContSNDUPacket( payload_iter, payload_end ); + if (isSDNUPacketComplete()) { + this->receiver_state = Idle; + try { + handleSNDUPacket(); + } catch (ULEdecException const & ex) { + std::cerr << ex.what() << "\n"; + return; } - stream << " " - << std::hex << std::setw(4) << std::setfill('0') - << offset << ' '; - break; - case BLOCK_SIZE/2: - stream << " "; - ascii += ' '; - break; + switch (std::distance( payload_iter, payload_end )) + case 0: + case 1: + return; + default: + if ( (*payload_iter++ << 8 | *payload_iter++) != ULE_END_INDICATOR ) + std::cerr << "delimiting error\n"; + } else { + assert( std::distance( payload_iter, payload_end ) == 0 ); } - stream << ' ' << std::hex << std::setw(2) << std::setfill('0') - << unsigned(*i); - ascii += (*i >= ' ' && *i < 126) ? *i : '.'; } - if (!ascii.empty()) { - for (; (offset % BLOCK_SIZE) != 0; ++offset) { - if ((offset % BLOCK_SIZE) == BLOCK_SIZE/2) - stream << " "; - stream << " "; + break; + } + case 1: { + // a PUSI value of 1 indicates the presence of a Payload Pointer. + unsigned char payload_pointer = *payload_iter++; + if (payload_pointer > MAX_PAYLOAD_POINTER) { + std::cerr << str( boost::format( + "invalid payload_pointer (%d)\n") % unsigned(payload_pointer) ) ; + this->receiver_state = Idle; + return; + } + switch (this->receiver_state) { + case Idle: + std::advance(payload_iter, payload_pointer); + break; + case Reassembly: + // Reassembly Payload Pointer Checking + if (snduPacketBytesLeft() != payload_pointer) { + // delimiting error + std::cerr << str( boost::format( + "delimiting error: bytes left in SNDU packet != payload_pointer (" + "(%d != %d)\n") % snduPacketBytesLeft() % payload_pointer ); + std::advance(payload_iter, payload_pointer); + } else { + payload_iter = readContSNDUPacket( payload_iter, payload_end ); + assert( isSDNUPacketComplete() ); + try { + handleSNDUPacket(); + } catch (ULEdecException const & ex) { + std::cerr << ex.what() << "\n"; + this->receiver_state = Idle; + return; + } } - stream << " " << ascii << "\n"; } - stream << std::dec; + this->receiver_state = Idle; + try { + do { + payload_iter = readNewSNDUPacket( payload_iter, payload_end ); + if (! isSDNUPacketComplete()) { + assert( std::distance( payload_iter, payload_end ) == 0 ); + this->receiver_state = Reassembly; + break; + } + handleSNDUPacket(); + } while (std::distance(payload_iter, payload_end) < 2 ); + } + catch (ULEdecException const & ex) { + std::cerr << ex.what() << "\n"; + return; + } } + + } // end pusi-switch } -class MySniffer +ULEdec::iterator ULEdec::readContSNDUPacket(iterator i, iterator const i_end) { - senf::DVBDemuxPESHandle demuxHandle; - senf::DVBDvrHandle dvrHandle; + if (priv_sndu_type_1) { + this->snduPacket->type() |= *i++; + } + return readRawSNDUPacketData(i, i_end); +} -public: - MySniffer() - { - struct dmx_pes_filter_params pes_filter; - memset(&pes_filter, 0, sizeof (struct dmx_pes_filter_params)); - pes_filter.pid = PID; - pes_filter.input = DMX_IN_FRONTEND; - pes_filter.output = DMX_OUT_TS_TAP; - pes_filter.pes_type = DMX_PES_OTHER; - pes_filter.flags = DMX_IMMEDIATE_START; - - demuxHandle.protocol().setPESFilter( &pes_filter ); - - senf::Scheduler::instance().add( - dvrHandle, senf::membind(&MySniffer::dumpSection, this)); + +ULEdec::iterator ULEdec::readNewSNDUPacket(iterator i, iterator const i_end) +{ + bool dbit = false; + senf::Packet::size_type sndu_length = *i++ << 8 | *i++; + if (sndu_length & 0x8000) { + sndu_length &= 0x7FFF; + dbit = true; } + if (sndu_length < 5 || sndu_length == 0xffff) { + throw ULEdecException( str( boost::format( + "SNDU length error. length=%d") % sndu_length) ); + } + this->snduPacket = senf::SNDUPacket::create(sndu_length+4); -private: - void dumpSection(senf::FileHandle /* ignored */, senf::Scheduler::EventId event) - { - std::string data (dvrHandle.read()); - senf::TransportPacket packet (senf::TransportPacket::create(data)); - packet.dump(std::cout); - senf::PacketData & packetData (packet.last().data()); - hexdump(packetData.begin(), packetData.end(), std::cout); + if (dbit) + this->snduPacket->withoutDestination(); + // else not needed since default on newly created packet is withDestination() + + this->snduPacket->length() = sndu_length; + this->snduPacketData_iter = boost::next(this->snduPacket.data().begin(), 2); + this->priv_sndu_type_1 = false; + + switch (std::distance(i, i_end)) { + case 1: + this->priv_sndu_type_1 = true; + this->snduPacket->type() = *i++ << 8; + this->snduPacketData_iter++; + case 0: + break; + + default: + this->snduPacket->type() = *i++ << 8 | *i++; + std::advance(this->snduPacketData_iter, 2); + i = readRawSNDUPacketData(i, i_end); } -}; + + return i; +} + + +ULEdec::iterator ULEdec::readRawSNDUPacketData(iterator i, iterator i_end) +{ + unsigned char how_much = std::min( + snduPacketBytesLeft(), std::distance(i, i_end) ); + copy_n(i, how_much, this->snduPacketData_iter); + std::advance(i, how_much); + std::advance(this->snduPacketData_iter, how_much); + return i; +} + + +void ULEdec::handleSNDUPacket() +{ + this->snduPacket.dump(std::cout); + std::cout << "----------------------------------------------------------------------------\n\n"; + if (this->snduPacket->crc() != this->snduPacket->calcCrc()) { + throw ULEdecException( str( boost::format( + "CRC Error. received crc:%d calculated crc:%d") + % this->snduPacket->crc() % this->snduPacket->calcCrc() ) ); + } +// senf::Packet nextPacket = this->snduPacket.next(); +// senf::hexdump( +// nextPacket.data().begin(), +// nextPacket.data().end(), +// std::cout); + +} + + +inline bool ULEdec::isSDNUPacketComplete() +{ + return this->snduPacketData_iter == this->snduPacket.data().end(); +} + +inline ULEdec::iterator::difference_type ULEdec::snduPacketBytesLeft() +{ + return std::distance( this->snduPacketData_iter, this->snduPacket.data().end() ); +} + int main(int argc, char const * argv[]) { try { - MySniffer sniffer; + ULEdec decoder; senf::Scheduler::instance().process(); } catch (std::exception const & ex) { @@ -131,7 +284,7 @@ int main(int argc, char const * argv[]) } -///////////////////////////////cc.e//////////////////////////////////////// +//-///////////////////////////////////////////////////////////////////////////////////////////////// #undef prefix_ @@ -141,6 +294,6 @@ int main(int argc, char const * argv[]) // c-file-style: "senf" // indent-tabs-mode: nil // ispell-local-dictionary: "american" -// compile-command: "scons -u test" +// compile-command: "scons -U" // comment-column: 40 // End: