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