changed font for dot graphs to Verdana
[senf.git] / Examples / DVBAdapter / ULEdec.cc
1 // $Id$
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
6 //     Stefan Bund <stefan.bund@fokus.fraunhofer.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 // Definition of non-inline non-template functions
24
25 #include <string>
26 #include <iostream>
27 #include <iomanip>
28 #include <algorithm>
29 #include <sys/ioctl.h>
30 #include <linux/sockios.h>
31 #include <linux/dvb/dmx.h> 
32
33 #include "Scheduler/Scheduler.hh"
34 #include "Packets/DefaultBundle/EthernetPacket.hh"
35 #include "Packets/MPEGDVBBundle/TransportPacket.hh"
36 #include "Packets/MPEGDVBBundle/SNDUPacket.hh"
37 #include "Utils/membind.hh"
38 #include "Socket/Protocols/DVB/DVBDemuxHandles.hh"
39 #include "Packets/ParseInt.hh"
40 #include "Packets/Packet.hh"
41 #include "Packets/PacketData.hh"
42 #include "Packets/ParseInt.hh"
43
44 #include "ULEdec.hh"
45
46 #define PID 271
47 #define TS_SYNC 0x47
48
49 #define prefix_
50 ///////////////////////////////cc.p////////////////////////////////////////
51
52 template <class Iterator>
53 void ULEdec::hexdump(Iterator i, Iterator const & i_end, std::ostream& stream)
54 {
55     unsigned offset (0);
56     std::string ascii;
57     for (; i != i_end; ++i, ++offset) {
58         switch (offset % BLOCK_SIZE) {
59         case 0:
60             if (!ascii.empty()) {
61                 stream << "  " << ascii << "\n";
62                 ascii = "";
63             }
64             stream << "  "
65                       << std::hex << std::setw(4) << std::setfill('0')
66                       << offset << ' ';
67             break;
68         case BLOCK_SIZE/2:
69             stream << " ";
70             ascii += ' ';
71             break;
72         }
73         stream << ' ' << std::hex << std::setw(2) << std::setfill('0')
74                   << unsigned(*i);
75         ascii += (*i >= ' ' && *i < 126) ? *i : '.';
76     }
77     if (!ascii.empty()) {
78         for (; (offset % BLOCK_SIZE) != 0; ++offset) {
79             if ((offset % BLOCK_SIZE) == BLOCK_SIZE/2)
80                 stream << " ";
81             stream << "   ";
82         }
83         stream << "  " << ascii << "\n";
84     }
85     stream << std::dec;
86 }
87
88
89 ULEdec::ULEdec()
90 {
91     struct dmx_pes_filter_params pes_filter;
92     memset(&pes_filter, 0, sizeof (struct dmx_pes_filter_params));
93     pes_filter.pid = PID;
94     pes_filter.input  = DMX_IN_FRONTEND;
95     pes_filter.output = DMX_OUT_TS_TAP;
96     pes_filter.pes_type = DMX_PES_OTHER;
97     pes_filter.flags = DMX_IMMEDIATE_START;
98     demuxHandle.protocol().setPESFilter( &pes_filter );
99     
100     senf::Scheduler::instance().add(
101         dvrHandle, senf::membind(&ULEdec::handleEvent, this));
102     
103     this->receiver_state = Idle;
104     this->priv_sndu_type_1 = false;
105 }
106
107 void ULEdec::handleEvent(senf::FileHandle, senf::Scheduler::EventId event)
108 {
109     senf::TransportPacket ts_packet (
110             senf::TransportPacket::create(188, senf::TransportPacket::noinit));
111     dvrHandle.read( ts_packet.data() );
112    
113     // Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control.
114     if ( (ts_packet->sync_byte() != TS_SYNC) || 
115          (ts_packet->transport_error_indicator() == true) || 
116          (ts_packet->transport_scrmbl_ctrl() != 0)) 
117     {
118         std::cerr << "invalid ts packet\n";
119         // drop partly decoded SNDU, reset state, resync on PUSI.
120         return;
121     }
122     
123     handleTSPacket(ts_packet);
124 }
125     
126 void ULEdec::handleTSPacket(senf::TransportPacket ts_packet)
127 {
128     senf::PacketData & payloadData (ts_packet.next().data());
129     iterator payload_start = payloadData.begin();
130     iterator payload_end = payloadData.end();
131     
132     hexdump(payload_start, payload_end, std::cout);
133     
134     // Synchronize continuity counter
135     this->priv_tscc = ts_packet->continuity_counter();
136     
137     if (ts_packet->pusi() == 0) {
138         switch (this->receiver_state) {
139         case Idle:
140             return;
141         case Reassembly:
142             readContSNDUPacket( payload_start, payload_end );
143         }
144     } else {
145         // a PUSI value of 1 indicates the presence of a Payload Pointer.
146         unsigned char payload_pointer = *payload_start++;
147         if (payload_pointer > 181) {
148             std::cerr << "invalid payload_pointer\n";
149             return;
150         }
151         switch (this->receiver_state) {
152         case Idle:
153             payload_start += payload_pointer;
154             readNewSNDUPacket( payload_start, payload_end );
155             this->snduPacket.dump(std::cout);
156             break;
157         case Reassembly:
158             // Reassembly Payload Pointer Checking
159             unsigned char sdnu_bytes_left = std::distance(
160                     this->snduPacketData_iter, this->snduPacket.data().end() );
161             if (sdnu_bytes_left != payload_pointer) {
162                 // delimiting error
163                 std::cerr << "delimiting error\n";
164                 payload_start += payload_pointer;
165             } else {
166                 readContSNDUPacket( payload_start, payload_end );
167                 BOOST_ASSERT( this->snduPacketData_iter == this->snduPacket.data().end() );
168             }
169             readNewSNDUPacket( payload_start, payload_end );
170         }       
171     }
172
173 }
174
175
176 ULEdec::iterator ULEdec::readContSNDUPacket(iterator i_start, iterator i_end)
177 {
178     if (priv_sndu_type_1) {
179         this->snduPacket->type() |= *i_start++;
180     }
181     i_start = readRawSNDUPacketData(i_start, i_end);
182     
183     return i_start;
184 }
185
186
187 ULEdec::iterator ULEdec::readNewSNDUPacket(iterator i_start, iterator i_end)
188
189     bool dbit = false;
190     senf::Packet::size_type sndu_length;
191     sndu_length = *i_start++ << 8 | *i_start++;
192     if (sndu_length & 0x8000) {
193         sndu_length &= 0x7FFF;
194         dbit = true;
195     }
196     this->snduPacket = senf::SNDUPacket::create(sndu_length+4);
197     this->snduPacket->d_bit() = dbit;
198     this->snduPacket->length() = sndu_length;
199     this->snduPacketData_iter = this->snduPacket.data().begin() + 2;
200     this->priv_sndu_type_1 = false;
201     
202     switch (std::distance(i_start, i_end)) {
203     case 1:
204         this->priv_sndu_type_1 = true;
205         this->snduPacket->type() = *i_start++;
206         this->snduPacketData_iter++;
207     case 0:
208         break;
209         
210     default: 
211         this->snduPacket->type() = *i_start++ | *i_start++;
212         this->snduPacketData_iter += 2;
213         i_start = readRawSNDUPacketData(i_start, i_end);
214     }
215     
216     return i_start;
217 }
218
219
220 ULEdec::iterator ULEdec::readRawSNDUPacketData(iterator i_start, iterator i_end)
221 {
222     unsigned char how_much = std::min(
223             std::distance( this->snduPacketData_iter, this->snduPacket.data().end() ),
224             std::distance( i_start, i_end ) );
225     copy_n(i_start, how_much, this->snduPacketData_iter);
226     i_start += how_much;
227     this->snduPacketData_iter += how_much;
228     return i_start;
229 }
230
231
232 int main(int argc, char const * argv[])
233 {
234     try {
235         ULEdec decoder;
236         senf::Scheduler::instance().process();
237     }
238     catch (std::exception const & ex) {
239         std::cerr << senf::prettyName(typeid(ex)) << ": " << ex.what() << "\n";
240     }
241     return 0;
242 }
243
244
245 ///////////////////////////////cc.e////////////////////////////////////////
246 #undef prefix_
247
248 \f
249 // Local Variables:
250 // mode: c++
251 // fill-column: 100
252 // c-file-style: "senf"
253 // indent-tabs-mode: nil
254 // ispell-local-dictionary: "american"
255 // compile-command: "scons -u test"
256 // comment-column: 40
257 // End: