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