some more small steps on the painful way to an ULE decoder ;)
[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             readContSNDUPacket( payload_start, payload_end );
159         }       
160     }
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     
190     switch (std::distance(i_start, i_end)) {
191     case 1:
192         this->priv_sndu_type_1 = true;;
193         this->snduPacket->type() = *i_start++;
194         this->snduPacketData_iter++;
195     case 0:
196         break;
197         
198     default: 
199         this->snduPacket->type() = *i_start++ | *i_start++;
200         this->snduPacketData_iter += 2;
201         i_start = readRawSNDUPacketData(i_start, i_end);
202     }
203     
204     return i_start;
205 }
206
207
208 ULEdec::iterator ULEdec::readRawSNDUPacketData(iterator i_start, iterator i_end)
209 {
210     unsigned char how_much = std::min(
211             std::distance( this->snduPacketData_iter, this->snduPacket.data().end() ),
212             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 int main(int argc, char const * argv[])
221 {
222     try {
223         ULEdec decoder;
224         senf::Scheduler::instance().process();
225     }
226     catch (std::exception const & ex) {
227         std::cerr << senf::prettyName(typeid(ex)) << ": " << ex.what() << "\n";
228     }
229     return 0;
230 }
231
232
233 ///////////////////////////////cc.e////////////////////////////////////////
234 #undef prefix_
235
236 \f
237 // Local Variables:
238 // mode: c++
239 // fill-column: 100
240 // c-file-style: "senf"
241 // indent-tabs-mode: nil
242 // ispell-local-dictionary: "american"
243 // compile-command: "scons -u test"
244 // comment-column: 40
245 // End: