4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Thorsten Horstmann <tho@berlios.de>
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.
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.
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.
23 // Definition of non-inline non-template functions
28 #include <linux/dvb/dmx.h>
29 #include <boost/format.hpp>
30 #include <senf/Packets.hh>
31 #include <senf/Utils/hexdump.hh>
32 #include <senf/Utils/membind.hh>
35 #define TRANSPORT_PACKET_SIZE 188
36 // max. payload_pointer = ts packet payload size ( = ts packet size - ts header - payload_pointer)
37 // - 2 bytes min. sndu header
38 #define MAX_PAYLOAD_POINTER ( TRANSPORT_PACKET_SIZE - 4 - 1 - 2 )
41 ///////////////////////////////cc.p////////////////////////////////////////
44 ULEdec::ULEdec(unsigned short adapter, unsigned short device)
45 : demuxHandle( adapter, device ), dvrHandle( adapter, device )
47 struct dmx_pes_filter_params pes_filter;
48 memset(&pes_filter, 0, sizeof (struct dmx_pes_filter_params));
50 pes_filter.input = DMX_IN_FRONTEND;
51 pes_filter.output = DMX_OUT_TS_TAP;
52 pes_filter.pes_type = DMX_PES_OTHER;
53 pes_filter.flags = DMX_IMMEDIATE_START;
54 demuxHandle.protocol().setPESFilter( &pes_filter );
56 senf::Scheduler::instance().add(
57 dvrHandle, senf::membind(&ULEdec::handleEvent, this));
59 this->receiver_state = Idle;
60 this->priv_sndu_type_1 = false;
63 void ULEdec::handleEvent(senf::Scheduler::EventId event)
65 senf::TransportPacket ts_packet (
66 senf::TransportPacket::create(188, senf::noinit));
67 dvrHandle.read( ts_packet.data() );
69 // Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control.
70 if ( (ts_packet->sync_byte() != senf::TransportPacketType::SYNC_BYTE) ||
71 (ts_packet->transport_error_indicator() == true) ||
72 (ts_packet->transport_scrmbl_ctrl() != 0))
74 std::cerr << "invalid ts packet\n";
75 // drop partly decoded SNDU, reset state, resync on PUSI.
79 handleTSPacket(ts_packet);
82 void ULEdec::handleTSPacket(senf::TransportPacket ts_packet)
84 senf::PacketData & payloadData (ts_packet.next().data());
85 iterator payload_iter = payloadData.begin();
86 iterator payload_end = payloadData.end();
88 std::cout << "New TS Packet:\n"
89 << "----------------------------------------------------------------------------\n";
90 senf::hexdump(payload_iter, payload_end, std::cout);
91 std::cout << "----------------------------------------------------------------------------\n";
93 // Synchronize continuity counter
94 this->priv_tscc = ts_packet->continuity_counter();
96 switch (ts_packet->pusi()) {
98 switch (this->receiver_state) {
102 payload_iter = readContSNDUPacket( payload_iter, payload_end );
103 if (isSDNUPacketComplete()) {
104 this->receiver_state = Idle;
107 } catch (ULEdecException const & ex) {
108 std::cerr << ex.what() << "\n";
111 switch (std::distance( payload_iter, payload_end ))
116 if ( (*payload_iter++ << 8 | *payload_iter++) != ULE_END_INDICATOR )
117 std::cerr << "delimiting error\n";
119 assert( std::distance( payload_iter, payload_end ) == 0 );
125 // a PUSI value of 1 indicates the presence of a Payload Pointer.
126 unsigned char payload_pointer = *payload_iter++;
127 if (payload_pointer > MAX_PAYLOAD_POINTER) {
128 std::cerr << str( boost::format(
129 "invalid payload_pointer (%d)\n") % unsigned(payload_pointer) ) ;
130 this->receiver_state = Idle;
133 switch (this->receiver_state) {
135 std::advance(payload_iter, payload_pointer);
138 // Reassembly Payload Pointer Checking
139 if (snduPacketBytesLeft() != payload_pointer) {
141 std::cerr << str( boost::format(
142 "delimiting error: bytes left in SNDU packet != payload_pointer ("
143 "(%d != %d)\n") % snduPacketBytesLeft() % payload_pointer );
144 std::advance(payload_iter, payload_pointer);
146 payload_iter = readContSNDUPacket( payload_iter, payload_end );
147 assert( isSDNUPacketComplete() );
150 } catch (ULEdecException const & ex) {
151 std::cerr << ex.what() << "\n";
152 this->receiver_state = Idle;
157 this->receiver_state = Idle;
160 payload_iter = readNewSNDUPacket( payload_iter, payload_end );
161 if (! isSDNUPacketComplete()) {
162 assert( std::distance( payload_iter, payload_end ) == 0 );
163 this->receiver_state = Reassembly;
167 } while (std::distance(payload_iter, payload_end) < 2 );
169 catch (ULEdecException const & ex) {
170 std::cerr << ex.what() << "\n";
179 ULEdec::iterator ULEdec::readContSNDUPacket(iterator i, iterator const i_end)
181 if (priv_sndu_type_1) {
182 this->snduPacket->type() |= *i++;
184 return readRawSNDUPacketData(i, i_end);
188 ULEdec::iterator ULEdec::readNewSNDUPacket(iterator i, iterator const i_end)
191 senf::Packet::size_type sndu_length = *i++ << 8 | *i++;
192 if (sndu_length & 0x8000) {
193 sndu_length &= 0x7FFF;
196 if (sndu_length < 5 || sndu_length == 0xffff) {
197 throw ULEdecException( str( boost::format(
198 "SNDU length error. length=%d") % sndu_length) );
200 this->snduPacket = senf::SNDUPacket::create(sndu_length+4);
203 this->snduPacket->withoutDestination();
204 // else not needed since default on newly created packet is withDestination()
206 this->snduPacket->length() = sndu_length;
207 this->snduPacketData_iter = boost::next(this->snduPacket.data().begin(), 2);
208 this->priv_sndu_type_1 = false;
210 switch (std::distance(i, i_end)) {
212 this->priv_sndu_type_1 = true;
213 this->snduPacket->type() = *i++ << 8;
214 this->snduPacketData_iter++;
219 this->snduPacket->type() = *i++ << 8 | *i++;
220 std::advance(this->snduPacketData_iter, 2);
221 i = readRawSNDUPacketData(i, i_end);
228 ULEdec::iterator ULEdec::readRawSNDUPacketData(iterator i, iterator i_end)
230 unsigned char how_much = std::min(
231 snduPacketBytesLeft(), std::distance(i, i_end) );
232 copy_n(i, how_much, this->snduPacketData_iter);
233 std::advance(i, how_much);
234 std::advance(this->snduPacketData_iter, how_much);
239 void ULEdec::handleSNDUPacket()
241 this->snduPacket.dump(std::cout);
242 std::cout << "----------------------------------------------------------------------------\n\n";
243 if (this->snduPacket->crc() != this->snduPacket->calcCrc()) {
244 throw ULEdecException( str( boost::format(
245 "CRC Error. received crc:%d calculated crc:%d")
246 % this->snduPacket->crc() % this->snduPacket->calcCrc() ) );
248 // senf::Packet nextPacket = this->snduPacket.next();
250 // nextPacket.data().begin(),
251 // nextPacket.data().end(),
257 inline bool ULEdec::isSDNUPacketComplete()
259 return this->snduPacketData_iter == this->snduPacket.data().end();
262 inline ULEdec::iterator::difference_type ULEdec::snduPacketBytesLeft()
264 return std::distance( this->snduPacketData_iter, this->snduPacket.data().end() );
268 int main(int argc, char const * argv[])
272 senf::Scheduler::instance().process();
274 catch (std::exception const & ex) {
275 std::cerr << senf::prettyName(typeid(ex)) << ": " << ex.what() << "\n";
281 ///////////////////////////////cc.e////////////////////////////////////////
288 // c-file-style: "senf"
289 // indent-tabs-mode: nil
290 // ispell-local-dictionary: "american"
291 // compile-command: "scons -U"
292 // comment-column: 40