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