implemented nextPacketType/Range for SNDU (yeah!)
[senf.git] / Examples / DVBAdapter / ULEdec.cc
index b41c3a8..9eccad3 100644 (file)
 
 // 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/DatagramSection.hh"
-#include "Utils/membind.hh"
-#include "Socket/DVBDemuxHandles.hh"
-#include "Packets/ParseInt.hh"
-#include "Packets/Packet.hh"
+#include "ULEdec.hh"
+
 #include "Packets/PacketData.hh"
+#include "Utils/hexdump.hh"
+#include "Utils/membind.hh"
 
 #define PID 271
+#define TS_SYNC 0x47
 
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-namespace {
 
-    static const unsigned BLOCK_SIZE = 16;
+ULEdec::ULEdec()
+{
+    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));
+    
+    this->receiver_state = Idle;
+    this->priv_sndu_type_1 = false;
+}
 
-    template <class Iterator>
-    void hexdump(Iterator i, Iterator const & i_end, std::ostream& stream)
+void ULEdec::handleEvent(senf::FileHandle, senf::Scheduler::EventId event)
+{
+    senf::TransportPacket ts_packet (
+            senf::TransportPacket::create(188, senf::TransportPacket::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)) 
     {
-        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 1\n";
+            } else {
+                BOOST_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 > 181) {
+            std::cerr << "invalid payload_pointer\n";
+            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 << "delimiting error 2\n";
+                std::advance(payload_iter, payload_pointer);
+            } else {
+                payload_iter = readContSNDUPacket( payload_iter, payload_end );
+                BOOST_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()) {
+                    BOOST_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 );
+
+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("SNDU length error");
+     }
+    this->snduPacket = senf::SNDUPacket::create(sndu_length+4);
+    this->snduPacket->d_bit() = dbit;
+    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;
         
-        senf::Scheduler::instance().add(
-            dvrHandle, senf::membind(&MySniffer::dumpSection, this));
+    default: 
+        this->snduPacket->type() = *i++ << 8 | *i++;
+        std::advance(this->snduPacketData_iter, 2);
+        i = readRawSNDUPacketData(i, i_end);
     }
+    
+    return i;
+}
 
-private:
-    void dumpSection(senf::FileHandle /* ignored */, senf::Scheduler::EventId event)
-    {
-        std::string data (dvrHandle.read());
-        std::cout << data.length() << "\n";
-        //senf::DatagramSection section (senf::DatagramSection::create(data));
-        //section.dump(std::cout);
-        //senf::PacketData & datagramData (section.last().data());
-        //hexdump(datagramData.begin(), datagramData.end(), std::cout);
+
+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("CRC Error");
     }
-};
+//    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) {
@@ -135,7 +264,7 @@ int main(int argc, char const * argv[])
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 
-\f
 // Local Variables:
 // mode: c++
 // fill-column: 100