Fix documentation build under maverick (doxygen 1.7.1)
[senf.git] / Examples / DVBAdapter / ULEdec.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Thorsten Horstmann <tho@berlios.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 "ULEdec.hh"
26
27 #include <cassert>
28 #include <linux/dvb/dmx.h>
29 #include <boost/format.hpp>
30 #include <senf/Packets.hh>
31 #include <senf/Utils/hexdump.hh>
32 #include <senf/Utils/membind.hh>
33
34 #define PID 271
35 #define TRANSPORT_PACKET_SIZE 188
36 // max. payload_pointer = ts packet payload size ( = ts packet size - ts header - payload_pointer)
37 //                          - 2 bytes min. sndu header
38 #define MAX_PAYLOAD_POINTER ( TRANSPORT_PACKET_SIZE - 4 - 1 - 2 )
39
40 #define prefix_
41 //-/////////////////////////////////////////////////////////////////////////////////////////////////
42
43
44 ULEdec::ULEdec(unsigned short adapter, unsigned short device)
45     : demuxHandle( adapter, device ),  dvrHandle( adapter, device )
46 {
47     struct dmx_pes_filter_params pes_filter;
48     memset(&pes_filter, 0, sizeof (struct dmx_pes_filter_params));
49     pes_filter.pid = PID;
50     pes_filter.input  = DMX_IN_FRONTEND;
51     pes_filter.output = DMX_OUT_TS_TAP;
52     pes_filter.pes_type = DMX_PES_OTHER;
53     pes_filter.flags = DMX_IMMEDIATE_START;
54     demuxHandle.protocol().setPESFilter( &pes_filter );
55
56     senf::Scheduler::instance().add(
57         dvrHandle, senf::membind(&ULEdec::handleEvent, this));
58
59     this->receiver_state = Idle;
60     this->priv_sndu_type_1 = false;
61 }
62
63 void ULEdec::handleEvent(senf::Scheduler::EventId event)
64 {
65     senf::TransportPacket ts_packet (
66             senf::TransportPacket::create(188, senf::noinit));
67     dvrHandle.read( ts_packet.data() );
68
69     // Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control.
70     if ( (ts_packet->sync_byte() != senf::TransportPacketType::SYNC_BYTE) ||
71          (ts_packet->transport_error_indicator() == true) ||
72          (ts_packet->transport_scrmbl_ctrl() != 0))
73     {
74         std::cerr << "invalid ts packet\n";
75         // drop partly decoded SNDU, reset state, resync on PUSI.
76         return;
77     }
78
79     handleTSPacket(ts_packet);
80 }
81
82 void ULEdec::handleTSPacket(senf::TransportPacket ts_packet)
83 {
84     senf::PacketData & payloadData (ts_packet.next().data());
85     iterator payload_iter = payloadData.begin();
86     iterator payload_end = payloadData.end();
87
88     std::cout << "New TS Packet:\n"
89               << "----------------------------------------------------------------------------\n";
90     senf::hexdump(payload_iter, payload_end, std::cout);
91     std::cout << "----------------------------------------------------------------------------\n";
92
93     // Synchronize continuity counter
94     this->priv_tscc = ts_packet->continuity_counter();
95
96     switch (ts_packet->pusi()) {
97     case 0: {
98         switch (this->receiver_state) {
99         case Idle:
100             return;
101         case Reassembly:
102             payload_iter = readContSNDUPacket( payload_iter, payload_end );
103             if (isSDNUPacketComplete()) {
104                 this->receiver_state = Idle;
105                 try {
106                     handleSNDUPacket();
107                 } catch (ULEdecException const & ex) {
108                     std::cerr << ex.what() << "\n";
109                     return;
110                 }
111                 switch (std::distance( payload_iter, payload_end ))
112                 case 0:
113                 case 1:
114                     return;
115                 default:
116                     if ( (*payload_iter++ << 8 | *payload_iter++) != ULE_END_INDICATOR )
117                         std::cerr << "delimiting error\n";
118             } else {
119                 assert( std::distance( payload_iter, payload_end ) == 0 );
120             }
121         }
122         break;
123     }
124     case 1: {
125         // a PUSI value of 1 indicates the presence of a Payload Pointer.
126         unsigned char payload_pointer = *payload_iter++;
127         if (payload_pointer > MAX_PAYLOAD_POINTER) {
128             std::cerr << str( boost::format(
129                     "invalid payload_pointer (%d)\n") % unsigned(payload_pointer) ) ;
130             this->receiver_state = Idle;
131             return;
132         }
133         switch (this->receiver_state) {
134         case Idle:
135             std::advance(payload_iter, payload_pointer);
136             break;
137         case Reassembly:
138             // Reassembly Payload Pointer Checking
139             if (snduPacketBytesLeft() != payload_pointer) {
140                 // delimiting error
141                 std::cerr << str( boost::format(
142                         "delimiting error: bytes left in SNDU packet != payload_pointer ("
143                         "(%d != %d)\n") % snduPacketBytesLeft() % payload_pointer );
144                 std::advance(payload_iter, payload_pointer);
145             } else {
146                 payload_iter = readContSNDUPacket( payload_iter, payload_end );
147                 assert( isSDNUPacketComplete() );
148                 try {
149                     handleSNDUPacket();
150                 } catch (ULEdecException const & ex) {
151                     std::cerr << ex.what() << "\n";
152                     this->receiver_state = Idle;
153                     return;
154                 }
155             }
156         }
157         this->receiver_state = Idle;
158         try {
159             do {
160                 payload_iter = readNewSNDUPacket( payload_iter, payload_end );
161                 if (! isSDNUPacketComplete()) {
162                     assert( std::distance( payload_iter, payload_end ) == 0 );
163                     this->receiver_state = Reassembly;
164                     break;
165                 }
166                 handleSNDUPacket();
167             } while (std::distance(payload_iter, payload_end) < 2 );
168         }
169         catch (ULEdecException const & ex) {
170             std::cerr << ex.what() << "\n";
171             return;
172         }
173     }
174
175     } // end pusi-switch
176 }
177
178
179 ULEdec::iterator ULEdec::readContSNDUPacket(iterator i, iterator const i_end)
180 {
181     if (priv_sndu_type_1) {
182         this->snduPacket->type() |= *i++;
183     }
184     return readRawSNDUPacketData(i, i_end);
185 }
186
187
188 ULEdec::iterator ULEdec::readNewSNDUPacket(iterator i, iterator const i_end)
189 {
190     bool dbit = false;
191     senf::Packet::size_type sndu_length = *i++ << 8 | *i++;
192     if (sndu_length & 0x8000) {
193         sndu_length &= 0x7FFF;
194         dbit = true;
195     }
196     if (sndu_length < 5 || sndu_length == 0xffff) {
197         throw ULEdecException( str( boost::format(
198                 "SNDU length error. length=%d") % sndu_length) );
199      }
200     this->snduPacket = senf::SNDUPacket::create(sndu_length+4);
201
202     if (dbit)
203         this->snduPacket->withoutDestination();
204     // else not needed since default on newly created packet is withDestination()
205
206     this->snduPacket->length() = sndu_length;
207     this->snduPacketData_iter = boost::next(this->snduPacket.data().begin(), 2);
208     this->priv_sndu_type_1 = false;
209
210     switch (std::distance(i, i_end)) {
211     case 1:
212         this->priv_sndu_type_1 = true;
213         this->snduPacket->type() = *i++ << 8;
214         this->snduPacketData_iter++;
215     case 0:
216         break;
217
218     default:
219         this->snduPacket->type() = *i++ << 8 | *i++;
220         std::advance(this->snduPacketData_iter, 2);
221         i = readRawSNDUPacketData(i, i_end);
222     }
223
224     return i;
225 }
226
227
228 ULEdec::iterator ULEdec::readRawSNDUPacketData(iterator i, iterator i_end)
229 {
230     unsigned char how_much = std::min(
231             snduPacketBytesLeft(), std::distance(i, i_end) );
232     copy_n(i, how_much, this->snduPacketData_iter);
233     std::advance(i, how_much);
234     std::advance(this->snduPacketData_iter, how_much);
235     return i;
236 }
237
238
239 void ULEdec::handleSNDUPacket()
240 {
241     this->snduPacket.dump(std::cout);
242     std::cout << "----------------------------------------------------------------------------\n\n";
243     if (this->snduPacket->crc() != this->snduPacket->calcCrc()) {
244         throw ULEdecException( str( boost::format(
245                 "CRC Error. received crc:%d calculated crc:%d")
246                     % this->snduPacket->crc() % this->snduPacket->calcCrc() ) );
247     }
248 //    senf::Packet nextPacket = this->snduPacket.next();
249 //    senf::hexdump(
250 //            nextPacket.data().begin(),
251 //            nextPacket.data().end(),
252 //            std::cout);
253
254 }
255
256
257 inline bool ULEdec::isSDNUPacketComplete()
258 {
259     return this->snduPacketData_iter == this->snduPacket.data().end();
260 }
261
262 inline ULEdec::iterator::difference_type ULEdec::snduPacketBytesLeft()
263 {
264     return std::distance( this->snduPacketData_iter, this->snduPacket.data().end() );
265 }
266
267
268 int main(int argc, char const * argv[])
269 {
270     try {
271         ULEdec decoder;
272         senf::Scheduler::instance().process();
273     }
274     catch (std::exception const & ex) {
275         std::cerr << senf::prettyName(typeid(ex)) << ": " << ex.what() << "\n";
276     }
277     return 0;
278 }
279
280
281 //-/////////////////////////////////////////////////////////////////////////////////////////////////
282 #undef prefix_
283
284 \f
285 // Local Variables:
286 // mode: c++
287 // fill-column: 100
288 // c-file-style: "senf"
289 // indent-tabs-mode: nil
290 // ispell-local-dictionary: "american"
291 // compile-command: "scons -U"
292 // comment-column: 40
293 // End: