bugfix in hexdump()
[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 "Utils/hexdump.hh"
39 #include "Socket/Protocols/DVB/DVBDemuxHandles.hh"
40 #include "Packets/ParseInt.hh"
41 #include "Packets/Packet.hh"
42 #include "Packets/PacketData.hh"
43 #include "Packets/ParseInt.hh"
44
45 #include "ULEdec.hh"
46
47 #define PID 271
48 #define TS_SYNC 0x47
49
50 #define prefix_
51 ///////////////////////////////cc.p////////////////////////////////////////
52
53
54 ULEdec::ULEdec()
55 {
56     struct dmx_pes_filter_params pes_filter;
57     memset(&pes_filter, 0, sizeof (struct dmx_pes_filter_params));
58     pes_filter.pid = PID;
59     pes_filter.input  = DMX_IN_FRONTEND;
60     pes_filter.output = DMX_OUT_TS_TAP;
61     pes_filter.pes_type = DMX_PES_OTHER;
62     pes_filter.flags = DMX_IMMEDIATE_START;
63     demuxHandle.protocol().setPESFilter( &pes_filter );
64     
65     senf::Scheduler::instance().add(
66         dvrHandle, senf::membind(&ULEdec::handleEvent, this));
67     
68     this->receiver_state = Idle;
69     this->priv_sndu_type_1 = false;
70 }
71
72 void ULEdec::handleEvent(senf::FileHandle, senf::Scheduler::EventId event)
73 {
74     senf::TransportPacket ts_packet (
75             senf::TransportPacket::create(188, senf::TransportPacket::noinit));
76     dvrHandle.read( ts_packet.data() );
77    
78     // Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control.
79     if ( (ts_packet->sync_byte() != TS_SYNC) || 
80          (ts_packet->transport_error_indicator() == true) || 
81          (ts_packet->transport_scrmbl_ctrl() != 0)) 
82     {
83         std::cerr << "invalid ts packet\n";
84         // drop partly decoded SNDU, reset state, resync on PUSI.
85         return;
86     }
87     
88     handleTSPacket(ts_packet);
89 }
90     
91 void ULEdec::handleTSPacket(senf::TransportPacket ts_packet)
92 {
93     senf::PacketData & payloadData (ts_packet.next().data());
94     iterator payload_start = payloadData.begin();
95     iterator payload_end = payloadData.end();
96     
97     senf::hexdump(payload_start, payload_end, std::cout);
98     
99     // Synchronize continuity counter
100     this->priv_tscc = ts_packet->continuity_counter();
101     
102     switch (ts_packet->pusi()) {
103     case 0: {
104         switch (this->receiver_state) {
105         case Idle:
106             return;
107         case Reassembly:
108             payload_start = readContSNDUPacket( payload_start, payload_end );
109             if (isSDNUPacketComplete()) {
110                 handleSNDUPacket();
111                 this->receiver_state = Idle;
112                 switch (std::distance( payload_start, payload_end ))
113                 case 0:
114                 case 1:
115                     return;
116                 default:
117                     if ( (*payload_start++ | *payload_start++) != ULE_END_INDICATOR )
118                         std::cerr << "delimiting error 1\n";
119             } else {
120                 BOOST_ASSERT( std::distance( payload_start, payload_end ) == 0 );
121             }
122         }
123         break;
124     }
125     case 1: {
126         // a PUSI value of 1 indicates the presence of a Payload Pointer.
127         unsigned char payload_pointer = *payload_start++;
128         if (payload_pointer > 181) {
129             std::cerr << "invalid payload_pointer\n";
130             this->receiver_state = Idle;
131             return;
132         }
133         switch (this->receiver_state) {
134         case Idle:
135             payload_start += payload_pointer;
136             break;
137         case Reassembly:
138             // Reassembly Payload Pointer Checking
139             if (snduPacketBytesLeft() != payload_pointer) {
140                 // delimiting error
141                 std::cerr << "delimiting error 2\n";
142                 payload_start += payload_pointer;
143             } else {
144                 payload_start = readContSNDUPacket( payload_start, payload_end );
145                 BOOST_ASSERT( isSDNUPacketComplete() );
146                 handleSNDUPacket();
147             }
148         }
149         do {
150             payload_start = readNewSNDUPacket( payload_start, payload_end );
151             if (! isSDNUPacketComplete()) {
152                 BOOST_ASSERT( std::distance( payload_start, payload_end ) == 0 );
153                 this->receiver_state = Reassembly;
154                 break;
155             }
156             handleSNDUPacket();
157             this->receiver_state = Idle;
158         } while (std::distance(payload_start, payload_end) < 2 );
159     }
160     } // end pusi-switch
161
162 }
163
164
165 ULEdec::iterator ULEdec::readContSNDUPacket(iterator i_start, iterator i_end)
166 {
167     if (priv_sndu_type_1) {
168         this->snduPacket->type() |= *i_start++;
169     }
170     i_start = readRawSNDUPacketData(i_start, i_end);
171     
172     return i_start;
173 }
174
175
176 ULEdec::iterator ULEdec::readNewSNDUPacket(iterator i_start, iterator i_end)
177
178     bool dbit = false;
179     senf::Packet::size_type sndu_length;
180     sndu_length = *i_start++ << 8 | *i_start++;
181     if (sndu_length & 0x8000) {
182         sndu_length &= 0x7FFF;
183         dbit = true;
184     }
185     this->snduPacket = senf::SNDUPacket::create(sndu_length+4);
186     this->snduPacket->d_bit() = dbit;
187     this->snduPacket->length() = sndu_length;
188     this->snduPacketData_iter = this->snduPacket.data().begin() + 2;
189     this->priv_sndu_type_1 = false;
190     
191     switch (std::distance(i_start, i_end)) {
192     case 1:
193         this->priv_sndu_type_1 = true;
194         this->snduPacket->type() = *i_start++;
195         this->snduPacketData_iter++;
196     case 0:
197         break;
198         
199     default: 
200         this->snduPacket->type() = *i_start++ | *i_start++;
201         this->snduPacketData_iter += 2;
202         i_start = readRawSNDUPacketData(i_start, i_end);
203     }
204     
205     return i_start;
206 }
207
208
209 ULEdec::iterator ULEdec::readRawSNDUPacketData(iterator i_start, iterator i_end)
210 {
211     unsigned char how_much = std::min(
212             snduPacketBytesLeft(), std::distance( i_start, i_end ) );
213     copy_n(i_start, how_much, this->snduPacketData_iter);
214     i_start += how_much;
215     this->snduPacketData_iter += how_much;
216     return i_start;
217 }
218
219
220 void ULEdec::handleSNDUPacket()
221 {
222     this->snduPacket.dump(std::cout);
223 }
224
225
226 inline bool ULEdec::isSDNUPacketComplete()
227 {
228     return this->snduPacketData_iter == this->snduPacket.data().end();
229 }
230
231 inline ULEdec::iterator::difference_type ULEdec::snduPacketBytesLeft()
232 {
233     return std::distance( this->snduPacketData_iter, this->snduPacket.data().end() );
234 }
235
236
237 int main(int argc, char const * argv[])
238 {
239     try {
240         ULEdec decoder;
241         senf::Scheduler::instance().process();
242     }
243     catch (std::exception const & ex) {
244         std::cerr << senf::prettyName(typeid(ex)) << ": " << ex.what() << "\n";
245     }
246     return 0;
247 }
248
249
250 ///////////////////////////////cc.e////////////////////////////////////////
251 #undef prefix_
252
253  
254 // Local Variables:
255 // mode: c++
256 // fill-column: 100
257 // c-file-style: "senf"
258 // indent-tabs-mode: nil
259 // ispell-local-dictionary: "american"
260 // compile-command: "scons -u test"
261 // comment-column: 40
262 // End: