switch to new MPL based Fraunhofer FOKUS Public License
[senf.git] / Examples / DVBAdapter / ULEdec.cc
index a732b96..fed227e 100644 (file)
@@ -1,91 +1,54 @@
 // $Id$
 //
-// Copyright (C) 2006
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
-//     Stefan Bund <stefan.bund@fokus.fraunhofer.de>
+// 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 <tho@berlios.de>
 
-// Definition of non-inline non-template functions
 
-#include <string>
-#include <iostream>
-#include <iomanip>
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/dvb/dmx.h> 
-
-#include "Scheduler/Scheduler.hh"
-#include "Packets/DefaultBundle/EthernetPacket.hh"
-#include "Packets/MPEGDVBBundle/TransportPacket.hh"
-#include "Packets/MPEGDVBBundle/SNDUPacket.hh"
-#include "Utils/membind.hh"
-#include "Socket/Protocols/DVB/DVBDemuxHandles.hh"
-#include "Packets/ParseInt.hh"
-#include "Packets/Packet.hh"
-#include "Packets/PacketData.hh"
-#include "Packets/ParseInt.hh"
+// Definition of non-inline non-template functions
 
 #include "ULEdec.hh"
 
+#include <cassert>
+#include <linux/dvb/dmx.h>
+#include <boost/format.hpp>
+#include <senf/Packets.hh>
+#include <senf/Utils/hexdump.hh>
+#include <senf/Utils/membind.hh>
+
 #define PID 271
-#define TS_SYNC 0x47
+#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////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 
-template <class Iterator>
-void ULEdec::hexdump(Iterator i, Iterator const & i_end, std::ostream& stream)
-{
-    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 = "";
-            }
-            stream << "  "
-                      << std::hex << std::setw(4) << std::setfill('0')
-                      << offset << ' ';
-            break;
-        case BLOCK_SIZE/2:
-            stream << " ";
-            ascii += ' ';
-            break;
-        }
-        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 << "   ";
-        }
-        stream << "  " << ascii << "\n";
-    }
-    stream << std::dec;
-}
 
-
-ULEdec::ULEdec()
+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));
@@ -95,84 +58,216 @@ ULEdec::ULEdec()
     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));
-    
-    this->receiver_state = 1; // Idle
+
+    this->receiver_state = Idle;
+    this->priv_sndu_type_1 = false;
 }
 
-void ULEdec::handleEvent(senf::FileHandle, senf::Scheduler::EventId event)
+void ULEdec::handleEvent(senf::Scheduler::EventId event)
 {
     senf::TransportPacket ts_packet (
-            senf::TransportPacket::create(188, senf::TransportPacket::noinit));
+            senf::TransportPacket::create(188, senf::noinit));
     dvrHandle.read( ts_packet.data() );
-   
+
     // Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control.
-    if ( (ts_packet->sync_byte() != TS_SYNC) || 
-         (ts_packet->transport_error_indicator() == true) || 
-         (ts_packet->transport_scrmbl_ctrl() != 0)) 
+    if ( (ts_packet->sync_byte() != senf::TransportPacketType::SYNC_BYTE) ||
+         (ts_packet->transport_error_indicator() == true) ||
+         (ts_packet->transport_scrmbl_ctrl() != 0))
     {
         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)
 {
-    unsigned char payload_pointer;
-
-    senf::PacketData &ts_payload (ts_packet.next().data());
-    BOOST_ASSERT( ts_payload.size() == 184 );
-    
-    switch (this->receiver_state) {
-    case 1: { // Idle State
-        // resync on PUSI
-        if (ts_packet->pusi() == 0) 
-            return; // skip packet
-        
-        // Synchronize continuity counter
-        this->priv_tscc = ts_packet->continuity_counter();
+    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;
+                }
+                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 );
+            }
+        }
+        break;
+    }
+    case 1: {
         // a PUSI value of 1 indicates the presence of a Payload Pointer.
-        payload_pointer = ts_payload[0];
-        if (payload_pointer>181) {
-            std::cerr << "invalid payload_pointer\n";
+        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;
         }
-        payload_pointer++;
-        
-        bool dbit = false;
-        senf::Packet::size_type sndu_length;
-        while (payload_pointer < 184) {
-            sndu_length = ts_payload[payload_pointer] << 8 | ts_payload[payload_pointer+1];
-            if (sndu_length & 0x8000) {
-                sndu_length &= 0x7FFF;
-                dbit = true;
+        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;
+                }
             }
-            this->snduPacket = senf::SNDUPacket::create(sndu_length+2);
-            this->snduPacket->d_bit() = dbit;
-            this->snduPacket->length() = sndu_length;
-
+        }
+        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;
-            
-            payload_pointer += 2;
-            
-            
         }
-        
-        
-        
-        // 
-        break;
     }
-    case 2: { // Reassembly State
+
+    } // end pusi-switch
+}
+
+
+ULEdec::iterator ULEdec::readContSNDUPacket(iterator i, iterator const i_end)
+{
+    if (priv_sndu_type_1) {
+        this->snduPacket->type() |= *i++;
+    }
+    return readRawSNDUPacketData(i, i_end);
+}
+
+
+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);
+
+    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() );
 }
 
 
@@ -189,7 +284,7 @@ int main(int argc, char const * argv[])
 }
 
 
-///////////////////////////////cc.e////////////////////////////////////////
+//-/////////////////////////////////////////////////////////////////////////////////////////////////
 #undef prefix_
 
 \f
@@ -199,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: