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