4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
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
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.
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.
19 // The Original Code is Fraunhofer FOKUS code.
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.
26 // Thorsten Horstmann <tho@berlios.de>
29 // Definition of non-inline non-template functions
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>
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 )
47 //-/////////////////////////////////////////////////////////////////////////////////////////////////
50 ULEdec::ULEdec(unsigned short adapter, unsigned short device)
51 : demuxHandle( adapter, device ), dvrHandle( adapter, device )
53 struct dmx_pes_filter_params pes_filter;
54 memset(&pes_filter, 0, sizeof (struct dmx_pes_filter_params));
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 );
62 senf::Scheduler::instance().add(
63 dvrHandle, senf::membind(&ULEdec::handleEvent, this));
65 this->receiver_state = Idle;
66 this->priv_sndu_type_1 = false;
69 void ULEdec::handleEvent(senf::Scheduler::EventId event)
71 senf::TransportPacket ts_packet (
72 senf::TransportPacket::create(188, senf::noinit));
73 dvrHandle.read( ts_packet.data() );
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))
80 std::cerr << "invalid ts packet\n";
81 // drop partly decoded SNDU, reset state, resync on PUSI.
85 handleTSPacket(ts_packet);
88 void ULEdec::handleTSPacket(senf::TransportPacket ts_packet)
90 senf::PacketData & payloadData (ts_packet.next().data());
91 iterator payload_iter = payloadData.begin();
92 iterator payload_end = payloadData.end();
94 std::cout << "New TS Packet:\n"
95 << "----------------------------------------------------------------------------\n";
96 senf::hexdump(payload_iter, payload_end, std::cout);
97 std::cout << "----------------------------------------------------------------------------\n";
99 // Synchronize continuity counter
100 this->priv_tscc = ts_packet->continuity_counter();
102 switch (ts_packet->pusi()) {
104 switch (this->receiver_state) {
108 payload_iter = readContSNDUPacket( payload_iter, payload_end );
109 if (isSDNUPacketComplete()) {
110 this->receiver_state = Idle;
113 } catch (ULEdecException const & ex) {
114 std::cerr << ex.what() << "\n";
117 switch (std::distance( payload_iter, payload_end ))
122 if ( (*payload_iter++ << 8 | *payload_iter++) != ULE_END_INDICATOR )
123 std::cerr << "delimiting error\n";
125 assert( std::distance( payload_iter, payload_end ) == 0 );
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;
139 switch (this->receiver_state) {
141 std::advance(payload_iter, payload_pointer);
144 // Reassembly Payload Pointer Checking
145 if (snduPacketBytesLeft() != payload_pointer) {
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);
152 payload_iter = readContSNDUPacket( payload_iter, payload_end );
153 assert( isSDNUPacketComplete() );
156 } catch (ULEdecException const & ex) {
157 std::cerr << ex.what() << "\n";
158 this->receiver_state = Idle;
163 this->receiver_state = Idle;
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;
173 } while (std::distance(payload_iter, payload_end) < 2 );
175 catch (ULEdecException const & ex) {
176 std::cerr << ex.what() << "\n";
185 ULEdec::iterator ULEdec::readContSNDUPacket(iterator i, iterator const i_end)
187 if (priv_sndu_type_1) {
188 this->snduPacket->type() |= *i++;
190 return readRawSNDUPacketData(i, i_end);
194 ULEdec::iterator ULEdec::readNewSNDUPacket(iterator i, iterator const i_end)
197 senf::Packet::size_type sndu_length = *i++ << 8 | *i++;
198 if (sndu_length & 0x8000) {
199 sndu_length &= 0x7FFF;
202 if (sndu_length < 5 || sndu_length == 0xffff) {
203 throw ULEdecException( str( boost::format(
204 "SNDU length error. length=%d") % sndu_length) );
206 this->snduPacket = senf::SNDUPacket::create(sndu_length+4);
209 this->snduPacket->withoutDestination();
210 // else not needed since default on newly created packet is withDestination()
212 this->snduPacket->length() = sndu_length;
213 this->snduPacketData_iter = boost::next(this->snduPacket.data().begin(), 2);
214 this->priv_sndu_type_1 = false;
216 switch (std::distance(i, i_end)) {
218 this->priv_sndu_type_1 = true;
219 this->snduPacket->type() = *i++ << 8;
220 this->snduPacketData_iter++;
225 this->snduPacket->type() = *i++ << 8 | *i++;
226 std::advance(this->snduPacketData_iter, 2);
227 i = readRawSNDUPacketData(i, i_end);
234 ULEdec::iterator ULEdec::readRawSNDUPacketData(iterator i, iterator i_end)
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);
245 void ULEdec::handleSNDUPacket()
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() ) );
254 // senf::Packet nextPacket = this->snduPacket.next();
256 // nextPacket.data().begin(),
257 // nextPacket.data().end(),
263 inline bool ULEdec::isSDNUPacketComplete()
265 return this->snduPacketData_iter == this->snduPacket.data().end();
268 inline ULEdec::iterator::difference_type ULEdec::snduPacketBytesLeft()
270 return std::distance( this->snduPacketData_iter, this->snduPacket.data().end() );
274 int main(int argc, char const * argv[])
278 senf::Scheduler::instance().process();
280 catch (std::exception const & ex) {
281 std::cerr << senf::prettyName(typeid(ex)) << ": " << ex.what() << "\n";
287 //-/////////////////////////////////////////////////////////////////////////////////////////////////
294 // c-file-style: "senf"
295 // indent-tabs-mode: nil
296 // ispell-local-dictionary: "american"
297 // compile-command: "scons -U"
298 // comment-column: 40